* sysdeps/unix/sysv/linux/dl-osinfo.h: Include fcntl.h.
[glibc/pb-stable.git] / locale / loadarchive.c
blobd545f17fb53f230340127ccb3024d76439aca90b
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.
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.
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.
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. */
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>
33 #include "localeinfo.h"
34 #include "locarchive.h"
35 #include <not-cancel.h>
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
44 /* Name of the locale archive file. */
45 static const char archfname[] = LOCALEDIR "/locale-archive";
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)
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
65 /* Record of contiguous pages already mapped from the locale archive. */
66 struct archmapped
68 void *ptr;
69 uint32_t from;
70 uint32_t len;
71 struct archmapped *next;
73 static struct archmapped *archmapped;
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. */
83 /* Record of locales that we have already loaded from the archive. */
84 struct locale_in_archive
86 struct locale_in_archive *next;
87 char *name;
88 struct locale_data *data[__LC_LAST];
90 static struct locale_in_archive *archloaded;
93 /* Local structure and subroutine of _nl_load_archive, see below. */
94 struct range
96 uint32_t from;
97 uint32_t len;
98 int category;
99 void *result;
102 static int
103 rangecmp (const void *p1, const void *p2)
105 return ((struct range *) p1)->from - ((struct range *) p2)->from;
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)
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));
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)
136 const char *name = *namep;
137 struct
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;
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))
163 *namep = lia->name;
164 return lia->data[category];
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')
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')
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;
190 free ((char *) normalized_codeset);
194 /* Make sure the archive is loaded. */
195 if (archmapped == NULL)
197 void *result;
198 size_t headsize, mapsize;
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;
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;
211 if (__fxstat64 (_STAT_VER, fd, &archive_stat) == -1)
213 /* stat failed, very strange. */
214 close_and_out:
215 if (fd >= 0)
216 close_not_cancel_no_status (fd);
217 return NULL;
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. */
225 mapsize = (sizeof (void *) > 4 ? archive_stat.st_size
226 : MIN (archive_stat.st_size, ARCHIVE_MAPPING_WINDOW));
228 result = __mmap64 (NULL, mapsize, PROT_READ, MAP_FILE|MAP_COPY, fd, 0);
229 if (result == MAP_FAILED)
230 goto close_and_out;
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)
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;
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;
252 if (sizeof (void *) > 4 || mapsize >= archive_stat.st_size)
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;
260 headmap.ptr = result;
261 /* headmap.from already initialized to zero. */
262 headmap.len = mapsize;
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;
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));
273 head = headmap.ptr;
274 namehashtab = (struct namehashent *) ((char *) head
275 + head->namehash_offset);
277 idx = hval % head->namehash_size;
278 incr = 1 + hval % (head->namehash_size - 2);
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)
284 if (namehashtab[idx].name_offset == 0)
285 /* Not found. */
286 goto close_and_out;
288 if (namehashtab[idx].hashval == hval
289 && strcmp (name, headmap.ptr + namehashtab[idx].name_offset) == 0)
290 /* Found the entry. */
291 break;
293 idx += incr;
294 if (idx >= head->namehash_size)
295 idx -= head->namehash_size;
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;
302 locrec = (struct locrecent *) (headmap.ptr + namehashtab[idx].locrec_offset);
304 if (sizeof (void *) > 4 /* || headmap.len == archive_stat.st_size */)
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)
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;
319 else
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)
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;
330 ++nranges;
333 qsort (ranges, nranges, sizeof (ranges[0]), rangecmp);
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)
340 int upper;
341 size_t from;
342 size_t to;
343 void *addr;
344 struct archmapped *newp;
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))
351 last = mapped;
352 mapped = mapped->next;
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))
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;
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;
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);
384 /* If a range is already mmaped in, stop. */
385 if (mapped != NULL && ranges[upper].from >= mapped->from)
386 break;
388 ++upper;
390 /* Loop while still in contiguous pages. */
391 while (upper < nranges && ranges[upper].from < to + ps);
393 /* Open the file if it hasn't happened yet. */
394 if (fd == -1)
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;
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;
418 /* Allocate a record for this mapping. */
419 newp = (struct archmapped *) malloc (sizeof (struct archmapped));
420 if (newp == NULL)
422 (void) __munmap (addr, to - from);
423 goto close_and_out;
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;
435 /* Determine the load addresses for the category data. */
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;
443 while (++cnt < upper);
444 --cnt; /* The 'for' will increase 'cnt' again. */
448 /* We don't need the file descriptor any longer. */
449 if (fd >= 0)
450 close_not_cancel_no_status (fd);
451 fd = -1;
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. */
456 lia = malloc (sizeof *lia);
457 if (__builtin_expect (lia == NULL, 0))
458 return NULL;
460 lia->name = strdup (*namep);
461 if (__builtin_expect (lia->name == NULL, 0))
463 free (lia);
464 return NULL;
467 lia->next = archloaded;
468 archloaded = lia;
470 for (cnt = 0; cnt < __LC_LAST; ++cnt)
471 if (cnt != LC_ALL)
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))
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;
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;
493 *namep = lia->name;
494 return lia->data[category];
497 void __libc_freeres_fn_section
498 _nl_archive_subfreeres (void)
500 struct locale_in_archive *lia;
501 struct archmapped *am;
503 /* Toss out our cached locales. */
504 lia = archloaded;
505 while (lia != NULL)
507 int category;
508 struct locale_in_archive *dead = lia;
509 lia = lia->next;
511 free (dead->name);
512 for (category = 0; category < __LC_LAST; ++category)
513 if (category != LC_ALL)
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]);
519 free (dead->data[category]);
521 free (dead);
523 archloaded = NULL;
525 if (archmapped != NULL)
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. */
530 assert (archmapped == &headmap);
531 archmapped = NULL;
532 (void) __munmap (headmap.ptr, headmap.len);
533 am = headmap.next;
534 while (am != NULL)
536 struct archmapped *dead = am;
537 am = am->next;
538 (void) __munmap (dead->ptr, dead->len);
539 free (dead);