Changeset View
Changeset View
Standalone View
Standalone View
head/lib/libc/nls/msgcat.c
Show All 37 Lines | |||||
#include "namespace.h" | #include "namespace.h" | ||||
#include <sys/types.h> | #include <sys/types.h> | ||||
#include <sys/stat.h> | #include <sys/stat.h> | ||||
#include <sys/mman.h> | #include <sys/mman.h> | ||||
#include <sys/queue.h> | #include <sys/queue.h> | ||||
#include <arpa/inet.h> /* for ntohl() */ | #include <arpa/inet.h> /* for ntohl() */ | ||||
#include <machine/atomic.h> | |||||
#include <errno.h> | #include <errno.h> | ||||
#include <fcntl.h> | #include <fcntl.h> | ||||
#include <limits.h> | #include <limits.h> | ||||
#include <nl_types.h> | #include <nl_types.h> | ||||
#include <pthread.h> | #include <pthread.h> | ||||
#include <stdio.h> | #include <stdio.h> | ||||
#include <stdlib.h> | #include <stdlib.h> | ||||
Show All 17 Lines | #define WLOCK(fail) { int ret; \ | ||||
errno = ret; \ | errno = ret; \ | ||||
return (fail); \ | return (fail); \ | ||||
}} | }} | ||||
#define UNLOCK { if (__isthreaded) \ | #define UNLOCK { if (__isthreaded) \ | ||||
_pthread_rwlock_unlock(&rwlock); } | _pthread_rwlock_unlock(&rwlock); } | ||||
#define NLERR ((nl_catd) -1) | #define NLERR ((nl_catd) -1) | ||||
#define NLRETERR(errc) { errno = errc; return (NLERR); } | #define NLRETERR(errc) { errno = errc; return (NLERR); } | ||||
#define SAVEFAIL(n, l, e) { WLOCK(NLERR); \ | #define SAVEFAIL(n, l, e) { np = calloc(1, sizeof(struct catentry)); \ | ||||
np = malloc(sizeof(struct catentry)); \ | |||||
if (np != NULL) { \ | if (np != NULL) { \ | ||||
np->name = strdup(n); \ | np->name = strdup(n); \ | ||||
np->path = NULL; \ | |||||
np->catd = NLERR; \ | np->catd = NLERR; \ | ||||
np->refcount = 0; \ | |||||
np->lang = (l == NULL) ? NULL : \ | np->lang = (l == NULL) ? NULL : \ | ||||
strdup(l); \ | strdup(l); \ | ||||
np->caterrno = e; \ | np->caterrno = e; \ | ||||
SLIST_INSERT_HEAD(&cache, np, list); \ | if (np->name == NULL || \ | ||||
} \ | (l != NULL && np->lang == NULL)) { \ | ||||
free(np->name); \ | |||||
free(np->lang); \ | |||||
free(np); \ | |||||
} else { \ | |||||
WLOCK(NLERR); \ | |||||
SLIST_INSERT_HEAD(&cache, np, \ | |||||
list); \ | |||||
UNLOCK; \ | UNLOCK; \ | ||||
} \ | |||||
} \ | |||||
errno = e; \ | errno = e; \ | ||||
} | } | ||||
static nl_catd load_msgcat(const char *, const char *, const char *); | static nl_catd load_msgcat(const char *, const char *, const char *); | ||||
static pthread_rwlock_t rwlock = PTHREAD_RWLOCK_INITIALIZER; | static pthread_rwlock_t rwlock = PTHREAD_RWLOCK_INITIALIZER; | ||||
struct catentry { | struct catentry { | ||||
▲ Show 20 Lines • Show All 47 Lines • ▼ Show 20 Lines | if ((strcmp(np->name, name) == 0) && | ||||
((lang != NULL && np->lang != NULL && | ((lang != NULL && np->lang != NULL && | ||||
strcmp(np->lang, lang) == 0) || (np->lang == lang))) { | strcmp(np->lang, lang) == 0) || (np->lang == lang))) { | ||||
if (np->caterrno != 0) { | if (np->caterrno != 0) { | ||||
/* Found cached failing entry */ | /* Found cached failing entry */ | ||||
UNLOCK; | UNLOCK; | ||||
NLRETERR(np->caterrno); | NLRETERR(np->caterrno); | ||||
} else { | } else { | ||||
/* Found cached successful entry */ | /* Found cached successful entry */ | ||||
np->refcount++; | atomic_add_int(&np->refcount, 1); | ||||
UNLOCK; | UNLOCK; | ||||
return (np->catd); | return (np->catd); | ||||
} | } | ||||
} | } | ||||
} | } | ||||
UNLOCK; | UNLOCK; | ||||
/* is it absolute path ? if yes, load immediately */ | /* is it absolute path ? if yes, load immediately */ | ||||
▲ Show 20 Lines • Show All 186 Lines • ▼ Show 20 Lines | if (catd == NULL || catd == NLERR) { | ||||
errno = EBADF; | errno = EBADF; | ||||
return (-1); | return (-1); | ||||
} | } | ||||
/* Remove from cache if not referenced any more */ | /* Remove from cache if not referenced any more */ | ||||
WLOCK(-1); | WLOCK(-1); | ||||
SLIST_FOREACH(np, &cache, list) { | SLIST_FOREACH(np, &cache, list) { | ||||
if (catd == np->catd) { | if (catd == np->catd) { | ||||
np->refcount--; | if (atomic_fetchadd_int(&np->refcount, -1) == 1) | ||||
if (np->refcount == 0) | |||||
catfree(np); | catfree(np); | ||||
break; | break; | ||||
} | } | ||||
} | } | ||||
UNLOCK; | UNLOCK; | ||||
return (0); | return (0); | ||||
} | } | ||||
/* | /* | ||||
* Internal support functions | * Internal support functions | ||||
*/ | */ | ||||
static nl_catd | static nl_catd | ||||
load_msgcat(const char *path, const char *name, const char *lang) | load_msgcat(const char *path, const char *name, const char *lang) | ||||
{ | { | ||||
struct stat st; | struct stat st; | ||||
nl_catd catd; | nl_catd catd; | ||||
struct catentry *np; | struct catentry *np; | ||||
void *data; | void *data; | ||||
char *copy_path, *copy_name, *copy_lang; | |||||
int fd; | int fd; | ||||
/* path/name will never be NULL here */ | /* path/name will never be NULL here */ | ||||
/* | /* | ||||
* One more try in cache; if it was not found by name, | * One more try in cache; if it was not found by name, | ||||
* it might still be found by absolute path. | * it might still be found by absolute path. | ||||
*/ | */ | ||||
RLOCK(NLERR); | RLOCK(NLERR); | ||||
SLIST_FOREACH(np, &cache, list) { | SLIST_FOREACH(np, &cache, list) { | ||||
if ((np->path != NULL) && (strcmp(np->path, path) == 0)) { | if ((np->path != NULL) && (strcmp(np->path, path) == 0)) { | ||||
np->refcount++; | atomic_add_int(&np->refcount, 1); | ||||
UNLOCK; | UNLOCK; | ||||
return (np->catd); | return (np->catd); | ||||
} | } | ||||
} | } | ||||
UNLOCK; | UNLOCK; | ||||
if ((fd = _open(path, O_RDONLY | O_CLOEXEC)) == -1) { | if ((fd = _open(path, O_RDONLY | O_CLOEXEC)) == -1) { | ||||
SAVEFAIL(name, lang, errno); | SAVEFAIL(name, lang, errno); | ||||
Show All 28 Lines | load_msgcat(const char *path, const char *name, const char *lang) | ||||
if (ntohl((u_int32_t)((struct _nls_cat_hdr *)data)->__magic) != | if (ntohl((u_int32_t)((struct _nls_cat_hdr *)data)->__magic) != | ||||
_NLS_MAGIC) { | _NLS_MAGIC) { | ||||
munmap(data, (size_t)st.st_size); | munmap(data, (size_t)st.st_size); | ||||
SAVEFAIL(name, lang, EFTYPE); | SAVEFAIL(name, lang, EFTYPE); | ||||
NLRETERR(EFTYPE); | NLRETERR(EFTYPE); | ||||
} | } | ||||
if ((catd = malloc(sizeof (*catd))) == NULL) { | copy_name = strdup(name); | ||||
copy_path = strdup(path); | |||||
copy_lang = (lang == NULL) ? NULL : strdup(lang); | |||||
catd = malloc(sizeof (*catd)); | |||||
np = calloc(1, sizeof(struct catentry)); | |||||
if (copy_name == NULL || copy_path == NULL || | |||||
(lang != NULL && copy_lang == NULL) || | |||||
catd == NULL || np == NULL) { | |||||
free(copy_name); | |||||
free(copy_path); | |||||
free(copy_lang); | |||||
free(catd); | |||||
free(np); | |||||
munmap(data, (size_t)st.st_size); | munmap(data, (size_t)st.st_size); | ||||
SAVEFAIL(name, lang, ENOMEM); | SAVEFAIL(name, lang, ENOMEM); | ||||
NLRETERR(ENOMEM); | NLRETERR(ENOMEM); | ||||
} | } | ||||
catd->__data = data; | catd->__data = data; | ||||
catd->__size = (int)st.st_size; | catd->__size = (int)st.st_size; | ||||
/* Caching opened catalog */ | /* Caching opened catalog */ | ||||
WLOCK(NLERR); | np->name = copy_name; | ||||
if ((np = malloc(sizeof(struct catentry))) != NULL) { | np->path = copy_path; | ||||
np->name = strdup(name); | |||||
np->path = strdup(path); | |||||
np->catd = catd; | np->catd = catd; | ||||
np->lang = (lang == NULL) ? NULL : strdup(lang); | np->lang = copy_lang; | ||||
np->refcount = 1; | atomic_store_int(&np->refcount, 1); | ||||
np->caterrno = 0; | WLOCK(NLERR); | ||||
SLIST_INSERT_HEAD(&cache, np, list); | SLIST_INSERT_HEAD(&cache, np, list); | ||||
} | |||||
UNLOCK; | UNLOCK; | ||||
return (catd); | return (catd); | ||||
} | } |