diff options
Diffstat (limited to 'locale/loadlocale.c')
-rw-r--r-- | locale/loadlocale.c | 188 |
1 files changed, 107 insertions, 81 deletions
diff --git a/locale/loadlocale.c b/locale/loadlocale.c index 53962ba..14f3773 100644 --- a/locale/loadlocale.c +++ b/locale/loadlocale.c @@ -60,21 +60,82 @@ static const enum value_type *_nl_value_types[] = }; -void -_nl_load_locale (struct loaded_l10nfile *file, int category) +struct locale_data * +internal_function +_nl_intern_locale_data (int category, const void *data, size_t datasize) { - int fd; - struct + const struct { unsigned int magic; unsigned int nstrings; unsigned int strindex[0]; - } *filedata; + } *const filedata = data; + struct locale_data *newdata; + size_t cnt; + + if (__builtin_expect (datasize < sizeof *filedata, 0) + || __builtin_expect (filedata->magic != LIMAGIC (category), 0)) + { + /* Bad data file. */ + __set_errno (EINVAL); + return NULL; + } + + if (__builtin_expect (filedata->nstrings < _nl_category_num_items[category], + 0) + || (__builtin_expect (sizeof *filedata + + filedata->nstrings * sizeof (unsigned int) + >= datasize, 0))) + { + /* Insufficient data. */ + __set_errno (EINVAL); + return NULL; + } + + newdata = malloc (sizeof *newdata + + filedata->nstrings * sizeof (union locale_data_value)); + if (newdata == NULL) + return NULL; + + newdata->filedata = (void *) filedata; + newdata->filesize = datasize; + newdata->usage_count = 0; + newdata->use_translit = 0; + newdata->nstrings = filedata->nstrings; + for (cnt = 0; cnt < newdata->nstrings; ++cnt) + { + size_t idx = filedata->strindex[cnt]; + if (__builtin_expect (idx > newdata->filesize, 0)) + { + puntdata: + free (newdata); + __set_errno (EINVAL); + return NULL; + } + if (__builtin_expect (_nl_value_types[category][cnt] == word, 0)) + { + if (idx % __alignof__ (u_int32_t) != 0) + goto puntdata; + newdata->values[cnt].word = + *((const u_int32_t *) (newdata->filedata + idx)); + } + else + newdata->values[cnt].string = newdata->filedata + idx; + } + + return newdata; +} + +void +internal_function +_nl_load_locale (struct loaded_l10nfile *file, int category) +{ + int fd; + void *filedata; struct stat64 st; struct locale_data *newdata; int save_err; - int mmaped = 1; - size_t cnt; + int alloc = ld_mapped; file->decided = 1; file->data = NULL; @@ -85,7 +146,11 @@ _nl_load_locale (struct loaded_l10nfile *file, int category) return; if (__builtin_expect (__fxstat64 (_STAT_VER, fd, &st), 0) < 0) - goto puntfd; + { + puntfd: + __close (fd); + return; + } if (__builtin_expect (S_ISDIR (st.st_mode), 0)) { /* LOCALE/LC_foo is a directory; open LOCALE/LC_foo/SYS_LC_foo @@ -122,25 +187,15 @@ _nl_load_locale (struct loaded_l10nfile *file, int category) /* Some systems do not have this flag; it is superfluous. */ # define MAP_FILE 0 # endif -# ifndef MAP_INHERIT - /* Some systems might lack this; they lose. */ -# define MAP_INHERIT 0 -# endif - filedata = (void *) __mmap ((caddr_t) 0, st.st_size, PROT_READ, - MAP_FILE|MAP_COPY|MAP_INHERIT, fd, 0); - if (__builtin_expect ((void *) filedata != MAP_FAILED, 1)) - { - if (__builtin_expect (st.st_size < sizeof (*filedata), 0)) - /* This cannot be a locale data file since it's too small. */ - goto puntfd; - } - else + filedata = __mmap ((caddr_t) 0, st.st_size, + PROT_READ, MAP_FILE|MAP_COPY, fd, 0); + if (__builtin_expect (filedata == MAP_FAILED, 0)) { if (__builtin_expect (errno, ENOSYS) == ENOSYS) { #endif /* _POSIX_MAPPED_FILES */ /* No mmap; allocate a buffer and read from the file. */ - mmaped = 0; + alloc = ld_malloced; filedata = malloc (st.st_size); if (filedata != NULL) { @@ -160,87 +215,58 @@ _nl_load_locale (struct loaded_l10nfile *file, int category) p += nread; to_read -= nread; } + __set_errno (save_err); } - else - goto puntfd; - __set_errno (save_err); #ifdef _POSIX_MAPPED_FILES } - else - goto puntfd; } #endif /* _POSIX_MAPPED_FILES */ - if (__builtin_expect (filedata->magic != LIMAGIC (category), 0)) - /* Bad data file in either byte order. */ + /* We have mapped the data, so we no longer need the descriptor. */ + __close (fd); + + if (__builtin_expect (filedata == NULL, 0)) + /* We failed to map or read the data. */ + return; + + newdata = _nl_intern_locale_data (category, filedata, st.st_size); + if (__builtin_expect (newdata == NULL, 0)) + /* Bad data. */ { - puntmap: #ifdef _POSIX_MAPPED_FILES - __munmap ((caddr_t) filedata, st.st_size); + if (alloc == ld_mapped) + __munmap ((caddr_t) filedata, st.st_size); #endif - puntfd: - __close (fd); return; } - if (__builtin_expect (filedata->nstrings < _nl_category_num_items[category], - 0) - || (__builtin_expect (sizeof *filedata - + filedata->nstrings * sizeof (unsigned int) - >= (size_t) st.st_size, 0))) - { - /* Insufficient data. */ - __set_errno (EINVAL); - goto puntmap; - } - - newdata = malloc (sizeof *newdata - + filedata->nstrings * sizeof (union locale_data_value)); - if (newdata == NULL) - goto puntmap; - + /* _nl_intern_locale_data leaves us these fields to initialize. */ newdata->name = NULL; /* This will be filled if necessary in findlocale.c. */ - newdata->filedata = (void *) filedata; - newdata->filesize = st.st_size; - newdata->mmaped = mmaped; - newdata->usage_count = 0; - newdata->use_translit = 0; - newdata->options = NULL; - newdata->nstrings = filedata->nstrings; - for (cnt = 0; cnt < newdata->nstrings; ++cnt) - { - off_t idx = filedata->strindex[cnt]; - if (__builtin_expect (idx > newdata->filesize, 0)) - { - free (newdata); - __set_errno (EINVAL); - goto puntmap; - } - if (__builtin_expect (_nl_value_types[category][cnt] == word, 0)) - { - assert (idx % __alignof__ (u_int32_t) == 0); - newdata->values[cnt].word = - *((u_int32_t *) (newdata->filedata + idx)); - } - else - newdata->values[cnt].string = newdata->filedata + idx; - } + newdata->alloc = alloc; - __close (fd); file->data = newdata; } void +internal_function _nl_unload_locale (struct locale_data *locale) { + switch (__builtin_expect (locale->alloc, ld_mapped)) + { + case ld_malloced: + free ((void *) locale->filedata); + break; + case ld_mapped: #ifdef _POSIX_MAPPED_FILES - if (__builtin_expect (locale->mmaped, 1)) - __munmap ((caddr_t) locale->filedata, locale->filesize); - else + __munmap ((caddr_t) locale->filedata, locale->filesize); + break; #endif - free ((void *) locale->filedata); + case ld_archive: /* Nothing to do. */ + break; + } + + if (__builtin_expect (locale->alloc, ld_mapped) != ld_archive) + free ((char *) locale->name); - free ((char *) locale->options); - free ((char *) locale->name); free (locale); } |