Hurd: fix mode type for openat
[glibc.git] / elf / cache.c
blobdb8b9fa2fa6a939334a31439ae65c2a45f423adb
1 /* Copyright (C) 1999-2003,2005,2006,2007,2011 Free Software Foundation, Inc.
2 This file is part of the GNU C Library.
3 Contributed by Andreas Jaeger <aj@suse.de>, 1999.
5 This program is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published
7 by the Free Software Foundation; version 2 of the License, or
8 (at your option) any later version.
10 This program 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
13 GNU General Public License for more details.
15 You should have received a copy of the GNU General Public License
16 along with this program; if not, see <http://www.gnu.org/licenses/>. */
18 #include <errno.h>
19 #include <error.h>
20 #include <dirent.h>
21 #include <inttypes.h>
22 #include <libgen.h>
23 #include <libintl.h>
24 #include <stdio.h>
25 #include <stdlib.h>
26 #include <string.h>
27 #include <unistd.h>
28 #include <sys/fcntl.h>
29 #include <sys/mman.h>
30 #include <sys/stat.h>
31 #include <sys/types.h>
33 #include <ldconfig.h>
34 #include <dl-cache.h>
36 struct cache_entry
38 char *lib; /* Library name. */
39 char *path; /* Path to find library. */
40 int flags; /* Flags to indicate kind of library. */
41 unsigned int osversion; /* Required OS version. */
42 uint64_t hwcap; /* Important hardware capabilities. */
43 int bits_hwcap; /* Number of bits set in hwcap. */
44 struct cache_entry *next; /* Next entry in list. */
47 /* List of all cache entries. */
48 static struct cache_entry *entries;
50 static const char *flag_descr[] =
51 { "libc4", "ELF", "libc5", "libc6"};
53 /* Print a single entry. */
54 static void
55 print_entry (const char *lib, int flag, unsigned int osversion,
56 uint64_t hwcap, const char *key)
58 printf ("\t%s (", lib);
59 switch (flag & FLAG_TYPE_MASK)
61 case FLAG_LIBC4:
62 case FLAG_ELF:
63 case FLAG_ELF_LIBC5:
64 case FLAG_ELF_LIBC6:
65 fputs (flag_descr[flag & FLAG_TYPE_MASK], stdout);
66 break;
67 default:
68 fputs (_("unknown"), stdout);
69 break;
71 switch (flag & FLAG_REQUIRED_MASK)
73 case FLAG_SPARC_LIB64:
74 fputs (",64bit", stdout);
75 break;
76 case FLAG_IA64_LIB64:
77 fputs (",IA-64", stdout);
78 break;
79 case FLAG_X8664_LIB64:
80 fputs (",x86-64", stdout);
81 break;
82 case FLAG_S390_LIB64:
83 fputs (",64bit", stdout);
84 break;
85 case FLAG_POWERPC_LIB64:
86 fputs (",64bit", stdout);
87 break;
88 case FLAG_MIPS64_LIBN32:
89 fputs (",N32", stdout);
90 break;
91 case FLAG_MIPS64_LIBN64:
92 fputs (",64bit", stdout);
93 break;
94 case FLAG_X8664_LIBX32:
95 fputs (",x32", stdout);
96 break;
97 case 0:
98 break;
99 default:
100 printf (",%d", flag & FLAG_REQUIRED_MASK);
101 break;
103 if (hwcap != 0)
104 printf (", hwcap: %#.16" PRIx64, hwcap);
105 if (osversion != 0)
107 static const char *const abi_tag_os[] =
109 [0] = "Linux",
110 [1] = "Hurd",
111 [2] = "Solaris",
112 [3] = "FreeBSD",
113 [4] = "kNetBSD",
114 [5] = "Syllable",
115 [6] = N_("Unknown OS")
117 #define MAXTAG (sizeof abi_tag_os / sizeof abi_tag_os[0] - 1)
118 unsigned int os = osversion >> 24;
120 printf (_(", OS ABI: %s %d.%d.%d"),
121 _(abi_tag_os[os > MAXTAG ? MAXTAG : os]),
122 (osversion >> 16) & 0xff,
123 (osversion >> 8) & 0xff,
124 osversion & 0xff);
126 printf (") => %s\n", key);
130 /* Print the whole cache file, if a file contains the new cache format
131 hidden in the old one, print the contents of the new format. */
132 void
133 print_cache (const char *cache_name)
135 int fd = open (cache_name, O_RDONLY);
136 if (fd < 0)
137 error (EXIT_FAILURE, errno, _("Can't open cache file %s\n"), cache_name);
139 struct stat64 st;
140 if (fstat64 (fd, &st) < 0
141 /* No need to map the file if it is empty. */
142 || st.st_size == 0)
144 close (fd);
145 return;
148 struct cache_file *cache
149 = mmap (NULL, st.st_size, PROT_READ, MAP_PRIVATE, fd, 0);
150 if (cache == MAP_FAILED)
151 error (EXIT_FAILURE, errno, _("mmap of cache file failed.\n"));
153 size_t cache_size = st.st_size;
154 if (cache_size < sizeof (struct cache_file))
155 error (EXIT_FAILURE, 0, _("File is not a cache file.\n"));
157 struct cache_file_new *cache_new = NULL;
158 const char *cache_data;
159 int format = 0;
161 if (memcmp (cache->magic, CACHEMAGIC, sizeof CACHEMAGIC - 1))
163 /* This can only be the new format without the old one. */
164 cache_new = (struct cache_file_new *) cache;
166 if (memcmp (cache_new->magic, CACHEMAGIC_NEW, sizeof CACHEMAGIC_NEW - 1)
167 || memcmp (cache_new->version, CACHE_VERSION,
168 sizeof CACHE_VERSION - 1))
169 error (EXIT_FAILURE, 0, _("File is not a cache file.\n"));
170 format = 1;
171 /* This is where the strings start. */
172 cache_data = (const char *) cache_new;
174 else
176 size_t offset = ALIGN_CACHE (sizeof (struct cache_file)
177 + (cache->nlibs
178 * sizeof (struct file_entry)));
179 /* This is where the strings start. */
180 cache_data = (const char *) &cache->libs[cache->nlibs];
182 /* Check for a new cache embedded in the old format. */
183 if (cache_size >
184 (offset + sizeof (struct cache_file_new)))
187 cache_new = (struct cache_file_new *) ((void *)cache + offset);
189 if (memcmp (cache_new->magic, CACHEMAGIC_NEW,
190 sizeof CACHEMAGIC_NEW - 1) == 0
191 && memcmp (cache_new->version, CACHE_VERSION,
192 sizeof CACHE_VERSION - 1) == 0)
194 cache_data = (const char *) cache_new;
195 format = 1;
200 if (format == 0)
202 printf (_("%d libs found in cache `%s'\n"), cache->nlibs, cache_name);
204 /* Print everything. */
205 for (unsigned int i = 0; i < cache->nlibs; i++)
206 print_entry (cache_data + cache->libs[i].key,
207 cache->libs[i].flags, 0, 0,
208 cache_data + cache->libs[i].value);
210 else if (format == 1)
212 printf (_("%d libs found in cache `%s'\n"),
213 cache_new->nlibs, cache_name);
215 /* Print everything. */
216 for (unsigned int i = 0; i < cache_new->nlibs; i++)
217 print_entry (cache_data + cache_new->libs[i].key,
218 cache_new->libs[i].flags,
219 cache_new->libs[i].osversion,
220 cache_new->libs[i].hwcap,
221 cache_data + cache_new->libs[i].value);
223 /* Cleanup. */
224 munmap (cache, cache_size);
225 close (fd);
228 /* Initialize cache data structures. */
229 void
230 init_cache (void)
232 entries = NULL;
235 static int
236 compare (const struct cache_entry *e1, const struct cache_entry *e2)
238 /* We need to swap entries here to get the correct sort order. */
239 int res = _dl_cache_libcmp (e2->lib, e1->lib);
240 if (res == 0)
242 if (e1->flags < e2->flags)
243 return 1;
244 else if (e1->flags > e2->flags)
245 return -1;
246 /* Sort by most specific hwcap. */
247 else if (e2->bits_hwcap > e1->bits_hwcap)
248 return 1;
249 else if (e2->bits_hwcap < e1->bits_hwcap)
250 return -1;
251 else if (e2->hwcap > e1->hwcap)
252 return 1;
253 else if (e2->hwcap < e1->hwcap)
254 return -1;
255 if (e2->osversion > e1->osversion)
256 return 1;
257 if (e2->osversion < e1->osversion)
258 return -1;
260 return res;
263 /* Save the contents of the cache. */
264 void
265 save_cache (const char *cache_name)
267 /* The cache entries are sorted already, save them in this order. */
269 /* Count the length of all strings. */
270 /* The old format doesn't contain hwcap entries and doesn't contain
271 libraries in subdirectories with hwcaps entries. Count therefore
272 also all entries with hwcap == 0. */
273 size_t total_strlen = 0;
274 struct cache_entry *entry;
275 /* Number of cache entries. */
276 int cache_entry_count = 0;
277 /* Number of normal cache entries. */
278 int cache_entry_old_count = 0;
280 for (entry = entries; entry != NULL; entry = entry->next)
282 /* Account the final NULs. */
283 total_strlen += strlen (entry->lib) + strlen (entry->path) + 2;
284 ++cache_entry_count;
285 if (entry->hwcap == 0)
286 ++cache_entry_old_count;
289 /* Create the on disk cache structure. */
290 struct cache_file *file_entries = NULL;
291 size_t file_entries_size = 0;
293 if (opt_format != 2)
295 /* struct cache_file_new is 64-bit aligned on some arches while
296 only 32-bit aligned on other arches. Duplicate last old
297 cache entry so that new cache in ld.so.cache can be used by
298 both. */
299 if (opt_format != 0)
300 cache_entry_old_count = (cache_entry_old_count + 1) & ~1;
302 /* And the list of all entries in the old format. */
303 file_entries_size = sizeof (struct cache_file)
304 + cache_entry_old_count * sizeof (struct file_entry);
305 file_entries = xmalloc (file_entries_size);
307 /* Fill in the header. */
308 memset (file_entries, '\0', sizeof (struct cache_file));
309 memcpy (file_entries->magic, CACHEMAGIC, sizeof CACHEMAGIC - 1);
311 file_entries->nlibs = cache_entry_old_count;
314 struct cache_file_new *file_entries_new = NULL;
315 size_t file_entries_new_size = 0;
317 if (opt_format != 0)
319 /* And the list of all entries in the new format. */
320 file_entries_new_size = sizeof (struct cache_file_new)
321 + cache_entry_count * sizeof (struct file_entry_new);
322 file_entries_new = xmalloc (file_entries_new_size);
324 /* Fill in the header. */
325 memset (file_entries_new, '\0', sizeof (struct cache_file_new));
326 memcpy (file_entries_new->magic, CACHEMAGIC_NEW,
327 sizeof CACHEMAGIC_NEW - 1);
328 memcpy (file_entries_new->version, CACHE_VERSION,
329 sizeof CACHE_VERSION - 1);
331 file_entries_new->nlibs = cache_entry_count;
332 file_entries_new->len_strings = total_strlen;
335 /* Pad for alignment of cache_file_new. */
336 size_t pad = ALIGN_CACHE (file_entries_size) - file_entries_size;
338 /* If we have both formats, we hide the new format in the strings
339 table, we have to adjust all string indices for this so that
340 old libc5/glibc 2 dynamic linkers just ignore them. */
341 unsigned int str_offset;
342 if (opt_format != 0)
343 str_offset = file_entries_new_size;
344 else
345 str_offset = 0;
347 /* An array for all strings. */
348 char *strings = xmalloc (total_strlen);
349 char *str = strings;
350 int idx_old;
351 int idx_new;
353 for (idx_old = 0, idx_new = 0, entry = entries; entry != NULL;
354 entry = entry->next, ++idx_new)
356 /* First the library. */
357 if (opt_format != 2 && entry->hwcap == 0)
359 file_entries->libs[idx_old].flags = entry->flags;
360 /* XXX: Actually we can optimize here and remove duplicates. */
361 file_entries->libs[idx_old].key = str_offset + pad;
363 if (opt_format != 0)
365 /* We could subtract file_entries_new_size from str_offset -
366 not doing so makes the code easier, the string table
367 always begins at the beginning of the new cache
368 struct. */
369 file_entries_new->libs[idx_new].flags = entry->flags;
370 file_entries_new->libs[idx_new].osversion = entry->osversion;
371 file_entries_new->libs[idx_new].hwcap = entry->hwcap;
372 file_entries_new->libs[idx_new].key = str_offset;
375 size_t len = strlen (entry->lib) + 1;
376 str = mempcpy (str, entry->lib, len);
377 str_offset += len;
378 /* Then the path. */
379 if (opt_format != 2 && entry->hwcap == 0)
380 file_entries->libs[idx_old].value = str_offset + pad;
381 if (opt_format != 0)
382 file_entries_new->libs[idx_new].value = str_offset;
383 len = strlen (entry->path) + 1;
384 str = mempcpy (str, entry->path, len);
385 str_offset += len;
386 /* Ignore entries with hwcap for old format. */
387 if (entry->hwcap == 0)
388 ++idx_old;
391 /* Duplicate last old cache entry if needed. */
392 if (opt_format != 2
393 && idx_old < cache_entry_old_count)
394 file_entries->libs[idx_old] = file_entries->libs[idx_old - 1];
396 /* Write out the cache. */
398 /* Write cache first to a temporary file and rename it later. */
399 char *temp_name = xmalloc (strlen (cache_name) + 2);
400 sprintf (temp_name, "%s~", cache_name);
402 /* Create file. */
403 int fd = open (temp_name, O_CREAT|O_WRONLY|O_TRUNC|O_NOFOLLOW,
404 S_IRUSR|S_IWUSR);
405 if (fd < 0)
406 error (EXIT_FAILURE, errno, _("Can't create temporary cache file %s"),
407 temp_name);
409 /* Write contents. */
410 if (opt_format != 2)
412 if (write (fd, file_entries, file_entries_size)
413 != (ssize_t) file_entries_size)
414 error (EXIT_FAILURE, errno, _("Writing of cache data failed"));
416 if (opt_format != 0)
418 /* Align cache. */
419 if (opt_format != 2)
421 char zero[pad];
422 memset (zero, '\0', pad);
423 if (write (fd, zero, pad) != (ssize_t) pad)
424 error (EXIT_FAILURE, errno, _("Writing of cache data failed"));
426 if (write (fd, file_entries_new, file_entries_new_size)
427 != (ssize_t) file_entries_new_size)
428 error (EXIT_FAILURE, errno, _("Writing of cache data failed"));
431 if (write (fd, strings, total_strlen) != (ssize_t) total_strlen
432 || close (fd))
433 error (EXIT_FAILURE, errno, _("Writing of cache data failed"));
435 /* Make sure user can always read cache file */
436 if (chmod (temp_name, S_IROTH|S_IRGRP|S_IRUSR|S_IWUSR))
437 error (EXIT_FAILURE, errno,
438 _("Changing access rights of %s to %#o failed"), temp_name,
439 S_IROTH|S_IRGRP|S_IRUSR|S_IWUSR);
441 /* Move temporary to its final location. */
442 if (rename (temp_name, cache_name))
443 error (EXIT_FAILURE, errno, _("Renaming of %s to %s failed"), temp_name,
444 cache_name);
446 /* Free all allocated memory. */
447 free (file_entries_new);
448 free (file_entries);
449 free (strings);
451 while (entries)
453 entry = entries;
454 entries = entries->next;
455 free (entry);
460 /* Add one library to the cache. */
461 void
462 add_to_cache (const char *path, const char *lib, int flags,
463 unsigned int osversion, uint64_t hwcap)
465 size_t liblen = strlen (lib) + 1;
466 size_t len = liblen + strlen (path) + 1;
467 struct cache_entry *new_entry
468 = xmalloc (sizeof (struct cache_entry) + liblen + len);
470 new_entry->lib = memcpy ((char *) (new_entry + 1), lib, liblen);
471 new_entry->path = new_entry->lib + liblen;
472 snprintf (new_entry->path, len, "%s/%s", path, lib);
473 new_entry->flags = flags;
474 new_entry->osversion = osversion;
475 new_entry->hwcap = hwcap;
476 new_entry->bits_hwcap = 0;
478 /* Count the number of bits set in the masked value. */
479 for (size_t i = 0;
480 (~((1ULL << i) - 1) & hwcap) != 0 && i < 8 * sizeof (hwcap); ++i)
481 if ((hwcap & (1ULL << i)) != 0)
482 ++new_entry->bits_hwcap;
485 /* Keep the list sorted - search for right place to insert. */
486 struct cache_entry *ptr = entries;
487 struct cache_entry *prev = entries;
488 while (ptr != NULL)
490 if (compare (ptr, new_entry) > 0)
491 break;
492 prev = ptr;
493 ptr = ptr->next;
495 /* Is this the first entry? */
496 if (ptr == entries)
498 new_entry->next = entries;
499 entries = new_entry;
501 else
503 new_entry->next = prev->next;
504 prev->next = new_entry;
509 /* Auxiliary cache. */
511 struct aux_cache_entry_id
513 uint64_t ino;
514 uint64_t ctime;
515 uint64_t size;
516 uint64_t dev;
519 struct aux_cache_entry
521 struct aux_cache_entry_id id;
522 int flags;
523 unsigned int osversion;
524 int used;
525 char *soname;
526 struct aux_cache_entry *next;
529 #define AUX_CACHEMAGIC "glibc-ld.so.auxcache-1.0"
531 struct aux_cache_file_entry
533 struct aux_cache_entry_id id; /* Unique id of entry. */
534 int32_t flags; /* This is 1 for an ELF library. */
535 uint32_t soname; /* String table indice. */
536 uint32_t osversion; /* Required OS version. */
537 int32_t pad;
540 /* ldconfig maintains an auxiliary cache file that allows
541 only reading those libraries that have changed since the last iteration.
542 For this for each library some information is cached in the auxiliary
543 cache. */
544 struct aux_cache_file
546 char magic[sizeof AUX_CACHEMAGIC - 1];
547 uint32_t nlibs; /* Number of entries. */
548 uint32_t len_strings; /* Size of string table. */
549 struct aux_cache_file_entry libs[0]; /* Entries describing libraries. */
550 /* After this the string table of size len_strings is found. */
553 static const unsigned int primes[] =
555 1021, 2039, 4093, 8191, 16381, 32749, 65521, 131071, 262139,
556 524287, 1048573, 2097143, 4194301, 8388593, 16777213, 33554393,
557 67108859, 134217689, 268435399, 536870909, 1073741789, 2147483647
560 static size_t aux_hash_size;
561 static struct aux_cache_entry **aux_hash;
563 /* Simplistic hash function for aux_cache_entry_id. */
564 static unsigned int
565 aux_cache_entry_id_hash (struct aux_cache_entry_id *id)
567 uint64_t ret = ((id->ino * 11 + id->ctime) * 11 + id->size) * 11 + id->dev;
568 return ret ^ (ret >> 32);
571 static size_t nextprime (size_t x)
573 for (unsigned int i = 0; i < sizeof (primes) / sizeof (primes[0]); ++i)
574 if (primes[i] >= x)
575 return primes[i];
576 return x;
579 void
580 init_aux_cache (void)
582 aux_hash_size = primes[3];
583 aux_hash = xcalloc (aux_hash_size, sizeof (struct aux_cache_entry *));
587 search_aux_cache (struct stat64 *stat_buf, int *flags,
588 unsigned int *osversion, char **soname)
590 struct aux_cache_entry_id id;
591 id.ino = (uint64_t) stat_buf->st_ino;
592 id.ctime = (uint64_t) stat_buf->st_ctime;
593 id.size = (uint64_t) stat_buf->st_size;
594 id.dev = (uint64_t) stat_buf->st_dev;
596 unsigned int hash = aux_cache_entry_id_hash (&id);
597 struct aux_cache_entry *entry;
598 for (entry = aux_hash[hash % aux_hash_size]; entry; entry = entry->next)
599 if (id.ino == entry->id.ino
600 && id.ctime == entry->id.ctime
601 && id.size == entry->id.size
602 && id.dev == entry->id.dev)
604 *flags = entry->flags;
605 *osversion = entry->osversion;
606 if (entry->soname != NULL)
607 *soname = xstrdup (entry->soname);
608 else
609 *soname = NULL;
610 entry->used = 1;
611 return 1;
614 return 0;
617 static void
618 insert_to_aux_cache (struct aux_cache_entry_id *id, int flags,
619 unsigned int osversion, const char *soname, int used)
621 size_t hash = aux_cache_entry_id_hash (id) % aux_hash_size;
622 struct aux_cache_entry *entry;
623 for (entry = aux_hash[hash]; entry; entry = entry->next)
624 if (id->ino == entry->id.ino
625 && id->ctime == entry->id.ctime
626 && id->size == entry->id.size
627 && id->dev == entry->id.dev)
628 abort ();
630 size_t len = soname ? strlen (soname) + 1 : 0;
631 entry = xmalloc (sizeof (struct aux_cache_entry) + len);
632 entry->id = *id;
633 entry->flags = flags;
634 entry->osversion = osversion;
635 entry->used = used;
636 if (soname != NULL)
637 entry->soname = memcpy ((char *) (entry + 1), soname, len);
638 else
639 entry->soname = NULL;
640 entry->next = aux_hash[hash];
641 aux_hash[hash] = entry;
644 void
645 add_to_aux_cache (struct stat64 *stat_buf, int flags,
646 unsigned int osversion, const char *soname)
648 struct aux_cache_entry_id id;
649 id.ino = (uint64_t) stat_buf->st_ino;
650 id.ctime = (uint64_t) stat_buf->st_ctime;
651 id.size = (uint64_t) stat_buf->st_size;
652 id.dev = (uint64_t) stat_buf->st_dev;
653 insert_to_aux_cache (&id, flags, osversion, soname, 1);
656 /* Load auxiliary cache to search for unchanged entries. */
657 void
658 load_aux_cache (const char *aux_cache_name)
660 int fd = open (aux_cache_name, O_RDONLY);
661 if (fd < 0)
663 init_aux_cache ();
664 return;
667 struct stat64 st;
668 if (fstat64 (fd, &st) < 0 || st.st_size < sizeof (struct aux_cache_file))
670 close (fd);
671 init_aux_cache ();
672 return;
675 size_t aux_cache_size = st.st_size;
676 struct aux_cache_file *aux_cache
677 = mmap (NULL, aux_cache_size, PROT_READ, MAP_PRIVATE, fd, 0);
678 if (aux_cache == MAP_FAILED
679 || aux_cache_size < sizeof (struct aux_cache_file)
680 || memcmp (aux_cache->magic, AUX_CACHEMAGIC, sizeof AUX_CACHEMAGIC - 1)
681 || aux_cache->nlibs >= aux_cache_size)
683 close (fd);
684 init_aux_cache ();
685 return;
688 aux_hash_size = nextprime (aux_cache->nlibs);
689 aux_hash = xcalloc (aux_hash_size, sizeof (struct aux_cache_entry *));
691 const char *aux_cache_data
692 = (const char *) &aux_cache->libs[aux_cache->nlibs];
693 for (unsigned int i = 0; i < aux_cache->nlibs; ++i)
694 insert_to_aux_cache (&aux_cache->libs[i].id,
695 aux_cache->libs[i].flags,
696 aux_cache->libs[i].osversion,
697 aux_cache->libs[i].soname == 0
698 ? NULL : aux_cache_data + aux_cache->libs[i].soname,
701 munmap (aux_cache, aux_cache_size);
702 close (fd);
705 /* Save the contents of the auxiliary cache. */
706 void
707 save_aux_cache (const char *aux_cache_name)
709 /* Count the length of all sonames. We start with empty string. */
710 size_t total_strlen = 1;
711 /* Number of cache entries. */
712 int cache_entry_count = 0;
714 for (size_t i = 0; i < aux_hash_size; ++i)
715 for (struct aux_cache_entry *entry = aux_hash[i];
716 entry != NULL; entry = entry->next)
717 if (entry->used)
719 ++cache_entry_count;
720 if (entry->soname != NULL)
721 total_strlen += strlen (entry->soname) + 1;
724 /* Auxiliary cache. */
725 size_t file_entries_size
726 = sizeof (struct aux_cache_file)
727 + cache_entry_count * sizeof (struct aux_cache_file_entry);
728 struct aux_cache_file *file_entries
729 = xmalloc (file_entries_size + total_strlen);
731 /* Fill in the header of the auxiliary cache. */
732 memset (file_entries, '\0', sizeof (struct aux_cache_file));
733 memcpy (file_entries->magic, AUX_CACHEMAGIC, sizeof AUX_CACHEMAGIC - 1);
735 file_entries->nlibs = cache_entry_count;
736 file_entries->len_strings = total_strlen;
738 /* Initial String offset for auxiliary cache is always after the
739 special empty string. */
740 unsigned int str_offset = 1;
742 /* An array for all strings. */
743 char *str = (char *) file_entries + file_entries_size;
744 *str++ = '\0';
746 size_t idx = 0;
747 for (size_t i = 0; i < aux_hash_size; ++i)
748 for (struct aux_cache_entry *entry = aux_hash[i];
749 entry != NULL; entry = entry->next)
750 if (entry->used)
752 file_entries->libs[idx].id = entry->id;
753 file_entries->libs[idx].flags = entry->flags;
754 if (entry->soname == NULL)
755 file_entries->libs[idx].soname = 0;
756 else
758 file_entries->libs[idx].soname = str_offset;
760 size_t len = strlen (entry->soname) + 1;
761 str = mempcpy (str, entry->soname, len);
762 str_offset += len;
764 file_entries->libs[idx].osversion = entry->osversion;
765 file_entries->libs[idx++].pad = 0;
768 /* Write out auxiliary cache file. */
769 /* Write auxiliary cache first to a temporary file and rename it later. */
771 char *temp_name = xmalloc (strlen (aux_cache_name) + 2);
772 sprintf (temp_name, "%s~", aux_cache_name);
774 /* Check that directory exists and create if needed. */
775 char *dir = strdupa (aux_cache_name);
776 dir = dirname (dir);
778 struct stat64 st;
779 if (stat64 (dir, &st) < 0)
781 if (mkdir (dir, 0700) < 0)
782 goto out_fail;
785 /* Create file. */
786 int fd = open (temp_name, O_CREAT|O_WRONLY|O_TRUNC|O_NOFOLLOW,
787 S_IRUSR|S_IWUSR);
788 if (fd < 0)
789 goto out_fail;
791 if (write (fd, file_entries, file_entries_size + total_strlen)
792 != (ssize_t) (file_entries_size + total_strlen)
793 || close (fd))
795 unlink (temp_name);
796 goto out_fail;
799 /* Move temporary to its final location. */
800 if (rename (temp_name, aux_cache_name))
801 unlink (temp_name);
803 out_fail:
804 /* Free allocated memory. */
805 free (temp_name);
806 free (file_entries);