(linenum→info "unix/slp.c:2238")

glibc/2.7/locale/loadlocale.c

    1: /* Functions to read locale data files.
    2:    Copyright (C) 1996-2004, 2005, 2006 Free Software Foundation, Inc.
    3:    This file is part of the GNU C Library.
    4:    Contributed by Ulrich Drepper <drepper@cygnus.com>, 1996.
    5: 
    6:    The GNU C Library is free software; you can redistribute it and/or
    7:    modify it under the terms of the GNU Lesser General Public
    8:    License as published by the Free Software Foundation; either
    9:    version 2.1 of the License, or (at your option) any later version.
   10: 
   11:    The GNU C Library is distributed in the hope that it will be useful,
   12:    but WITHOUT ANY WARRANTY; without even the implied warranty of
   13:    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
   14:    Lesser General Public License for more details.
   15: 
   16:    You should have received a copy of the GNU Lesser General Public
   17:    License along with the GNU C Library; if not, write to the Free
   18:    Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
   19:    02111-1307 USA.  */
   20: 
   21: #include <assert.h>
   22: #include <errno.h>
   23: #include <fcntl.h>
   24: #include <locale.h>
   25: #include <stdlib.h>
   26: #include <string.h>
   27: #include <unistd.h>
   28: #ifdef _POSIX_MAPPED_FILES
   29: # include <sys/mman.h>
   30: #endif
   31: #include <sys/stat.h>
   32: 
   33: #include <not-cancel.h>
   34: #include "localeinfo.h"
   35: 
   36: 
   37: static const size_t _nl_category_num_items[] =
   38: {
   39: #define DEFINE_CATEGORY(category, category_name, items, a) \
   40:   [category] = _NL_ITEM_INDEX (_NL_NUM_##category),
   41: #include "categories.def"
   42: #undef  DEFINE_CATEGORY
   43: };
   44: 
   45: 
   46: #define NO_PAREN(arg, rest...) arg, ##rest
   47: 
   48: #define DEFINE_CATEGORY(category, category_name, items, a) \
   49: static const enum value_type _nl_value_type_##category[] = { NO_PAREN items };
   50: #define DEFINE_ELEMENT(element, element_name, optstd, type, rest...) \
   51:   [_NL_ITEM_INDEX (element)] = type,
   52: #include "categories.def"
   53: #undef DEFINE_CATEGORY
   54: 
   55: static const enum value_type *const _nl_value_types[] =
   56: {
   57: #define DEFINE_CATEGORY(category, category_name, items, a) \
   58:   [category] = _nl_value_type_##category,
   59: #include "categories.def"
   60: #undef DEFINE_CATEGORY
   61: };
   62: 
   63: 
   64: struct locale_data *
   65: internal_function
   66: _nl_intern_locale_data (int category, const void *data, size_t datasize)
   67: {
   68:   const struct
   69:     {
   70:       unsigned int magic;
   71:       unsigned int nstrings;
   72:       unsigned int strindex[0];
   73:     } *const filedata = data;
   74:   struct locale_data *newdata;
   75:   size_t cnt;
   76: 
   77:   if (__builtin_expect (datasize < sizeof *filedata, 0)
   78:       || __builtin_expect (filedata->magic != LIMAGIC (category), 0))
   79:     {
   80:       /* Bad data file.  */
   81:       __set_errno (EINVAL);
   82:       return NULL;
   83:     }
   84: 
   85:   if (__builtin_expect (filedata->nstrings < _nl_category_num_items[category],
   86:                         0)
   87:       || (__builtin_expect (sizeof *filedata
   88:                             + filedata->nstrings * sizeof (unsigned int)
   89:                             >= datasize, 0)))
   90:     {
   91:       /* Insufficient data.  */
   92:       __set_errno (EINVAL);
   93:       return NULL;
   94:     }
   95: 
   96:   newdata = malloc (sizeof *newdata
   97:                     + filedata->nstrings * sizeof (union locale_data_value));
   98:   if (newdata == NULL)
   99:     return NULL;
  100: 
  101:   newdata->filedata = (void *) filedata;
  102:   newdata->filesize = datasize;
  103:   newdata->private.data = NULL;
  104:   newdata->private.cleanup = NULL;
  105:   newdata->usage_count = 0;
  106:   newdata->use_translit = 0;
  107:   newdata->nstrings = filedata->nstrings;
  108:   for (cnt = 0; cnt < newdata->nstrings; ++cnt)
  109:     {
  110:       size_t idx = filedata->strindex[cnt];
  111:       if (__builtin_expect (idx > (size_t) newdata->filesize, 0))
  112:         {
  113:         puntdata:
  114:           free (newdata);
  115:           __set_errno (EINVAL);
  116:           return NULL;
  117:         }
  118: 
  119:       /* Determine the type.  There is one special case: the LC_CTYPE
  120:          category can have more elements than there are in the
  121:          _nl_value_type_LC_XYZ array.  There are all pointers.  */
  122:       switch (category)
  123:         {
  124: #define CATTEST(cat) \
  125:         case LC_##cat:                                                       \
  126:           assert (cnt < (sizeof (_nl_value_type_LC_##cat)                    \
  127:                          / sizeof (_nl_value_type_LC_##cat[0])));          \
  128:           break
  129:           CATTEST (NUMERIC);
  130:           CATTEST (TIME);
  131:           CATTEST (COLLATE);
  132:           CATTEST (MONETARY);
  133:           CATTEST (MESSAGES);
  134:           CATTEST (PAPER);
  135:           CATTEST (NAME);
  136:           CATTEST (ADDRESS);
  137:           CATTEST (TELEPHONE);
  138:           CATTEST (MEASUREMENT);
  139:           CATTEST (IDENTIFICATION);
  140:         default:
  141:           assert (category == LC_CTYPE);
  142:           break;
  143:         }
  144: 
  145:       if ((category == LC_CTYPE
  146:            && cnt >= (sizeof (_nl_value_type_LC_CTYPE)
  147:                       / sizeof (_nl_value_type_LC_CTYPE[0])))
  148:           || __builtin_expect (_nl_value_types[category][cnt] != word, 1))
  149:         newdata->values[cnt].string = newdata->filedata + idx;
  150:       else
  151:         {
  152:           if (idx % __alignof__ (u_int32_t) != 0)
  153:             goto puntdata;
  154:           newdata->values[cnt].word =
  155:             *((const u_int32_t *) (newdata->filedata + idx));
  156:         }
  157:     }
  158: 
  159:   return newdata;
  160: }
  161: 
  162: void
  163: internal_function
  164: _nl_load_locale (struct loaded_l10nfile *file, int category)
  165: {
  166:   int fd;
  167:   void *filedata;
  168:   struct stat64 st;
  169:   struct locale_data *newdata;
  170:   int save_err;
  171:   int alloc = ld_mapped;
  172: 
  173:   file->decided = 1;
  174:   file->data = NULL;
  175: 
  176:   fd = open_not_cancel_2 (file->filename, O_RDONLY);
  177:   if (__builtin_expect (fd, 0) < 0)
  178:     /* Cannot open the file.  */
  179:     return;
  180: 
  181:   if (__builtin_expect (__fxstat64 (_STAT_VER, fd, &st), 0) < 0)
  182:     {
  183:     puntfd:
  184:       close_not_cancel_no_status (fd);
  185:       return;
  186:     }
  187:   if (__builtin_expect (S_ISDIR (st.st_mode), 0))
  188:     {
  189:       /* LOCALE/LC_foo is a directory; open LOCALE/LC_foo/SYS_LC_foo
  190:            instead.  */
  191:       char *newp;
  192:       size_t filenamelen;
  193: 
  194:       close_not_cancel_no_status (fd);
  195: 
  196:       filenamelen = strlen (file->filename);
  197:       newp = (char *) alloca (filenamelen
  198:                               + 5 + _nl_category_name_sizes[category] + 1);
  199:       __mempcpy (__mempcpy (__mempcpy (newp, file->filename, filenamelen),
  200:                             "/SYS_", 5),
  201:                  _nl_category_names.str + _nl_category_name_idxs[category],
  202:                  _nl_category_name_sizes[category] + 1);
  203: 
  204:       fd = open_not_cancel_2 (newp, O_RDONLY);
  205:       if (__builtin_expect (fd, 0) < 0)
  206:         return;
  207: 
  208:       if (__builtin_expect (__fxstat64 (_STAT_VER, fd, &st), 0) < 0)
  209:         goto puntfd;
  210:     }
  211: 
  212:   /* Map in the file's data.  */
  213:   save_err = errno;
  214: #ifdef _POSIX_MAPPED_FILES
  215: # ifndef MAP_COPY
  216:   /* Linux seems to lack read-only copy-on-write.  */
  217: #  define MAP_COPY MAP_PRIVATE
  218: # endif
  219: # ifndef MAP_FILE
  220:   /* Some systems do not have this flag; it is superfluous.  */
  221: #  define MAP_FILE 0
  222: # endif
  223:   filedata = __mmap ((caddr_t) 0, st.st_size,
  224:                      PROT_READ, MAP_FILE|MAP_COPY, fd, 0);
  225:   if (__builtin_expect (filedata == MAP_FAILED, 0))
  226:     {
  227:       if (__builtin_expect (errno, ENOSYS) == ENOSYS)
  228:         {
  229: #endif  /* _POSIX_MAPPED_FILES */
  230:           /* No mmap; allocate a buffer and read from the file.  */
  231:           alloc = ld_malloced;
  232:           filedata = malloc (st.st_size);
  233:           if (filedata != NULL)
  234:             {
  235:               off_t to_read = st.st_size;
  236:               ssize_t nread;
  237:               char *p = (char *) filedata;
  238:               while (to_read > 0)
  239:                 {
  240:                   nread = read_not_cancel (fd, p, to_read);
  241:                   if (__builtin_expect (nread, 1) <= 0)
  242:                     {
  243:                       free (filedata);
  244:                       if (nread == 0)
  245:                         __set_errno (EINVAL); /* Bizarreness going on.  */
  246:                       goto puntfd;
  247:                     }
  248:                   p += nread;
  249:                   to_read -= nread;
  250:                 }
  251:               __set_errno (save_err);
  252:             }
  253: #ifdef _POSIX_MAPPED_FILES
  254:         }
  255:     }
  256: #endif  /* _POSIX_MAPPED_FILES */
  257: 
  258:   /* We have mapped the data, so we no longer need the descriptor.  */
  259:   close_not_cancel_no_status (fd);
  260: 
  261:   if (__builtin_expect (filedata == NULL, 0))
  262:     /* We failed to map or read the data.  */
  263:     return;
  264: 
  265:   newdata = _nl_intern_locale_data (category, filedata, st.st_size);
  266:   if (__builtin_expect (newdata == NULL, 0))
  267:     /* Bad data.  */
  268:     {
  269: #ifdef _POSIX_MAPPED_FILES
  270:       if (alloc == ld_mapped)
  271:         __munmap ((caddr_t) filedata, st.st_size);
  272: #endif
  273:       return;
  274:     }
  275: 
  276:   /* _nl_intern_locale_data leaves us these fields to initialize.  */
  277:   newdata->name = NULL; /* This will be filled if necessary in findlocale.c. */
  278:   newdata->alloc = alloc;
  279: 
  280:   file->data = newdata;
  281: }
  282: 
  283: void
  284: internal_function
  285: _nl_unload_locale (struct locale_data *locale)
  286: {
  287:   if (locale->private.cleanup)
  288:     (*locale->private.cleanup) (locale);
  289: 
  290:   switch (__builtin_expect (locale->alloc, ld_mapped))
  291:     {
  292:     case ld_malloced:
  293:       free ((void *) locale->filedata);
  294:       break;
  295:     case ld_mapped:
  296: #ifdef _POSIX_MAPPED_FILES
  297:       __munmap ((caddr_t) locale->filedata, locale->filesize);
  298:       break;
  299: #endif
  300:     case ld_archive:            /* Nothing to do.  */
  301:       break;
  302:     }
  303: 
  304:   if (__builtin_expect (locale->alloc, ld_mapped) != ld_archive)
  305:     free ((char *) locale->name);
  306: 
  307:   free (locale);
  308: }
Syntax (Markdown)