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