citrus_mapper.c revision 219019
1219019Sgabor/* $FreeBSD: head/lib/libc/iconv/citrus_mapper.c 219019 2011-02-25 00:04:39Z gabor $ */ 2219019Sgabor/* $NetBSD: citrus_mapper.c,v 1.7 2008/07/25 14:05:25 christos Exp $ */ 3219019Sgabor 4219019Sgabor/*- 5219019Sgabor * Copyright (c)2003 Citrus Project, 6219019Sgabor * All rights reserved. 7219019Sgabor * 8219019Sgabor * Redistribution and use in source and binary forms, with or without 9219019Sgabor * modification, are permitted provided that the following conditions 10219019Sgabor * are met: 11219019Sgabor * 1. Redistributions of source code must retain the above copyright 12219019Sgabor * notice, this list of conditions and the following disclaimer. 13219019Sgabor * 2. Redistributions in binary form must reproduce the above copyright 14219019Sgabor * notice, this list of conditions and the following disclaimer in the 15219019Sgabor * documentation and/or other materials provided with the distribution. 16219019Sgabor * 17219019Sgabor * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 18219019Sgabor * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 19219019Sgabor * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 20219019Sgabor * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 21219019Sgabor * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 22219019Sgabor * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 23219019Sgabor * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 24219019Sgabor * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 25219019Sgabor * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 26219019Sgabor * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 27219019Sgabor * SUCH DAMAGE. 28219019Sgabor */ 29219019Sgabor 30219019Sgabor#include <sys/cdefs.h> 31219019Sgabor#include <sys/types.h> 32219019Sgabor#include <sys/stat.h> 33219019Sgabor#include <sys/queue.h> 34219019Sgabor 35219019Sgabor#include <assert.h> 36219019Sgabor#include <errno.h> 37219019Sgabor#include <limits.h> 38219019Sgabor#include <stdio.h> 39219019Sgabor#include <stdlib.h> 40219019Sgabor#include <string.h> 41219019Sgabor 42219019Sgabor#include "citrus_namespace.h" 43219019Sgabor#include "citrus_types.h" 44219019Sgabor#include "citrus_region.h" 45219019Sgabor#include "citrus_lock.h" 46219019Sgabor#include "citrus_memstream.h" 47219019Sgabor#include "citrus_bcs.h" 48219019Sgabor#include "citrus_mmap.h" 49219019Sgabor#include "citrus_module.h" 50219019Sgabor#include "citrus_hash.h" 51219019Sgabor#include "citrus_mapper.h" 52219019Sgabor 53219019Sgabor#define _CITRUS_MAPPER_DIR "mapper.dir" 54219019Sgabor 55219019Sgabor#define CM_HASH_SIZE 101 56219019Sgabor#define REFCOUNT_PERSISTENT -1 57219019Sgabor 58219019Sgaborstruct _citrus_mapper_area { 59219019Sgabor _CITRUS_HASH_HEAD(, _citrus_mapper, CM_HASH_SIZE) ma_cache; 60219019Sgabor char *ma_dir; 61219019Sgabor}; 62219019Sgabor 63219019Sgabor/* 64219019Sgabor * _citrus_mapper_create_area: 65219019Sgabor * create mapper area 66219019Sgabor */ 67219019Sgabor 68219019Sgaborint 69219019Sgabor_citrus_mapper_create_area( 70219019Sgabor struct _citrus_mapper_area *__restrict *__restrict rma, 71219019Sgabor const char *__restrict area) 72219019Sgabor{ 73219019Sgabor struct _citrus_mapper_area *ma; 74219019Sgabor struct stat st; 75219019Sgabor char path[PATH_MAX]; 76219019Sgabor int ret; 77219019Sgabor 78219019Sgabor WLOCK; 79219019Sgabor 80219019Sgabor if (*rma != NULL) { 81219019Sgabor ret = 0; 82219019Sgabor goto quit; 83219019Sgabor } 84219019Sgabor 85219019Sgabor snprintf(path, (size_t)PATH_MAX, "%s/%s", area, _CITRUS_MAPPER_DIR); 86219019Sgabor 87219019Sgabor ret = stat(path, &st); 88219019Sgabor if (ret) 89219019Sgabor goto quit; 90219019Sgabor 91219019Sgabor ma = malloc(sizeof(*ma)); 92219019Sgabor if (ma == NULL) { 93219019Sgabor ret = errno; 94219019Sgabor goto quit; 95219019Sgabor } 96219019Sgabor ma->ma_dir = strdup(area); 97219019Sgabor if (ma->ma_dir == NULL) { 98219019Sgabor ret = errno; 99219019Sgabor free(ma->ma_dir); 100219019Sgabor goto quit; 101219019Sgabor } 102219019Sgabor _CITRUS_HASH_INIT(&ma->ma_cache, CM_HASH_SIZE); 103219019Sgabor 104219019Sgabor *rma = ma; 105219019Sgabor ret = 0; 106219019Sgaborquit: 107219019Sgabor UNLOCK; 108219019Sgabor 109219019Sgabor return (ret); 110219019Sgabor} 111219019Sgabor 112219019Sgabor 113219019Sgabor/* 114219019Sgabor * lookup_mapper_entry: 115219019Sgabor * lookup mapper.dir entry in the specified directory. 116219019Sgabor * 117219019Sgabor * line format of iconv.dir file: 118219019Sgabor * mapper module arg 119219019Sgabor * mapper : mapper name. 120219019Sgabor * module : mapper module name. 121219019Sgabor * arg : argument for the module (generally, description file name) 122219019Sgabor */ 123219019Sgabor 124219019Sgaborstatic int 125219019Sgaborlookup_mapper_entry(const char *dir, const char *mapname, void *linebuf, 126219019Sgabor size_t linebufsize, const char **module, const char **variable) 127219019Sgabor{ 128219019Sgabor struct _region r; 129219019Sgabor struct _memstream ms; 130219019Sgabor const char *cp, *cq; 131219019Sgabor char *p; 132219019Sgabor char path[PATH_MAX]; 133219019Sgabor size_t len; 134219019Sgabor int ret; 135219019Sgabor 136219019Sgabor /* create mapper.dir path */ 137219019Sgabor snprintf(path, (size_t)PATH_MAX, "%s/%s", dir, _CITRUS_MAPPER_DIR); 138219019Sgabor 139219019Sgabor /* open read stream */ 140219019Sgabor ret = _map_file(&r, path); 141219019Sgabor if (ret) 142219019Sgabor return (ret); 143219019Sgabor 144219019Sgabor _memstream_bind(&ms, &r); 145219019Sgabor 146219019Sgabor /* search the line matching to the map name */ 147219019Sgabor cp = _memstream_matchline(&ms, mapname, &len, 0); 148219019Sgabor if (!cp) { 149219019Sgabor ret = ENOENT; 150219019Sgabor goto quit; 151219019Sgabor } 152219019Sgabor if (!len || len > linebufsize - 1) { 153219019Sgabor ret = EINVAL; 154219019Sgabor goto quit; 155219019Sgabor } 156219019Sgabor 157219019Sgabor p = linebuf; 158219019Sgabor /* get module name */ 159219019Sgabor *module = p; 160219019Sgabor cq = _bcs_skip_nonws_len(cp, &len); 161219019Sgabor strlcpy(p, cp, (size_t)(cq - cp + 1)); 162219019Sgabor p += cq - cp + 1; 163219019Sgabor 164219019Sgabor /* get variable */ 165219019Sgabor *variable = p; 166219019Sgabor cp = _bcs_skip_ws_len(cq, &len); 167219019Sgabor strlcpy(p, cp, len + 1); 168219019Sgabor 169219019Sgabor ret = 0; 170219019Sgabor 171219019Sgaborquit: 172219019Sgabor _unmap_file(&r); 173219019Sgabor return (ret); 174219019Sgabor} 175219019Sgabor 176219019Sgabor/* 177219019Sgabor * mapper_close: 178219019Sgabor * simply close a mapper. (without handling hash) 179219019Sgabor */ 180219019Sgaborstatic void 181219019Sgabormapper_close(struct _citrus_mapper *cm) 182219019Sgabor{ 183219019Sgabor if (cm->cm_module) { 184219019Sgabor if (cm->cm_ops) { 185219019Sgabor if (cm->cm_closure) 186219019Sgabor (*cm->cm_ops->mo_uninit)(cm); 187219019Sgabor free(cm->cm_ops); 188219019Sgabor } 189219019Sgabor _citrus_unload_module(cm->cm_module); 190219019Sgabor } 191219019Sgabor free(cm->cm_traits); 192219019Sgabor free(cm); 193219019Sgabor} 194219019Sgabor 195219019Sgabor/* 196219019Sgabor * mapper_open: 197219019Sgabor * simply open a mapper. (without handling hash) 198219019Sgabor */ 199219019Sgaborstatic int 200219019Sgabormapper_open(struct _citrus_mapper_area *__restrict ma, 201219019Sgabor struct _citrus_mapper * __restrict * __restrict rcm, 202219019Sgabor const char * __restrict module, 203219019Sgabor const char * __restrict variable) 204219019Sgabor{ 205219019Sgabor struct _citrus_mapper *cm; 206219019Sgabor _citrus_mapper_getops_t getops; 207219019Sgabor int ret; 208219019Sgabor 209219019Sgabor /* initialize mapper handle */ 210219019Sgabor cm = malloc(sizeof(*cm)); 211219019Sgabor if (!cm) 212219019Sgabor return (errno); 213219019Sgabor 214219019Sgabor cm->cm_module = NULL; 215219019Sgabor cm->cm_ops = NULL; 216219019Sgabor cm->cm_closure = NULL; 217219019Sgabor cm->cm_traits = NULL; 218219019Sgabor cm->cm_refcount = 0; 219219019Sgabor cm->cm_key = NULL; 220219019Sgabor 221219019Sgabor /* load module */ 222219019Sgabor ret = _citrus_load_module(&cm->cm_module, module); 223219019Sgabor if (ret) 224219019Sgabor goto err; 225219019Sgabor 226219019Sgabor /* get operators */ 227219019Sgabor getops = (_citrus_mapper_getops_t) 228219019Sgabor _citrus_find_getops(cm->cm_module, module, "mapper"); 229219019Sgabor if (!getops) { 230219019Sgabor ret = EOPNOTSUPP; 231219019Sgabor goto err; 232219019Sgabor } 233219019Sgabor cm->cm_ops = malloc(sizeof(*cm->cm_ops)); 234219019Sgabor if (!cm->cm_ops) { 235219019Sgabor ret = errno; 236219019Sgabor goto err; 237219019Sgabor } 238219019Sgabor ret = (*getops)(cm->cm_ops); 239219019Sgabor if (ret) 240219019Sgabor goto err; 241219019Sgabor 242219019Sgabor if (!cm->cm_ops->mo_init || 243219019Sgabor !cm->cm_ops->mo_uninit || 244219019Sgabor !cm->cm_ops->mo_convert || 245219019Sgabor !cm->cm_ops->mo_init_state) 246219019Sgabor goto err; 247219019Sgabor 248219019Sgabor /* allocate traits structure */ 249219019Sgabor cm->cm_traits = malloc(sizeof(*cm->cm_traits)); 250219019Sgabor if (cm->cm_traits == NULL) { 251219019Sgabor ret = errno; 252219019Sgabor goto err; 253219019Sgabor } 254219019Sgabor /* initialize the mapper */ 255219019Sgabor ret = (*cm->cm_ops->mo_init)(ma, cm, ma->ma_dir, 256219019Sgabor (const void *)variable, strlen(variable) + 1, 257219019Sgabor cm->cm_traits, sizeof(*cm->cm_traits)); 258219019Sgabor if (ret) 259219019Sgabor goto err; 260219019Sgabor 261219019Sgabor *rcm = cm; 262219019Sgabor 263219019Sgabor return (0); 264219019Sgabor 265219019Sgaborerr: 266219019Sgabor mapper_close(cm); 267219019Sgabor return (ret); 268219019Sgabor} 269219019Sgabor 270219019Sgabor/* 271219019Sgabor * _citrus_mapper_open_direct: 272219019Sgabor * open a mapper. 273219019Sgabor */ 274219019Sgaborint 275219019Sgabor_citrus_mapper_open_direct(struct _citrus_mapper_area *__restrict ma, 276219019Sgabor struct _citrus_mapper * __restrict * __restrict rcm, 277219019Sgabor const char * __restrict module, const char * __restrict variable) 278219019Sgabor{ 279219019Sgabor 280219019Sgabor return (mapper_open(ma, rcm, module, variable)); 281219019Sgabor} 282219019Sgabor 283219019Sgabor/* 284219019Sgabor * hash_func 285219019Sgabor */ 286219019Sgaborstatic __inline int 287219019Sgaborhash_func(const char *key) 288219019Sgabor{ 289219019Sgabor 290219019Sgabor return (_string_hash_func(key, CM_HASH_SIZE)); 291219019Sgabor} 292219019Sgabor 293219019Sgabor/* 294219019Sgabor * match_func 295219019Sgabor */ 296219019Sgaborstatic __inline int 297219019Sgabormatch_func(struct _citrus_mapper *cm, const char *key) 298219019Sgabor{ 299219019Sgabor 300219019Sgabor return (strcmp(cm->cm_key, key)); 301219019Sgabor} 302219019Sgabor 303219019Sgabor/* 304219019Sgabor * _citrus_mapper_open: 305219019Sgabor * open a mapper with looking up "mapper.dir". 306219019Sgabor */ 307219019Sgaborint 308219019Sgabor_citrus_mapper_open(struct _citrus_mapper_area *__restrict ma, 309219019Sgabor struct _citrus_mapper * __restrict * __restrict rcm, 310219019Sgabor const char * __restrict mapname) 311219019Sgabor{ 312219019Sgabor struct _citrus_mapper *cm; 313219019Sgabor char linebuf[PATH_MAX]; 314219019Sgabor const char *module, *variable; 315219019Sgabor int hashval, ret; 316219019Sgabor 317219019Sgabor variable = NULL; 318219019Sgabor 319219019Sgabor WLOCK; 320219019Sgabor 321219019Sgabor /* search in the cache */ 322219019Sgabor hashval = hash_func(mapname); 323219019Sgabor _CITRUS_HASH_SEARCH(&ma->ma_cache, cm, cm_entry, match_func, mapname, 324219019Sgabor hashval); 325219019Sgabor if (cm) { 326219019Sgabor /* found */ 327219019Sgabor cm->cm_refcount++; 328219019Sgabor *rcm = cm; 329219019Sgabor ret = 0; 330219019Sgabor goto quit; 331219019Sgabor } 332219019Sgabor 333219019Sgabor /* search mapper entry */ 334219019Sgabor ret = lookup_mapper_entry(ma->ma_dir, mapname, linebuf, 335219019Sgabor (size_t)PATH_MAX, &module, &variable); 336219019Sgabor if (ret) 337219019Sgabor goto quit; 338219019Sgabor 339219019Sgabor /* open mapper */ 340219019Sgabor ret = mapper_open(ma, &cm, module, variable); 341219019Sgabor if (ret) 342219019Sgabor goto quit; 343219019Sgabor cm->cm_key = strdup(mapname); 344219019Sgabor if (cm->cm_key == NULL) { 345219019Sgabor ret = errno; 346219019Sgabor _mapper_close(cm); 347219019Sgabor goto quit; 348219019Sgabor } 349219019Sgabor 350219019Sgabor /* insert to the cache */ 351219019Sgabor cm->cm_refcount = 1; 352219019Sgabor _CITRUS_HASH_INSERT(&ma->ma_cache, cm, cm_entry, hashval); 353219019Sgabor 354219019Sgabor *rcm = cm; 355219019Sgabor ret = 0; 356219019Sgaborquit: 357219019Sgabor UNLOCK; 358219019Sgabor 359219019Sgabor return (ret); 360219019Sgabor} 361219019Sgabor 362219019Sgabor/* 363219019Sgabor * _citrus_mapper_close: 364219019Sgabor * close the specified mapper. 365219019Sgabor */ 366219019Sgaborvoid 367219019Sgabor_citrus_mapper_close(struct _citrus_mapper *cm) 368219019Sgabor{ 369219019Sgabor 370219019Sgabor if (cm) { 371219019Sgabor WLOCK; 372219019Sgabor if (cm->cm_refcount == REFCOUNT_PERSISTENT) 373219019Sgabor goto quit; 374219019Sgabor if (cm->cm_refcount > 0) { 375219019Sgabor if (--cm->cm_refcount > 0) 376219019Sgabor goto quit; 377219019Sgabor _CITRUS_HASH_REMOVE(cm, cm_entry); 378219019Sgabor free(cm->cm_key); 379219019Sgabor } 380219019Sgabor mapper_close(cm); 381219019Sgaborquit: 382219019Sgabor UNLOCK; 383219019Sgabor } 384219019Sgabor} 385219019Sgabor 386219019Sgabor/* 387219019Sgabor * _citrus_mapper_set_persistent: 388219019Sgabor * set persistent count. 389219019Sgabor */ 390219019Sgaborvoid 391219019Sgabor_citrus_mapper_set_persistent(struct _citrus_mapper * __restrict cm) 392219019Sgabor{ 393219019Sgabor 394219019Sgabor WLOCK; 395219019Sgabor cm->cm_refcount = REFCOUNT_PERSISTENT; 396219019Sgabor UNLOCK; 397219019Sgabor} 398