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

glibc/2.7/locale/loadarchive.c

    1: /* Code to load locale data from the locale archive file.
    2:    Copyright (C) 2002, 2003, 2005 Free Software Foundation, Inc.
    3:    This file is part of the GNU C Library.
    4: 
    5:    The GNU C Library is free software; you can redistribute it and/or
    6:    modify it under the terms of the GNU Lesser General Public
    7:    License as published by the Free Software Foundation; either
    8:    version 2.1 of the License, or (at your option) any later version.
    9: 
   10:    The GNU C Library is distributed in the hope that it will be useful,
   11:    but WITHOUT ANY WARRANTY; without even the implied warranty of
   12:    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
   13:    Lesser General Public License for more details.
   14: 
   15:    You should have received a copy of the GNU Lesser General Public
   16:    License along with the GNU C Library; if not, write to the Free
   17:    Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
   18:    02111-1307 USA.  */
   19: 
   20: #include <locale.h>
   21: #include <stddef.h>
   22: #include <stdlib.h>
   23: #include <stdbool.h>
   24: #include <errno.h>
   25: #include <assert.h>
   26: #include <string.h>
   27: #include <fcntl.h>
   28: #include <unistd.h>
   29: #include <sys/mman.h>
   30: #include <sys/stat.h>
   31: #include <sys/param.h>
   32: 
   33: #include "localeinfo.h"
   34: #include "locarchive.h"
   35: #include <not-cancel.h>
   36: 
   37: /* Define the hash function.  We define the function as static inline.  */
   38: #define compute_hashval static inline compute_hashval
   39: #define hashval_t uint32_t
   40: #include "hashval.h"
   41: #undef compute_hashval
   42: 
   43: 
   44: /* Name of the locale archive file.  */
   45: static const char archfname[] = LOCALEDIR "/locale-archive";
   46: 
   47: /* Size of initial mapping window, optimal if large enough to
   48:    cover the header plus the initial locale.  */
   49: #define ARCHIVE_MAPPING_WINDOW  (2 * 1024 * 1024)
   50: 
   51: #ifndef MAP_COPY
   52: /* This is not quite as good as MAP_COPY since unexamined pages
   53:    can change out from under us and give us inconsistent data.
   54:    But we rely on the user not to diddle the system's live archive.
   55:    Even though we only ever use PROT_READ, using MAP_SHARED would
   56:    not give the system sufficient freedom to e.g. let the on disk
   57:    file go away because it doesn't know we won't call mprotect later.  */
   58: # define MAP_COPY MAP_PRIVATE
   59: #endif
   60: #ifndef MAP_FILE
   61:  /* Some systems do not have this flag; it is superfluous.  */
   62: # define MAP_FILE 0
   63: #endif
   64: 
   65: /* Record of contiguous pages already mapped from the locale archive.  */
   66: struct archmapped
   67: {
   68:   void *ptr;
   69:   uint32_t from;
   70:   uint32_t len;
   71:   struct archmapped *next;
   72: };
   73: static struct archmapped *archmapped;
   74: 
   75: /* This describes the mapping at the beginning of the file that contains
   76:    the header data.  There could be data in the following partial page,
   77:    so this is searched like any other.  Once the archive has been used,
   78:    ARCHMAPPED points to this; if mapping the archive header failed,
   79:    then headmap.ptr is null.  */
   80: static struct archmapped headmap;
   81: static struct stat64 archive_stat; /* stat of archive when header mapped.  */
   82: 
   83: /* Record of locales that we have already loaded from the archive.  */
   84: struct locale_in_archive
   85: {
   86:   struct locale_in_archive *next;
   87:   char *name;
   88:   struct locale_data *data[__LC_LAST];
   89: };
   90: static struct locale_in_archive *archloaded;
   91: 
   92: 
   93: /* Local structure and subroutine of _nl_load_archive, see below.  */
   94: struct range
   95: {
   96:   uint32_t from;
   97:   uint32_t len;
   98:   int category;
   99:   void *result;
  100: };
  101: 
  102: static int
  103: rangecmp (const void *p1, const void *p2)
  104: {
  105:   return ((struct range *) p1)->from - ((struct range *) p2)->from;
  106: }
  107: 
  108: 
  109: /* Calculate the amount of space needed for all the tables described
  110:    by the given header.  Note we do not include the empty table space
  111:    that has been preallocated in the file, so our mapping may not be
  112:    large enough if localedef adds data to the file in place.  However,
  113:    doing that would permute the header fields while we are accessing
  114:    them and thus not be safe anyway, so we don't allow for that.  */
  115: static inline off_t
  116: calculate_head_size (const struct locarhead *h)
  117: {
  118:   off_t namehash_end = (h->namehash_offset
  119:                         + h->namehash_size * sizeof (struct namehashent));
  120:   off_t string_end =  h->string_offset + h->string_used;
  121:   off_t locrectab_end = (h->locrectab_offset
  122:                          + h->locrectab_used * sizeof (struct locrecent));
  123:   return MAX (namehash_end, MAX (string_end, locrectab_end));
  124: }
  125: 
  126: 
  127: /* Find the locale *NAMEP in the locale archive, and return the
  128:    internalized data structure for its CATEGORY data.  If this locale has
  129:    already been loaded from the archive, just returns the existing data
  130:    structure.  If successful, sets *NAMEP to point directly into the mapped
  131:    archive string table; that way, the next call can short-circuit strcmp.  */
  132: struct locale_data *
  133: internal_function
  134: _nl_load_locale_from_archive (int category, const char **namep)
  135: {
  136:   const char *name = *namep;
  137:   struct
  138:   {
  139:     void *addr;
  140:     size_t len;
  141:   } results[__LC_LAST];
  142:   struct locale_in_archive *lia;
  143:   struct locarhead *head;
  144:   struct namehashent *namehashtab;
  145:   struct locrecent *locrec;
  146:   struct archmapped *mapped;
  147:   struct archmapped *last;
  148:   unsigned long int hval;
  149:   size_t idx;
  150:   size_t incr;
  151:   struct range ranges[__LC_LAST - 1];
  152:   int nranges;
  153:   int cnt;
  154:   size_t ps = __sysconf (_SC_PAGE_SIZE);
  155:   int fd = -1;
  156: 
  157:   /* Check if we have already loaded this locale from the archive.
  158:      If we previously loaded the locale but found bogons in the data,
  159:      then we will have stored a null pointer to return here.  */
  160:   for (lia = archloaded; lia != NULL; lia = lia->next)
  161:     if (name == lia->name || !strcmp (name, lia->name))
  162:       {
  163:         *namep = lia->name;
  164:         return lia->data[category];
  165:       }
  166: 
  167:   {
  168:     /* If the name contains a codeset, then we normalize the name before
  169:        doing the lookup.  */
  170:     const char *p = strchr (name, '.');
  171:     if (p != NULL && p[1] != '@' && p[1] != '\0')
  172:       {
  173:         const char *rest = __strchrnul (++p, '@');
  174:         const char *normalized_codeset = _nl_normalize_codeset (p, rest - p);
  175:         if (normalized_codeset == NULL)        /* malloc failure */
  176:           return NULL;
  177:         if (strncmp (normalized_codeset, p, rest - p) != 0
  178:             || normalized_codeset[rest - p] != '\0')
  179:           {
  180:             /* There is a normalized codeset name that is different from
  181:                what was specified; reconstruct a new locale name using it.  */
  182:             size_t normlen = strlen (normalized_codeset);
  183:             size_t restlen = strlen (rest) + 1;
  184:             char *newname = alloca (p - name + normlen + restlen);
  185:             memcpy (__mempcpy (__mempcpy (newname, name, p - name),
  186:                                normalized_codeset, normlen),
  187:                     rest, restlen);
  188:             name = newname;
  189:           }
  190:         free ((char *) normalized_codeset);
  191:       }
  192:   }
  193: 
  194:   /* Make sure the archive is loaded.  */
  195:   if (archmapped == NULL)
  196:     {
  197:       void *result;
  198:       size_t headsize, mapsize;
  199: 
  200:       /* We do this early as a sign that we have tried to open the archive.
  201:          If headmap.ptr remains null, that's an indication that we tried
  202:          and failed, so we won't try again.  */
  203:       archmapped = &headmap;
  204: 
  205:       /* The archive has never been opened.  */
  206:       fd = open_not_cancel_2 (archfname, O_RDONLY|O_LARGEFILE);
  207:       if (fd < 0)
  208:         /* Cannot open the archive, for whatever reason.  */
  209:         return NULL;
  210: 
  211:       if (__fxstat64 (_STAT_VER, fd, &archive_stat) == -1)
  212:         {
  213:           /* stat failed, very strange.  */
  214:         close_and_out:
  215:           if (fd >= 0)
  216:             close_not_cancel_no_status (fd);
  217:           return NULL;
  218:         }
  219: 
  220: 
  221:       /* Map an initial window probably large enough to cover the header
  222:          and the first locale's data.  With a large address space, we can
  223:          just map the whole file and be sure everything is covered.  */
  224: 
  225:       mapsize = (sizeof (void *) > 4 ? archive_stat.st_size
  226:                  : MIN (archive_stat.st_size, ARCHIVE_MAPPING_WINDOW));
  227: 
  228:       result = __mmap64 (NULL, mapsize, PROT_READ, MAP_FILE|MAP_COPY, fd, 0);
  229:       if (result == MAP_FAILED)
  230:         goto close_and_out;
  231: 
  232:       /* Check whether the file is large enough for the sizes given in
  233:          the header.  Theoretically an archive could be so large that
  234:          just the header fails to fit in our initial mapping window.  */
  235:       headsize = calculate_head_size ((const struct locarhead *) result);
  236:       if (headsize > mapsize)
  237:         {
  238:           (void) __munmap (result, mapsize);
  239:           if (sizeof (void *) > 4 || headsize > archive_stat.st_size)
  240:             /* The file is not big enough for the header.  Bogus.  */
  241:             goto close_and_out;
  242: 
  243:           /* Freakishly long header.  */
  244:           /* XXX could use mremap when available */
  245:           mapsize = (headsize + ps - 1) & ~(ps - 1);
  246:           result = __mmap64 (NULL, mapsize, PROT_READ, MAP_FILE|MAP_COPY,
  247:                              fd, 0);
  248:           if (result == MAP_FAILED)
  249:             goto close_and_out;
  250:         }
  251: 
  252:       if (sizeof (void *) > 4 || mapsize >= archive_stat.st_size)
  253:         {
  254:           /* We've mapped the whole file already, so we can be
  255:              sure we won't need this file descriptor later.  */
  256:           close_not_cancel_no_status (fd);
  257:           fd = -1;
  258:         }
  259: 
  260:       headmap.ptr = result;
  261:       /* headmap.from already initialized to zero.  */
  262:       headmap.len = mapsize;
  263:     }
  264: 
  265:   /* If there is no archive or it cannot be loaded for some reason fail.  */
  266:   if (__builtin_expect (headmap.ptr == NULL, 0))
  267:     goto close_and_out;
  268: 
  269:   /* We have the archive available.  To find the name we first have to
  270:      determine its hash value.  */
  271:   hval = compute_hashval (name, strlen (name));
  272: 
  273:   head = headmap.ptr;
  274:   namehashtab = (struct namehashent *) ((char *) head
  275:                                         + head->namehash_offset);
  276: 
  277:   idx = hval % head->namehash_size;
  278:   incr = 1 + hval % (head->namehash_size - 2);
  279: 
  280:   /* If the name_offset field is zero this means this is a
  281:      deleted entry and therefore no entry can be found.  */
  282:   while (1)
  283:     {
  284:       if (namehashtab[idx].name_offset == 0)
  285:         /* Not found.  */
  286:         goto close_and_out;
  287: 
  288:       if (namehashtab[idx].hashval == hval
  289:           && strcmp (name, headmap.ptr + namehashtab[idx].name_offset) == 0)
  290:         /* Found the entry.  */
  291:         break;
  292: 
  293:       idx += incr;
  294:       if (idx >= head->namehash_size)
  295:         idx -= head->namehash_size;
  296:     }
  297: 
  298:   /* We found an entry.  It might be a placeholder for a removed one.  */
  299:   if (namehashtab[idx].locrec_offset == 0)
  300:     goto close_and_out;
  301: 
  302:   locrec = (struct locrecent *) (headmap.ptr + namehashtab[idx].locrec_offset);
  303: 
  304:   if (sizeof (void *) > 4 /* || headmap.len == archive_stat.st_size */)
  305:     {
  306:       /* We already have the whole locale archive mapped in.  */
  307:       assert (headmap.len == archive_stat.st_size);
  308:       for (cnt = 0; cnt < __LC_LAST; ++cnt)
  309:         if (cnt != LC_ALL)
  310:           {
  311:             if (locrec->record[cnt].offset + locrec->record[cnt].len
  312:                 > headmap.len)
  313:               /* The archive locrectab contains bogus offsets.  */
  314:               goto close_and_out;
  315:             results[cnt].addr = headmap.ptr + locrec->record[cnt].offset;
  316:             results[cnt].len = locrec->record[cnt].len;
  317:           }
  318:     }
  319:   else
  320:     {
  321:       /* Get the offsets of the data files and sort them.  */
  322:       for (cnt = nranges = 0; cnt < __LC_LAST; ++cnt)
  323:         if (cnt != LC_ALL)
  324:           {
  325:             ranges[nranges].from = locrec->record[cnt].offset;
  326:             ranges[nranges].len = locrec->record[cnt].len;
  327:             ranges[nranges].category = cnt;
  328:             ranges[nranges].result = NULL;
  329: 
  330:             ++nranges;
  331:           }
  332: 
  333:       qsort (ranges, nranges, sizeof (ranges[0]), rangecmp);
  334: 
  335:       /* The information about mmap'd blocks is kept in a list.
  336:          Skip over the blocks which are before the data we need.  */
  337:       last = mapped = archmapped;
  338:       for (cnt = 0; cnt < nranges; ++cnt)
  339:         {
  340:           int upper;
  341:           size_t from;
  342:           size_t to;
  343:           void *addr;
  344:           struct archmapped *newp;
  345: 
  346:           /* Determine whether the appropriate page is already mapped.  */
  347:           while (mapped != NULL
  348:                  && (mapped->from + mapped->len
  349:                      <= ranges[cnt].from + ranges[cnt].len))
  350:             {
  351:               last = mapped;
  352:               mapped = mapped->next;
  353:             }
  354: 
  355:           /* Do we have a match?  */
  356:           if (mapped != NULL
  357:               && mapped->from <= ranges[cnt].from
  358:               && (ranges[cnt].from + ranges[cnt].len
  359:                   <= mapped->from + mapped->len))
  360:             {
  361:               /* Yep, already loaded.  */
  362:               results[ranges[cnt].category].addr = ((char *) mapped->ptr
  363:                                                     + ranges[cnt].from
  364:                                                     - mapped->from);
  365:               results[ranges[cnt].category].len = ranges[cnt].len;
  366:               continue;
  367:             }
  368: 
  369:           /* Map the range with the locale data from the file.  We will
  370:              try to cover as much of the locale as possible.  I.e., if the
  371:              next category (next as in "next offset") is on the current or
  372:              immediately following page we use it as well.  */
  373:           assert (powerof2 (ps));
  374:           from = ranges[cnt].from & ~(ps - 1);
  375:           upper = cnt;
  376:           do
  377:             {
  378:               to = ranges[upper].from + ranges[upper].len;
  379:               if (to > (size_t) archive_stat.st_size)
  380:                 /* The archive locrectab contains bogus offsets.  */
  381:                 goto close_and_out;
  382:               to = (to + ps - 1) & ~(ps - 1);
  383: 
  384:               /* If a range is already mmaped in, stop.         */
  385:               if (mapped != NULL && ranges[upper].from >= mapped->from)
  386:                 break;
  387: 
  388:               ++upper;
  389:             }
  390:           /* Loop while still in contiguous pages. */
  391:           while (upper < nranges && ranges[upper].from < to + ps);
  392: 
  393:           /* Open the file if it hasn't happened yet.  */
  394:           if (fd == -1)
  395:             {
  396:               struct stat64 st;
  397:               fd = open_not_cancel_2 (archfname, O_RDONLY|O_LARGEFILE);
  398:               if (fd == -1)
  399:                 /* Cannot open the archive, for whatever reason.  */
  400:                 return NULL;
  401:               /* Now verify we think this is really the same archive file
  402:                  we opened before.  If it has been changed we cannot trust
  403:                  the header we read previously.  */
  404:               if (__fxstat64 (_STAT_VER, fd, &st) < 0
  405:                   || st.st_size != archive_stat.st_size
  406:                   || st.st_mtime != archive_stat.st_mtime
  407:                   || st.st_dev != archive_stat.st_dev
  408:                   || st.st_ino != archive_stat.st_ino)
  409:                 goto close_and_out;
  410:             }
  411: 
  412:           /* Map the range from the archive.  */
  413:           addr = __mmap64 (NULL, to - from, PROT_READ, MAP_FILE|MAP_COPY,
  414:                            fd, from);
  415:           if (addr == MAP_FAILED)
  416:             goto close_and_out;
  417: 
  418:           /* Allocate a record for this mapping.  */
  419:           newp = (struct archmapped *) malloc (sizeof (struct archmapped));
  420:           if (newp == NULL)
  421:             {
  422:               (void) __munmap (addr, to - from);
  423:               goto close_and_out;
  424:             }
  425: 
  426:           /* And queue it.  */
  427:           newp->ptr = addr;
  428:           newp->from = from;
  429:           newp->len = to - from;
  430:           assert (last->next == mapped);
  431:           newp->next = mapped;
  432:           last->next = newp;
  433:           last = newp;
  434: 
  435:           /* Determine the load addresses for the category data.  */
  436:           do
  437:             {
  438:               assert (ranges[cnt].from >= from);
  439:               results[ranges[cnt].category].addr = ((char *) addr
  440:                                                     + ranges[cnt].from - from);
  441:               results[ranges[cnt].category].len = ranges[cnt].len;
  442:             }
  443:           while (++cnt < upper);
  444:           --cnt;               /* The 'for' will increase 'cnt' again.  */
  445:         }
  446:     }
  447: 
  448:   /* We don't need the file descriptor any longer.  */
  449:   if (fd >= 0)
  450:     close_not_cancel_no_status (fd);
  451:   fd = -1;
  452: 
  453:   /* We succeeded in mapping all the necessary regions of the archive.
  454:      Now we need the expected data structures to point into the data.  */
  455: 
  456:   lia = malloc (sizeof *lia);
  457:   if (__builtin_expect (lia == NULL, 0))
  458:     return NULL;
  459: 
  460:   lia->name = strdup (*namep);
  461:   if (__builtin_expect (lia->name == NULL, 0))
  462:     {
  463:       free (lia);
  464:       return NULL;
  465:     }
  466: 
  467:   lia->next = archloaded;
  468:   archloaded = lia;
  469: 
  470:   for (cnt = 0; cnt < __LC_LAST; ++cnt)
  471:     if (cnt != LC_ALL)
  472:       {
  473:         lia->data[cnt] = _nl_intern_locale_data (cnt,
  474:                                                  results[cnt].addr,
  475:                                                  results[cnt].len);
  476:         if (__builtin_expect (lia->data[cnt] != NULL, 1))
  477:           {
  478:             /* _nl_intern_locale_data leaves us these fields to initialize.  */
  479:             lia->data[cnt]->alloc = ld_archive;
  480:             lia->data[cnt]->name = lia->name;
  481: 
  482:             /* We do this instead of bumping the count each time we return
  483:                this data because the mappings stay around forever anyway
  484:                and we might as well hold on to a little more memory and not
  485:                have to rebuild it on the next lookup of the same thing.
  486:                If we were to maintain the usage_count normally and let the
  487:                structures be freed, we would have to remove the elements
  488:                from archloaded too.  */
  489:             lia->data[cnt]->usage_count = UNDELETABLE;
  490:           }
  491:       }
  492: 
  493:   *namep = lia->name;
  494:   return lia->data[category];
  495: }
  496: 
  497: void __libc_freeres_fn_section
  498: _nl_archive_subfreeres (void)
  499: {
  500:   struct locale_in_archive *lia;
  501:   struct archmapped *am;
  502: 
  503:   /* Toss out our cached locales.  */
  504:   lia = archloaded;
  505:   while (lia != NULL)
  506:     {
  507:       int category;
  508:       struct locale_in_archive *dead = lia;
  509:       lia = lia->next;
  510: 
  511:       free (dead->name);
  512:       for (category = 0; category < __LC_LAST; ++category)
  513:         if (category != LC_ALL)
  514:           {
  515:             /* _nl_unload_locale just does this free for the archive case.  */
  516:             if (dead->data[category]->private.cleanup)
  517:               (*dead->data[category]->private.cleanup) (dead->data[category]);
  518: 
  519:             free (dead->data[category]);
  520:           }
  521:       free (dead);
  522:     }
  523:   archloaded = NULL;
  524: 
  525:   if (archmapped != NULL)
  526:     {
  527:       /* Now toss all the mapping windows, which we know nothing is using any
  528:          more because we just tossed all the locales that point into them.  */
  529: 
  530:       assert (archmapped == &headmap);
  531:       archmapped = NULL;
  532:       (void) __munmap (headmap.ptr, headmap.len);
  533:       am = headmap.next;
  534:       while (am != NULL)
  535:         {
  536:           struct archmapped *dead = am;
  537:           am = am->next;
  538:           (void) __munmap (dead->ptr, dead->len);
  539:           free (dead);
  540:         }
  541:     }
  542: }
1
Syntax (Markdown)