10d5acd74SJohn Marino /*********************************************************** 20d5acd74SJohn Marino Copyright 1990, by Alfalfa Software Incorporated, Cambridge, Massachusetts. 30d5acd74SJohn Marino Copyright 2010, Gabor Kovesdan <gabor@FreeBSD.org> 40d5acd74SJohn Marino 50d5acd74SJohn Marino All Rights Reserved 60d5acd74SJohn Marino 70d5acd74SJohn Marino Permission to use, copy, modify, and distribute this software and its 80d5acd74SJohn Marino documentation for any purpose and without fee is hereby granted, 90d5acd74SJohn Marino provided that the above copyright notice appear in all copies and that 100d5acd74SJohn Marino both that copyright notice and this permission notice appear in 110d5acd74SJohn Marino supporting documentation, and that Alfalfa's name not be used in 120d5acd74SJohn Marino advertising or publicity pertaining to distribution of the software 130d5acd74SJohn Marino without specific, written prior permission. 140d5acd74SJohn Marino 150d5acd74SJohn Marino ALPHALPHA DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING 160d5acd74SJohn Marino ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL 170d5acd74SJohn Marino ALPHALPHA BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR 180d5acd74SJohn Marino ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, 190d5acd74SJohn Marino WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, 200d5acd74SJohn Marino ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS 210d5acd74SJohn Marino SOFTWARE. 220d5acd74SJohn Marino 230d5acd74SJohn Marino If you make any modifications, bugfixes or other changes to this software 240d5acd74SJohn Marino we'd appreciate it if you could send a copy to us so we can keep things 250d5acd74SJohn Marino up-to-date. Many thanks. 260d5acd74SJohn Marino Kee Hinckley 270d5acd74SJohn Marino Alfalfa Software, Inc. 280d5acd74SJohn Marino 267 Allston St., #3 290d5acd74SJohn Marino Cambridge, MA 02139 USA 300d5acd74SJohn Marino nazgul@alfalfa.com 310d5acd74SJohn Marino 32*4bbf0fc0Szrj $FreeBSD: head/lib/libc/nls/msgcat.c 304755 2016-08-24 16:44:27Z ache $ 330d5acd74SJohn Marino ******************************************************************/ 340d5acd74SJohn Marino 350d5acd74SJohn Marino #define _NLS_PRIVATE 360d5acd74SJohn Marino 370d5acd74SJohn Marino #include "namespace.h" 380d5acd74SJohn Marino #include <sys/types.h> 390d5acd74SJohn Marino #include <sys/stat.h> 400d5acd74SJohn Marino #include <sys/mman.h> 410d5acd74SJohn Marino #include <sys/queue.h> 420d5acd74SJohn Marino 430d5acd74SJohn Marino #include <arpa/inet.h> /* for ntohl() */ 440d5acd74SJohn Marino 450d5acd74SJohn Marino #include <errno.h> 460d5acd74SJohn Marino #include <fcntl.h> 470d5acd74SJohn Marino #include <limits.h> 480d5acd74SJohn Marino #include <nl_types.h> 490d5acd74SJohn Marino #include <pthread.h> 500d5acd74SJohn Marino #include <stdio.h> 510d5acd74SJohn Marino #include <stdlib.h> 520d5acd74SJohn Marino #include <string.h> 530d5acd74SJohn Marino #include <unistd.h> 540d5acd74SJohn Marino #include "un-namespace.h" 550d5acd74SJohn Marino 5621a0e97dSSascha Wildner #include "../locale/xlocale_private.h" 570d5acd74SJohn Marino 580d5acd74SJohn Marino #define _DEFAULT_NLS_PATH "/usr/share/nls/%L/%N.cat:/usr/share/nls/%N/%L:/usr/local/share/nls/%L/%N.cat:/usr/local/share/nls/%N/%L" 590d5acd74SJohn Marino 600d5acd74SJohn Marino #define RLOCK(fail) { int ret; \ 610d5acd74SJohn Marino if (__isthreaded && \ 620d5acd74SJohn Marino ((ret = _pthread_rwlock_rdlock(&rwlock)) != 0)) { \ 630d5acd74SJohn Marino errno = ret; \ 640d5acd74SJohn Marino return (fail); \ 650d5acd74SJohn Marino }} 660d5acd74SJohn Marino #define WLOCK(fail) { int ret; \ 670d5acd74SJohn Marino if (__isthreaded && \ 680d5acd74SJohn Marino ((ret = _pthread_rwlock_wrlock(&rwlock)) != 0)) { \ 690d5acd74SJohn Marino errno = ret; \ 700d5acd74SJohn Marino return (fail); \ 710d5acd74SJohn Marino }} 720d5acd74SJohn Marino #define UNLOCK { if (__isthreaded) \ 730d5acd74SJohn Marino _pthread_rwlock_unlock(&rwlock); } 740d5acd74SJohn Marino 750d5acd74SJohn Marino #define NLERR ((nl_catd) -1) 760d5acd74SJohn Marino #define NLRETERR(errc) { errno = errc; return (NLERR); } 770d5acd74SJohn Marino #define SAVEFAIL(n, l, e) { WLOCK(NLERR); \ 780d5acd74SJohn Marino np = malloc(sizeof(struct catentry)); \ 790d5acd74SJohn Marino if (np != NULL) { \ 800d5acd74SJohn Marino np->name = strdup(n); \ 810d5acd74SJohn Marino np->path = NULL; \ 820d5acd74SJohn Marino np->catd = NLERR; \ 83*4bbf0fc0Szrj np->refcount = 0; \ 840d5acd74SJohn Marino np->lang = (l == NULL) ? NULL : \ 850d5acd74SJohn Marino strdup(l); \ 860d5acd74SJohn Marino np->caterrno = e; \ 870d5acd74SJohn Marino SLIST_INSERT_HEAD(&cache, np, list); \ 880d5acd74SJohn Marino } \ 890d5acd74SJohn Marino UNLOCK; \ 900d5acd74SJohn Marino errno = e; \ 910d5acd74SJohn Marino } 920d5acd74SJohn Marino 930d5acd74SJohn Marino static nl_catd load_msgcat(const char *, const char *, const char *); 940d5acd74SJohn Marino 950d5acd74SJohn Marino static pthread_rwlock_t rwlock = PTHREAD_RWLOCK_INITIALIZER; 960d5acd74SJohn Marino 970d5acd74SJohn Marino struct catentry { 980d5acd74SJohn Marino SLIST_ENTRY(catentry) list; 990d5acd74SJohn Marino char *name; 1000d5acd74SJohn Marino char *path; 1010d5acd74SJohn Marino int caterrno; 1020d5acd74SJohn Marino nl_catd catd; 1030d5acd74SJohn Marino char *lang; 1040d5acd74SJohn Marino int refcount; 1050d5acd74SJohn Marino }; 1060d5acd74SJohn Marino 1070d5acd74SJohn Marino SLIST_HEAD(listhead, catentry) cache = 1080d5acd74SJohn Marino SLIST_HEAD_INITIALIZER(cache); 1090d5acd74SJohn Marino 1100d5acd74SJohn Marino nl_catd 1110d5acd74SJohn Marino catopen(const char *name, int type) 1120d5acd74SJohn Marino { 1130d5acd74SJohn Marino struct stat sbuf; 1140d5acd74SJohn Marino struct catentry *np; 11521a0e97dSSascha Wildner char *base, *cptr, *cptr1, *nlspath, *pathP, *pcode; 11621a0e97dSSascha Wildner char *plang, *pter; 1170d5acd74SJohn Marino int saverr, spcleft; 11821a0e97dSSascha Wildner const char *lang, *tmpptr; 1190d5acd74SJohn Marino char path[PATH_MAX]; 1200d5acd74SJohn Marino 1210d5acd74SJohn Marino /* sanity checking */ 1220d5acd74SJohn Marino if (name == NULL || *name == '\0') 1230d5acd74SJohn Marino NLRETERR(EINVAL); 1240d5acd74SJohn Marino 1250d5acd74SJohn Marino if (strchr(name, '/') != NULL) 1260d5acd74SJohn Marino /* have a pathname */ 1270d5acd74SJohn Marino lang = NULL; 1280d5acd74SJohn Marino else { 1290d5acd74SJohn Marino if (type == NL_CAT_LOCALE) 13021a0e97dSSascha Wildner lang = querylocale(LC_MESSAGES_MASK, __get_locale()); 1310d5acd74SJohn Marino else 1320d5acd74SJohn Marino lang = getenv("LANG"); 1330d5acd74SJohn Marino 1340d5acd74SJohn Marino if (lang == NULL || *lang == '\0' || strlen(lang) > ENCODING_LEN || 1350d5acd74SJohn Marino (lang[0] == '.' && 1360d5acd74SJohn Marino (lang[1] == '\0' || (lang[1] == '.' && lang[2] == '\0'))) || 1370d5acd74SJohn Marino strchr(lang, '/') != NULL) 1380d5acd74SJohn Marino lang = "C"; 1390d5acd74SJohn Marino } 1400d5acd74SJohn Marino 1410d5acd74SJohn Marino /* Try to get it from the cache first */ 1420d5acd74SJohn Marino RLOCK(NLERR); 1430d5acd74SJohn Marino SLIST_FOREACH(np, &cache, list) { 1440d5acd74SJohn Marino if ((strcmp(np->name, name) == 0) && 1450d5acd74SJohn Marino ((lang != NULL && np->lang != NULL && 1460d5acd74SJohn Marino strcmp(np->lang, lang) == 0) || (np->lang == lang))) { 1470d5acd74SJohn Marino if (np->caterrno != 0) { 1480d5acd74SJohn Marino /* Found cached failing entry */ 1490d5acd74SJohn Marino UNLOCK; 1500d5acd74SJohn Marino NLRETERR(np->caterrno); 1510d5acd74SJohn Marino } else { 1520d5acd74SJohn Marino /* Found cached successful entry */ 1530d5acd74SJohn Marino np->refcount++; 1540d5acd74SJohn Marino UNLOCK; 1550d5acd74SJohn Marino return (np->catd); 1560d5acd74SJohn Marino } 1570d5acd74SJohn Marino } 1580d5acd74SJohn Marino } 1590d5acd74SJohn Marino UNLOCK; 1600d5acd74SJohn Marino 1610d5acd74SJohn Marino /* is it absolute path ? if yes, load immediately */ 1620d5acd74SJohn Marino if (strchr(name, '/') != NULL) 1630d5acd74SJohn Marino return (load_msgcat(name, name, lang)); 1640d5acd74SJohn Marino 1650d5acd74SJohn Marino /* sanity checking */ 1660d5acd74SJohn Marino if ((plang = cptr1 = strdup(lang)) == NULL) 1670d5acd74SJohn Marino return (NLERR); 1680d5acd74SJohn Marino if ((cptr = strchr(cptr1, '@')) != NULL) 1690d5acd74SJohn Marino *cptr = '\0'; 1700d5acd74SJohn Marino pter = pcode = ""; 1710d5acd74SJohn Marino if ((cptr = strchr(cptr1, '_')) != NULL) { 1720d5acd74SJohn Marino *cptr++ = '\0'; 1730d5acd74SJohn Marino pter = cptr1 = cptr; 1740d5acd74SJohn Marino } 1750d5acd74SJohn Marino if ((cptr = strchr(cptr1, '.')) != NULL) { 1760d5acd74SJohn Marino *cptr++ = '\0'; 1770d5acd74SJohn Marino pcode = cptr; 1780d5acd74SJohn Marino } 1790d5acd74SJohn Marino 1800d5acd74SJohn Marino if ((nlspath = getenv("NLSPATH")) == NULL || issetugid()) 1810d5acd74SJohn Marino nlspath = _DEFAULT_NLS_PATH; 1820d5acd74SJohn Marino 1830d5acd74SJohn Marino if ((base = cptr = strdup(nlspath)) == NULL) { 1840d5acd74SJohn Marino saverr = errno; 1850d5acd74SJohn Marino free(plang); 1860d5acd74SJohn Marino errno = saverr; 1870d5acd74SJohn Marino return (NLERR); 1880d5acd74SJohn Marino } 1890d5acd74SJohn Marino 1900d5acd74SJohn Marino while ((nlspath = strsep(&cptr, ":")) != NULL) { 1910d5acd74SJohn Marino pathP = path; 1920d5acd74SJohn Marino if (*nlspath) { 1930d5acd74SJohn Marino for (; *nlspath; ++nlspath) { 1940d5acd74SJohn Marino if (*nlspath == '%') { 1950d5acd74SJohn Marino switch (*(nlspath + 1)) { 1960d5acd74SJohn Marino case 'l': 1970d5acd74SJohn Marino tmpptr = plang; 1980d5acd74SJohn Marino break; 1990d5acd74SJohn Marino case 't': 2000d5acd74SJohn Marino tmpptr = pter; 2010d5acd74SJohn Marino break; 2020d5acd74SJohn Marino case 'c': 2030d5acd74SJohn Marino tmpptr = pcode; 2040d5acd74SJohn Marino break; 2050d5acd74SJohn Marino case 'L': 2060d5acd74SJohn Marino tmpptr = lang; 2070d5acd74SJohn Marino break; 2080d5acd74SJohn Marino case 'N': 2090d5acd74SJohn Marino tmpptr = (char *)name; 2100d5acd74SJohn Marino break; 2110d5acd74SJohn Marino case '%': 2120d5acd74SJohn Marino ++nlspath; 2130d5acd74SJohn Marino /* FALLTHROUGH */ 2140d5acd74SJohn Marino default: 2150d5acd74SJohn Marino if (pathP - path >= 2160d5acd74SJohn Marino sizeof(path) - 1) 2170d5acd74SJohn Marino goto too_long; 2180d5acd74SJohn Marino *(pathP++) = *nlspath; 2190d5acd74SJohn Marino continue; 2200d5acd74SJohn Marino } 2210d5acd74SJohn Marino ++nlspath; 2220d5acd74SJohn Marino put_tmpptr: 2230d5acd74SJohn Marino spcleft = sizeof(path) - 2240d5acd74SJohn Marino (pathP - path) - 1; 2250d5acd74SJohn Marino if (strlcpy(pathP, tmpptr, spcleft) >= 2260d5acd74SJohn Marino spcleft) { 2270d5acd74SJohn Marino too_long: 2280d5acd74SJohn Marino free(plang); 2290d5acd74SJohn Marino free(base); 2300d5acd74SJohn Marino SAVEFAIL(name, lang, ENAMETOOLONG); 2310d5acd74SJohn Marino NLRETERR(ENAMETOOLONG); 2320d5acd74SJohn Marino } 2330d5acd74SJohn Marino pathP += strlen(tmpptr); 2340d5acd74SJohn Marino } else { 2350d5acd74SJohn Marino if (pathP - path >= sizeof(path) - 1) 2360d5acd74SJohn Marino goto too_long; 2370d5acd74SJohn Marino *(pathP++) = *nlspath; 2380d5acd74SJohn Marino } 2390d5acd74SJohn Marino } 2400d5acd74SJohn Marino *pathP = '\0'; 2410d5acd74SJohn Marino if (stat(path, &sbuf) == 0) { 2420d5acd74SJohn Marino free(plang); 2430d5acd74SJohn Marino free(base); 2440d5acd74SJohn Marino return (load_msgcat(path, name, lang)); 2450d5acd74SJohn Marino } 2460d5acd74SJohn Marino } else { 2470d5acd74SJohn Marino tmpptr = (char *)name; 2480d5acd74SJohn Marino --nlspath; 2490d5acd74SJohn Marino goto put_tmpptr; 2500d5acd74SJohn Marino } 2510d5acd74SJohn Marino } 2520d5acd74SJohn Marino free(plang); 2530d5acd74SJohn Marino free(base); 2540d5acd74SJohn Marino SAVEFAIL(name, lang, ENOENT); 2550d5acd74SJohn Marino NLRETERR(ENOENT); 2560d5acd74SJohn Marino } 2570d5acd74SJohn Marino 2580d5acd74SJohn Marino char * 2590d5acd74SJohn Marino catgets(nl_catd catd, int set_id, int msg_id, const char *s) 2600d5acd74SJohn Marino { 2610d5acd74SJohn Marino struct _nls_cat_hdr *cat_hdr; 2620d5acd74SJohn Marino struct _nls_msg_hdr *msg_hdr; 2630d5acd74SJohn Marino struct _nls_set_hdr *set_hdr; 2640d5acd74SJohn Marino int i, l, r, u; 2650d5acd74SJohn Marino 2660d5acd74SJohn Marino if (catd == NULL || catd == NLERR) { 2670d5acd74SJohn Marino errno = EBADF; 2680d5acd74SJohn Marino /* LINTED interface problem */ 2690d5acd74SJohn Marino return ((char *)s); 2700d5acd74SJohn Marino } 2710d5acd74SJohn Marino 2720d5acd74SJohn Marino cat_hdr = (struct _nls_cat_hdr *)catd->__data; 2730d5acd74SJohn Marino set_hdr = (struct _nls_set_hdr *)(void *)((char *)catd->__data + 2740d5acd74SJohn Marino sizeof(struct _nls_cat_hdr)); 2750d5acd74SJohn Marino 2760d5acd74SJohn Marino /* binary search, see knuth algorithm b */ 2770d5acd74SJohn Marino l = 0; 2780d5acd74SJohn Marino u = ntohl((u_int32_t)cat_hdr->__nsets) - 1; 2790d5acd74SJohn Marino while (l <= u) { 2800d5acd74SJohn Marino i = (l + u) / 2; 2810d5acd74SJohn Marino r = set_id - ntohl((u_int32_t)set_hdr[i].__setno); 2820d5acd74SJohn Marino 2830d5acd74SJohn Marino if (r == 0) { 2840d5acd74SJohn Marino msg_hdr = (struct _nls_msg_hdr *) 2850d5acd74SJohn Marino (void *)((char *)catd->__data + 2860d5acd74SJohn Marino sizeof(struct _nls_cat_hdr) + 2870d5acd74SJohn Marino ntohl((u_int32_t)cat_hdr->__msg_hdr_offset)); 2880d5acd74SJohn Marino 2890d5acd74SJohn Marino l = ntohl((u_int32_t)set_hdr[i].__index); 2900d5acd74SJohn Marino u = l + ntohl((u_int32_t)set_hdr[i].__nmsgs) - 1; 2910d5acd74SJohn Marino while (l <= u) { 2920d5acd74SJohn Marino i = (l + u) / 2; 2930d5acd74SJohn Marino r = msg_id - 2940d5acd74SJohn Marino ntohl((u_int32_t)msg_hdr[i].__msgno); 2950d5acd74SJohn Marino if (r == 0) { 2960d5acd74SJohn Marino return ((char *) catd->__data + 2970d5acd74SJohn Marino sizeof(struct _nls_cat_hdr) + 2980d5acd74SJohn Marino ntohl((u_int32_t) 2990d5acd74SJohn Marino cat_hdr->__msg_txt_offset) + 3000d5acd74SJohn Marino ntohl((u_int32_t) 3010d5acd74SJohn Marino msg_hdr[i].__offset)); 3020d5acd74SJohn Marino } else if (r < 0) { 3030d5acd74SJohn Marino u = i - 1; 3040d5acd74SJohn Marino } else { 3050d5acd74SJohn Marino l = i + 1; 3060d5acd74SJohn Marino } 3070d5acd74SJohn Marino } 3080d5acd74SJohn Marino 3090d5acd74SJohn Marino /* not found */ 3100d5acd74SJohn Marino goto notfound; 3110d5acd74SJohn Marino 3120d5acd74SJohn Marino } else if (r < 0) { 3130d5acd74SJohn Marino u = i - 1; 3140d5acd74SJohn Marino } else { 3150d5acd74SJohn Marino l = i + 1; 3160d5acd74SJohn Marino } 3170d5acd74SJohn Marino } 3180d5acd74SJohn Marino 3190d5acd74SJohn Marino notfound: 3200d5acd74SJohn Marino /* not found */ 3210d5acd74SJohn Marino errno = ENOMSG; 3220d5acd74SJohn Marino /* LINTED interface problem */ 3230d5acd74SJohn Marino return ((char *)s); 3240d5acd74SJohn Marino } 3250d5acd74SJohn Marino 326*4bbf0fc0Szrj static void 327*4bbf0fc0Szrj catfree(struct catentry *np) 328*4bbf0fc0Szrj { 329*4bbf0fc0Szrj 330*4bbf0fc0Szrj if (np->catd != NULL && np->catd != NLERR) { 331*4bbf0fc0Szrj munmap(np->catd->__data, (size_t)np->catd->__size); 332*4bbf0fc0Szrj free(np->catd); 333*4bbf0fc0Szrj } 334*4bbf0fc0Szrj SLIST_REMOVE(&cache, np, catentry, list); 335*4bbf0fc0Szrj free(np->name); 336*4bbf0fc0Szrj free(np->path); 337*4bbf0fc0Szrj free(np->lang); 338*4bbf0fc0Szrj free(np); 339*4bbf0fc0Szrj } 340*4bbf0fc0Szrj 3410d5acd74SJohn Marino int 3420d5acd74SJohn Marino catclose(nl_catd catd) 3430d5acd74SJohn Marino { 3440d5acd74SJohn Marino struct catentry *np; 3450d5acd74SJohn Marino 3460d5acd74SJohn Marino /* sanity checking */ 3470d5acd74SJohn Marino if (catd == NULL || catd == NLERR) { 3480d5acd74SJohn Marino errno = EBADF; 3490d5acd74SJohn Marino return (-1); 3500d5acd74SJohn Marino } 3510d5acd74SJohn Marino 3520d5acd74SJohn Marino /* Remove from cache if not referenced any more */ 3530d5acd74SJohn Marino WLOCK(-1); 3540d5acd74SJohn Marino SLIST_FOREACH(np, &cache, list) { 3550d5acd74SJohn Marino if (catd == np->catd) { 3560d5acd74SJohn Marino np->refcount--; 357*4bbf0fc0Szrj if (np->refcount == 0) 358*4bbf0fc0Szrj catfree(np); 3590d5acd74SJohn Marino break; 3600d5acd74SJohn Marino } 3610d5acd74SJohn Marino } 3620d5acd74SJohn Marino UNLOCK; 3630d5acd74SJohn Marino return (0); 3640d5acd74SJohn Marino } 3650d5acd74SJohn Marino 3660d5acd74SJohn Marino /* 3670d5acd74SJohn Marino * Internal support functions 3680d5acd74SJohn Marino */ 3690d5acd74SJohn Marino 3700d5acd74SJohn Marino static nl_catd 3710d5acd74SJohn Marino load_msgcat(const char *path, const char *name, const char *lang) 3720d5acd74SJohn Marino { 3730d5acd74SJohn Marino struct stat st; 3740d5acd74SJohn Marino nl_catd catd; 3750d5acd74SJohn Marino struct catentry *np; 3760d5acd74SJohn Marino void *data; 3770d5acd74SJohn Marino int fd; 3780d5acd74SJohn Marino 3790d5acd74SJohn Marino /* path/name will never be NULL here */ 3800d5acd74SJohn Marino 3810d5acd74SJohn Marino /* 3820d5acd74SJohn Marino * One more try in cache; if it was not found by name, 3830d5acd74SJohn Marino * it might still be found by absolute path. 3840d5acd74SJohn Marino */ 3850d5acd74SJohn Marino RLOCK(NLERR); 3860d5acd74SJohn Marino SLIST_FOREACH(np, &cache, list) { 3870d5acd74SJohn Marino if ((np->path != NULL) && (strcmp(np->path, path) == 0)) { 3880d5acd74SJohn Marino np->refcount++; 3890d5acd74SJohn Marino UNLOCK; 3900d5acd74SJohn Marino return (np->catd); 3910d5acd74SJohn Marino } 3920d5acd74SJohn Marino } 3930d5acd74SJohn Marino UNLOCK; 3940d5acd74SJohn Marino 3950d5acd74SJohn Marino if ((fd = _open(path, O_RDONLY | O_CLOEXEC)) == -1) { 3960d5acd74SJohn Marino SAVEFAIL(name, lang, errno); 3970d5acd74SJohn Marino NLRETERR(errno); 3980d5acd74SJohn Marino } 3990d5acd74SJohn Marino 4000d5acd74SJohn Marino if (_fstat(fd, &st) != 0) { 4010d5acd74SJohn Marino _close(fd); 4020d5acd74SJohn Marino SAVEFAIL(name, lang, EFTYPE); 4030d5acd74SJohn Marino NLRETERR(EFTYPE); 4040d5acd74SJohn Marino } 4050d5acd74SJohn Marino 4060d5acd74SJohn Marino /* 4070d5acd74SJohn Marino * If the file size cannot be held in size_t we cannot mmap() 4080d5acd74SJohn Marino * it to the memory. Probably, this will not be a problem given 4090d5acd74SJohn Marino * that catalog files are usually small. 4100d5acd74SJohn Marino */ 4110d5acd74SJohn Marino if (st.st_size > SIZE_T_MAX) { 4120d5acd74SJohn Marino _close(fd); 4130d5acd74SJohn Marino SAVEFAIL(name, lang, EFBIG); 4140d5acd74SJohn Marino NLRETERR(EFBIG); 4150d5acd74SJohn Marino } 4160d5acd74SJohn Marino 4170d5acd74SJohn Marino if ((data = mmap(0, (size_t)st.st_size, PROT_READ, 4180d5acd74SJohn Marino MAP_FILE|MAP_SHARED, fd, (off_t)0)) == MAP_FAILED) { 4190d5acd74SJohn Marino int saved_errno = errno; 4200d5acd74SJohn Marino _close(fd); 4210d5acd74SJohn Marino SAVEFAIL(name, lang, saved_errno); 4220d5acd74SJohn Marino NLRETERR(saved_errno); 4230d5acd74SJohn Marino } 4240d5acd74SJohn Marino _close(fd); 4250d5acd74SJohn Marino 4260d5acd74SJohn Marino if (ntohl((u_int32_t)((struct _nls_cat_hdr *)data)->__magic) != 4270d5acd74SJohn Marino _NLS_MAGIC) { 4280d5acd74SJohn Marino munmap(data, (size_t)st.st_size); 4290d5acd74SJohn Marino SAVEFAIL(name, lang, EFTYPE); 4300d5acd74SJohn Marino NLRETERR(EFTYPE); 4310d5acd74SJohn Marino } 4320d5acd74SJohn Marino 4330d5acd74SJohn Marino if ((catd = malloc(sizeof (*catd))) == NULL) { 4340d5acd74SJohn Marino munmap(data, (size_t)st.st_size); 4350d5acd74SJohn Marino SAVEFAIL(name, lang, ENOMEM); 4360d5acd74SJohn Marino NLRETERR(ENOMEM); 4370d5acd74SJohn Marino } 4380d5acd74SJohn Marino 4390d5acd74SJohn Marino catd->__data = data; 4400d5acd74SJohn Marino catd->__size = (int)st.st_size; 4410d5acd74SJohn Marino 4420d5acd74SJohn Marino /* Caching opened catalog */ 4430d5acd74SJohn Marino WLOCK(NLERR); 4440d5acd74SJohn Marino if ((np = malloc(sizeof(struct catentry))) != NULL) { 4450d5acd74SJohn Marino np->name = strdup(name); 4460d5acd74SJohn Marino np->path = strdup(path); 4470d5acd74SJohn Marino np->catd = catd; 4480d5acd74SJohn Marino np->lang = (lang == NULL) ? NULL : strdup(lang); 4490d5acd74SJohn Marino np->refcount = 1; 4500d5acd74SJohn Marino np->caterrno = 0; 4510d5acd74SJohn Marino SLIST_INSERT_HEAD(&cache, np, list); 4520d5acd74SJohn Marino } 4530d5acd74SJohn Marino UNLOCK; 4540d5acd74SJohn Marino return (catd); 4550d5acd74SJohn Marino } 456