citrus_mapper.c revision 257039
1156952Sume/* $FreeBSD: stable/10/lib/libc/iconv/citrus_mapper.c 257039 2013-10-24 05:01:49Z delphij $ */ 2156952Sume/* $NetBSD: citrus_mapper.c,v 1.7 2008/07/25 14:05:25 christos Exp $ */ 3156952Sume 4156952Sume/*- 5156952Sume * Copyright (c)2003 Citrus Project, 6156952Sume * All rights reserved. 7156952Sume * 8156952Sume * Redistribution and use in source and binary forms, with or without 9156952Sume * modification, are permitted provided that the following conditions 10156952Sume * are met: 11156952Sume * 1. Redistributions of source code must retain the above copyright 12156952Sume * notice, this list of conditions and the following disclaimer. 13156952Sume * 2. Redistributions in binary form must reproduce the above copyright 14156952Sume * notice, this list of conditions and the following disclaimer in the 15156952Sume * documentation and/or other materials provided with the distribution. 16156952Sume * 17156952Sume * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 18156952Sume * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 19156952Sume * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 20156952Sume * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 21156956Sume * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 22156956Sume * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 23156952Sume * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 24156952Sume * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 25156952Sume * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 26156952Sume * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 27156952Sume * SUCH DAMAGE. 28156952Sume */ 29156952Sume 30156952Sume#include <sys/cdefs.h> 31156952Sume#include <sys/types.h> 32156952Sume#include <sys/stat.h> 33156952Sume#include <sys/queue.h> 34156952Sume 35156952Sume#include <assert.h> 36156952Sume#include <errno.h> 37156952Sume#include <limits.h> 38156956Sume#include <stdio.h> 39156952Sume#include <stdlib.h> 40156956Sume#include <string.h> 41156952Sume 42156952Sume#include "citrus_namespace.h" 43156952Sume#include "citrus_types.h" 44156952Sume#include "citrus_region.h" 45156952Sume#include "citrus_lock.h" 46156952Sume#include "citrus_memstream.h" 47156952Sume#include "citrus_bcs.h" 48156952Sume#include "citrus_mmap.h" 49156952Sume#include "citrus_module.h" 50156952Sume#include "citrus_hash.h" 51156952Sume#include "citrus_mapper.h" 52156952Sume 53156952Sume#define _CITRUS_MAPPER_DIR "mapper.dir" 54156952Sume 55156952Sume#define CM_HASH_SIZE 101 56156952Sume#define REFCOUNT_PERSISTENT -1 57156952Sume 58156952Sumestatic pthread_rwlock_t cm_lock = PTHREAD_RWLOCK_INITIALIZER; 59156952Sume 60156952Sumestruct _citrus_mapper_area { 61156952Sume _CITRUS_HASH_HEAD(, _citrus_mapper, CM_HASH_SIZE) ma_cache; 62156952Sume char *ma_dir; 63156952Sume}; 64156952Sume 65156952Sume/* 66156952Sume * _citrus_mapper_create_area: 67156952Sume * create mapper area 68156952Sume */ 69156952Sume 70156952Sumeint 71156952Sume_citrus_mapper_create_area( 72156952Sume struct _citrus_mapper_area *__restrict *__restrict rma, 73156952Sume const char *__restrict area) 74156952Sume{ 75156952Sume struct _citrus_mapper_area *ma; 76156952Sume struct stat st; 77156952Sume char path[PATH_MAX]; 78156952Sume int ret; 79156952Sume 80156952Sume WLOCK(&cm_lock); 81156952Sume 82156952Sume if (*rma != NULL) { 83156952Sume ret = 0; 84156952Sume goto quit; 85156952Sume } 86156952Sume 87156952Sume snprintf(path, (size_t)PATH_MAX, "%s/%s", area, _CITRUS_MAPPER_DIR); 88156952Sume 89156952Sume ret = stat(path, &st); 90156952Sume if (ret) 91156952Sume goto quit; 92156952Sume 93156952Sume ma = malloc(sizeof(*ma)); 94156952Sume if (ma == NULL) { 95156952Sume ret = errno; 96156952Sume goto quit; 97156952Sume } 98156952Sume ma->ma_dir = strdup(area); 99156952Sume if (ma->ma_dir == NULL) { 100156952Sume ret = errno; 101156952Sume free(ma); 102156952Sume goto quit; 103156952Sume } 104156952Sume _CITRUS_HASH_INIT(&ma->ma_cache, CM_HASH_SIZE); 105156952Sume 106156952Sume *rma = ma; 107156952Sume ret = 0; 108156956Sumequit: 109156952Sume UNLOCK(&cm_lock); 110156952Sume 111156952Sume return (ret); 112156952Sume} 113156952Sume 114156952Sume 115156952Sume/* 116156952Sume * lookup_mapper_entry: 117156952Sume * lookup mapper.dir entry in the specified directory. 118156952Sume * 119156952Sume * line format of iconv.dir file: 120156952Sume * mapper module arg 121156952Sume * mapper : mapper name. 122156952Sume * module : mapper module name. 123156952Sume * arg : argument for the module (generally, description file name) 124156952Sume */ 125156952Sume 126156952Sumestatic int 127156952Sumelookup_mapper_entry(const char *dir, const char *mapname, void *linebuf, 128156952Sume size_t linebufsize, const char **module, const char **variable) 129156952Sume{ 130156952Sume struct _region r; 131156952Sume struct _memstream ms; 132156952Sume const char *cp, *cq; 133156952Sume char *p; 134156952Sume char path[PATH_MAX]; 135156952Sume size_t len; 136156952Sume int ret; 137156952Sume 138156952Sume /* create mapper.dir path */ 139156952Sume snprintf(path, (size_t)PATH_MAX, "%s/%s", dir, _CITRUS_MAPPER_DIR); 140156952Sume 141156952Sume /* open read stream */ 142156952Sume ret = _map_file(&r, path); 143156952Sume if (ret) 144156952Sume return (ret); 145156952Sume 146156952Sume _memstream_bind(&ms, &r); 147156952Sume 148156952Sume /* search the line matching to the map name */ 149156952Sume cp = _memstream_matchline(&ms, mapname, &len, 0); 150156952Sume if (!cp) { 151156952Sume ret = ENOENT; 152156952Sume goto quit; 153156952Sume } 154156952Sume if (!len || len > linebufsize - 1) { 155156952Sume ret = EINVAL; 156156952Sume goto quit; 157156952Sume } 158156952Sume 159156956Sume p = linebuf; 160156952Sume /* get module name */ 161156952Sume *module = p; 162156952Sume cq = _bcs_skip_nonws_len(cp, &len); 163156952Sume strlcpy(p, cp, (size_t)(cq - cp + 1)); 164156952Sume p += cq - cp + 1; 165156952Sume 166156952Sume /* get variable */ 167156952Sume *variable = p; 168156952Sume cp = _bcs_skip_ws_len(cq, &len); 169156956Sume strlcpy(p, cp, len + 1); 170156952Sume 171156952Sume ret = 0; 172156952Sume 173156952Sumequit: 174156952Sume _unmap_file(&r); 175156952Sume return (ret); 176156952Sume} 177156952Sume 178156952Sume/* 179156952Sume * mapper_close: 180156952Sume * simply close a mapper. (without handling hash) 181156952Sume */ 182156952Sumestatic void 183156952Sumemapper_close(struct _citrus_mapper *cm) 184156956Sume{ 185156952Sume if (cm->cm_module) { 186156952Sume if (cm->cm_ops) { 187156952Sume if (cm->cm_closure) 188156952Sume (*cm->cm_ops->mo_uninit)(cm); 189156952Sume free(cm->cm_ops); 190156952Sume } 191156952Sume _citrus_unload_module(cm->cm_module); 192156952Sume } 193156952Sume free(cm->cm_traits); 194156956Sume free(cm); 195156952Sume} 196156952Sume 197156952Sume/* 198156952Sume * mapper_open: 199156952Sume * simply open a mapper. (without handling hash) 200156952Sume */ 201156952Sumestatic int 202156952Sumemapper_open(struct _citrus_mapper_area *__restrict ma, 203156952Sume struct _citrus_mapper * __restrict * __restrict rcm, 204156952Sume const char * __restrict module, 205156952Sume const char * __restrict variable) 206156952Sume{ 207156952Sume struct _citrus_mapper *cm; 208156952Sume _citrus_mapper_getops_t getops; 209156952Sume int ret; 210156952Sume 211156956Sume /* initialize mapper handle */ 212156952Sume cm = malloc(sizeof(*cm)); 213156952Sume if (!cm) 214156952Sume return (errno); 215156952Sume 216156952Sume cm->cm_module = NULL; 217156952Sume cm->cm_ops = NULL; 218156952Sume cm->cm_closure = NULL; 219156952Sume cm->cm_traits = NULL; 220156952Sume cm->cm_refcount = 0; 221156952Sume cm->cm_key = NULL; 222156952Sume 223156956Sume /* load module */ 224156952Sume ret = _citrus_load_module(&cm->cm_module, module); 225156952Sume if (ret) 226156952Sume goto err; 227156952Sume 228156952Sume /* get operators */ 229156952Sume getops = (_citrus_mapper_getops_t) 230156956Sume _citrus_find_getops(cm->cm_module, module, "mapper"); 231156952Sume if (!getops) { 232156952Sume ret = EOPNOTSUPP; 233156952Sume goto err; 234156952Sume } 235156952Sume cm->cm_ops = malloc(sizeof(*cm->cm_ops)); 236156952Sume if (!cm->cm_ops) { 237156952Sume ret = errno; 238156952Sume goto err; 239156952Sume } 240156956Sume ret = (*getops)(cm->cm_ops); 241156952Sume if (ret) 242156952Sume goto err; 243156952Sume 244156952Sume if (!cm->cm_ops->mo_init || 245156952Sume !cm->cm_ops->mo_uninit || 246156952Sume !cm->cm_ops->mo_convert || 247156952Sume !cm->cm_ops->mo_init_state) 248156952Sume goto err; 249156952Sume 250156952Sume /* allocate traits structure */ 251156952Sume cm->cm_traits = malloc(sizeof(*cm->cm_traits)); 252156952Sume if (cm->cm_traits == NULL) { 253156952Sume ret = errno; 254156952Sume goto err; 255156952Sume } 256156952Sume /* initialize the mapper */ 257156952Sume ret = (*cm->cm_ops->mo_init)(ma, cm, ma->ma_dir, 258156952Sume (const void *)variable, strlen(variable) + 1, 259156952Sume cm->cm_traits, sizeof(*cm->cm_traits)); 260156952Sume if (ret) 261156952Sume goto err; 262156952Sume 263156952Sume *rcm = cm; 264156952Sume 265156952Sume return (0); 266156952Sume 267156952Sumeerr: 268156952Sume mapper_close(cm); 269156952Sume return (ret); 270156952Sume} 271156952Sume 272156952Sume/* 273156956Sume * _citrus_mapper_open_direct: 274156956Sume * open a mapper. 275156956Sume */ 276156956Sumeint 277156956Sume_citrus_mapper_open_direct(struct _citrus_mapper_area *__restrict ma, 278156956Sume struct _citrus_mapper * __restrict * __restrict rcm, 279156952Sume const char * __restrict module, const char * __restrict variable) 280156952Sume{ 281156952Sume 282156952Sume return (mapper_open(ma, rcm, module, variable)); 283156952Sume} 284156952Sume 285156952Sume/* 286156952Sume * hash_func 287156952Sume */ 288156952Sumestatic __inline int 289156952Sumehash_func(const char *key) 290156952Sume{ 291156952Sume 292156952Sume return (_string_hash_func(key, CM_HASH_SIZE)); 293156952Sume} 294156952Sume 295156952Sume/* 296156952Sume * match_func 297156952Sume */ 298156952Sumestatic __inline int 299156952Sumematch_func(struct _citrus_mapper *cm, const char *key) 300156952Sume{ 301156952Sume 302156952Sume return (strcmp(cm->cm_key, key)); 303156956Sume} 304156956Sume 305156956Sume/* 306156956Sume * _citrus_mapper_open: 307156956Sume * open a mapper with looking up "mapper.dir". 308156956Sume */ 309156956Sumeint 310156956Sume_citrus_mapper_open(struct _citrus_mapper_area *__restrict ma, 311156956Sume struct _citrus_mapper * __restrict * __restrict rcm, 312156956Sume const char * __restrict mapname) 313156956Sume{ 314156956Sume struct _citrus_mapper *cm; 315156956Sume char linebuf[PATH_MAX]; 316156956Sume const char *module, *variable; 317156956Sume int hashval, ret; 318156956Sume 319156956Sume variable = NULL; 320156956Sume 321156956Sume WLOCK(&cm_lock); 322156956Sume 323156956Sume /* search in the cache */ 324156952Sume hashval = hash_func(mapname); 325 _CITRUS_HASH_SEARCH(&ma->ma_cache, cm, cm_entry, match_func, mapname, 326 hashval); 327 if (cm) { 328 /* found */ 329 cm->cm_refcount++; 330 *rcm = cm; 331 ret = 0; 332 goto quit; 333 } 334 335 /* search mapper entry */ 336 ret = lookup_mapper_entry(ma->ma_dir, mapname, linebuf, 337 (size_t)PATH_MAX, &module, &variable); 338 if (ret) 339 goto quit; 340 341 /* open mapper */ 342 UNLOCK(&cm_lock); 343 ret = mapper_open(ma, &cm, module, variable); 344 WLOCK(&cm_lock); 345 if (ret) 346 goto quit; 347 cm->cm_key = strdup(mapname); 348 if (cm->cm_key == NULL) { 349 ret = errno; 350 _mapper_close(cm); 351 goto quit; 352 } 353 354 /* insert to the cache */ 355 cm->cm_refcount = 1; 356 _CITRUS_HASH_INSERT(&ma->ma_cache, cm, cm_entry, hashval); 357 358 *rcm = cm; 359 ret = 0; 360quit: 361 UNLOCK(&cm_lock); 362 363 return (ret); 364} 365 366/* 367 * _citrus_mapper_close: 368 * close the specified mapper. 369 */ 370void 371_citrus_mapper_close(struct _citrus_mapper *cm) 372{ 373 374 if (cm) { 375 WLOCK(&cm_lock); 376 if (cm->cm_refcount == REFCOUNT_PERSISTENT) 377 goto quit; 378 if (cm->cm_refcount > 0) { 379 if (--cm->cm_refcount > 0) 380 goto quit; 381 _CITRUS_HASH_REMOVE(cm, cm_entry); 382 free(cm->cm_key); 383 } 384 UNLOCK(&cm_lock); 385 mapper_close(cm); 386 return; 387quit: 388 UNLOCK(&cm_lock); 389 } 390} 391 392/* 393 * _citrus_mapper_set_persistent: 394 * set persistent count. 395 */ 396void 397_citrus_mapper_set_persistent(struct _citrus_mapper * __restrict cm) 398{ 399 400 WLOCK(&cm_lock); 401 cm->cm_refcount = REFCOUNT_PERSISTENT; 402 UNLOCK(&cm_lock); 403} 404