1 /* $NetBSD: src/lib/libc/citrus/citrus_esdb.c,v 1.4 2004/07/21 14:16:34 tshiozak Exp $ */ 2 /* $DragonFly: src/lib/libc/citrus/citrus_esdb.c,v 1.1 2005/03/11 23:33:53 joerg Exp $ */ 3 4 5 /*- 6 * Copyright (c)2003 Citrus Project, 7 * All rights reserved. 8 * 9 * Redistribution and use in source and binary forms, with or without 10 * modification, are permitted provided that the following conditions 11 * are met: 12 * 1. Redistributions of source code must retain the above copyright 13 * notice, this list of conditions and the following disclaimer. 14 * 2. Redistributions in binary form must reproduce the above copyright 15 * notice, this list of conditions and the following disclaimer in the 16 * documentation and/or other materials provided with the distribution. 17 * 18 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 19 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 20 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 21 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 22 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 23 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 24 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 25 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 26 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 27 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 28 * SUCH DAMAGE. 29 */ 30 31 #include <assert.h> 32 #include <stdio.h> 33 #include <stdlib.h> 34 #include <string.h> 35 #include <errno.h> 36 #include <limits.h> 37 #include <paths.h> 38 #include <sys/types.h> 39 40 #include "citrus_namespace.h" 41 #include "citrus_types.h" 42 #include "citrus_bcs.h" 43 #include "citrus_region.h" 44 #include "citrus_memstream.h" 45 #include "citrus_mmap.h" 46 #include "citrus_lookup.h" 47 #include "citrus_db.h" 48 #include "citrus_db_hash.h" 49 #include "citrus_esdb.h" 50 #include "citrus_esdb_file.h" 51 52 #define ESDB_DIR "esdb.dir" 53 #define ESDB_ALIAS "esdb.alias" 54 55 /* 56 * _citrus_esdb_alias: 57 * resolve encoding scheme name aliases. 58 */ 59 const char * 60 _citrus_esdb_alias(const char *esname, char *buf, size_t bufsize) 61 { 62 return _lookup_alias(_PATH_ESDB "/" ESDB_ALIAS, esname, buf, bufsize, 63 _LOOKUP_CASE_IGNORE); 64 } 65 66 67 /* 68 * conv_esdb: 69 * external representation -> local structure. 70 */ 71 static int 72 conv_esdb(struct _citrus_esdb *esdb, struct _region *fr) 73 { 74 int ret; 75 struct _citrus_db *db; 76 uint32_t version, num_charsets, csid, i, tmp; 77 char buf[100]; 78 const char *str; 79 80 /* open db */ 81 ret = _db_open(&db, fr, _CITRUS_ESDB_MAGIC, &_db_hash_std, NULL); 82 if (ret) 83 goto err0; 84 85 /* check version */ 86 ret = _db_lookup32_by_s(db, _CITRUS_ESDB_SYM_VERSION, &version, NULL); 87 if (ret) 88 goto err1; 89 switch (version) { 90 case 0x00000001: 91 /* current version */ 92 /* initial version */ 93 break; 94 default: 95 ret = EFTYPE; 96 goto err1; 97 } 98 99 /* get encoding/variable */ 100 ret = _db_lookupstr_by_s(db, _CITRUS_ESDB_SYM_ENCODING, &str, NULL); 101 if (ret) 102 goto err1; 103 esdb->db_encname = strdup(str); 104 if (esdb->db_encname == NULL) { 105 ret = errno; 106 goto err1; 107 } 108 109 esdb->db_len_variable = 0; 110 esdb->db_variable = NULL; 111 ret = _db_lookupstr_by_s(db, _CITRUS_ESDB_SYM_VARIABLE, &str, NULL); 112 if (ret == 0) { 113 esdb->db_len_variable = strlen(str)+1; 114 esdb->db_variable = strdup(str); 115 if (esdb->db_variable == NULL) { 116 ret = errno; 117 goto err2; 118 } 119 } else if (ret != ENOENT) 120 goto err2; 121 122 /* get number of charsets */ 123 ret = _db_lookup32_by_s(db, _CITRUS_ESDB_SYM_NUM_CHARSETS, 124 &num_charsets, NULL); 125 if (ret) 126 goto err3; 127 esdb->db_num_charsets = num_charsets; 128 129 /* get invalid character */ 130 ret = _db_lookup32_by_s(db, _CITRUS_ESDB_SYM_INVALID, &tmp, NULL); 131 if (ret == 0) { 132 esdb->db_use_invalid = 1; 133 esdb->db_invalid = tmp; 134 } else if (ret == ENOENT) 135 esdb->db_use_invalid = 0; 136 else 137 goto err3; 138 139 /* get charsets */ 140 esdb->db_charsets = malloc(num_charsets * sizeof(*esdb->db_charsets)); 141 if (esdb->db_charsets == NULL) { 142 ret = errno; 143 goto err3; 144 } 145 for (i = 0; i < num_charsets; i++) { 146 snprintf(buf, sizeof(buf), 147 _CITRUS_ESDB_SYM_CSID_PREFIX "%d", i); 148 ret = _db_lookup32_by_s(db, buf, &csid, NULL); 149 if (ret) 150 goto err4; 151 esdb->db_charsets[i].ec_csid = csid; 152 153 snprintf(buf, sizeof(buf), 154 _CITRUS_ESDB_SYM_CSNAME_PREFIX "%d", i); 155 ret = _db_lookupstr_by_s(db, buf, &str, NULL); 156 if (ret) 157 goto err4; 158 esdb->db_charsets[i].ec_csname = strdup(str); 159 if (esdb->db_charsets[i].ec_csname == NULL) { 160 ret = errno; 161 goto err4; 162 } 163 } 164 165 _db_close(db); 166 return 0; 167 168 err4: 169 for (; i > 0; i--) 170 free(esdb->db_charsets[i - 1].ec_csname); 171 free(esdb->db_charsets); 172 err3: 173 free(esdb->db_variable); 174 err2: 175 free(esdb->db_encname); 176 err1: 177 _db_close(db); 178 if (ret == ENOENT) 179 ret = EFTYPE; 180 err0: 181 return ret; 182 } 183 184 /* 185 * _citrus_esdb_open: 186 * open an ESDB file. 187 */ 188 int 189 _citrus_esdb_open(struct _citrus_esdb *db, const char *esname) 190 { 191 int ret; 192 const char *realname, *encfile; 193 char buf1[PATH_MAX], buf2[PATH_MAX], path[PATH_MAX]; 194 struct _region fr; 195 196 _DIAGASSERT(esname != NULL); 197 198 snprintf(path, sizeof(path), "%s/%s", _PATH_ESDB, ESDB_ALIAS); 199 realname = _lookup_alias(path, esname, buf1, sizeof(buf1), 200 _LOOKUP_CASE_IGNORE); 201 202 snprintf(path, sizeof(path), "%s/%s", _PATH_ESDB, ESDB_DIR); 203 encfile = _lookup_simple(path, realname, buf2, sizeof(buf2), 204 _LOOKUP_CASE_IGNORE); 205 if (encfile==NULL) 206 return ENOENT; 207 208 /* open file */ 209 snprintf(path, sizeof(path), "%s/%s", _PATH_ESDB, encfile); 210 ret = _map_file(&fr, path); 211 if (ret) 212 return ret; 213 214 ret = conv_esdb(db, &fr); 215 216 _unmap_file(&fr); 217 218 return ret; 219 } 220 221 /* 222 * _citrus_esdb_close: 223 * free an ESDB. 224 */ 225 void 226 _citrus_esdb_close(struct _citrus_esdb *db) 227 { 228 int i; 229 230 _DIAGASSERT(db != NULL); 231 _DIAGASSERT(db->db_num_charsets == 0 || db->db_charsets != NULL); 232 233 for (i = 0; i < db->db_num_charsets; i++) 234 free(db->db_charsets[i].ec_csname); 235 db->db_num_charsets = 0; 236 free(db->db_charsets); db->db_charsets = NULL; 237 free(db->db_encname); db->db_encname = NULL; 238 db->db_len_variable = 0; 239 free(db->db_variable); db->db_variable = NULL; 240 } 241 242 /* 243 * _citrus_esdb_free_list: 244 * free the list. 245 */ 246 void 247 _citrus_esdb_free_list(char **list, size_t num) 248 { 249 size_t i; 250 251 for (i = 0; i < num; i++) 252 free(list[i]); 253 free(list); 254 } 255 256 /* 257 * _citrus_esdb_get_list: 258 * get esdb entries. 259 */ 260 int 261 _citrus_esdb_get_list(char ***rlist, size_t *rnum) 262 { 263 int ret; 264 struct _region key; 265 size_t num; 266 struct _citrus_lookup *cla, *cld; 267 char **list, **q; 268 char buf[PATH_MAX]; 269 270 num = 0; 271 272 ret = _lookup_seq_open(&cla, _PATH_ESDB "/" ESDB_ALIAS, 273 _LOOKUP_CASE_IGNORE); 274 if (ret) 275 goto quit0; 276 277 ret = _lookup_seq_open(&cld, _PATH_ESDB "/" ESDB_DIR, 278 _LOOKUP_CASE_IGNORE); 279 if (ret) 280 goto quit1; 281 282 /* count number of entries */ 283 num = _lookup_get_num_entries(cla) + _lookup_get_num_entries(cld); 284 285 _lookup_seq_rewind(cla); 286 _lookup_seq_rewind(cld); 287 288 /* allocate list pointer space */ 289 list = malloc(num * sizeof(char *)); 290 num = 0; 291 if (list == NULL) { 292 ret = errno; 293 goto quit3; 294 } 295 296 /* get alias entries */ 297 while ((ret = _lookup_seq_next(cla, &key, NULL)) == 0) { 298 snprintf(buf, sizeof(buf), "%.*s", 299 (int)_region_size(&key), 300 (const char *)_region_head(&key)); 301 _bcs_convert_to_lower(buf); 302 list[num] = strdup(buf); 303 if (list[num] == NULL) { 304 ret = errno; 305 goto quit3; 306 } 307 num++; 308 } 309 if (ret != ENOENT) 310 goto quit3; 311 /* get dir entries */ 312 while ((ret = _lookup_seq_next(cld, &key, NULL)) == 0) { 313 /* check duplicated entry */ 314 snprintf(buf, sizeof(buf), "%.*s", 315 (int)_region_size(&key), 316 (const char *)_region_head(&key)); 317 _bcs_convert_to_lower(buf); 318 ret = _lookup_seq_lookup(cla, buf, NULL); 319 if (ret) { 320 if (ret != ENOENT) 321 goto quit3; 322 /* not duplicated */ 323 list[num] = strdup(buf); 324 if (list[num] == NULL) { 325 ret = errno; 326 goto quit3; 327 } 328 num++; 329 } 330 } 331 if (ret != ENOENT) 332 goto quit3; 333 334 ret = 0; 335 q = realloc(list, num * sizeof(char *)); 336 if (!q) { 337 ret = ENOMEM; 338 goto quit3; 339 } 340 list = q; 341 *rlist = list; 342 *rnum = num; 343 quit3: 344 if (ret) 345 _citrus_esdb_free_list(list, num); 346 _lookup_seq_close(cld); 347 quit1: 348 _lookup_seq_close(cla); 349 quit0: 350 return ret; 351 } 352