Cast to __intptr_t before casting pointer to int64
[glibc.git] / elf / cache.c
blobf5ed370e7858a56128cccaf27ca4b14bcd3ade59
1 /* Copyright (C) 1999-2012 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 FLAG_ARM_LIBHF:
98 fputs (",hard-float", stdout);
99 break;
100 case FLAG_AARCH64_LIB64:
101 fputs (",AArch64", stdout);
102 break;
103 case 0:
104 break;
105 default:
106 printf (",%d", flag & FLAG_REQUIRED_MASK);
107 break;
109 if (hwcap != 0)
110 printf (", hwcap: %#.16" PRIx64, hwcap);
111 if (osversion != 0)
113 static const char *const abi_tag_os[] =
115 [0] = "Linux",
116 [1] = "Hurd",
117 [2] = "Solaris",
118 [3] = "FreeBSD",
119 [4] = "kNetBSD",
120 [5] = "Syllable",
121 [6] = N_("Unknown OS")
123 #define MAXTAG (sizeof abi_tag_os / sizeof abi_tag_os[0] - 1)
124 unsigned int os = osversion >> 24;
126 printf (_(", OS ABI: %s %d.%d.%d"),
127 _(abi_tag_os[os > MAXTAG ? MAXTAG : os]),
128 (osversion >> 16) & 0xff,
129 (osversion >> 8) & 0xff,
130 osversion & 0xff);
132 printf (") => %s\n", key);
136 /* Print the whole cache file, if a file contains the new cache format
137 hidden in the old one, print the contents of the new format. */
138 void
139 print_cache (const char *cache_name)
141 int fd = open (cache_name, O_RDONLY);
142 if (fd < 0)
143 error (EXIT_FAILURE, errno, _("Can't open cache file %s\n"), cache_name);
145 struct stat64 st;
146 if (fstat64 (fd, &st) < 0
147 /* No need to map the file if it is empty. */
148 || st.st_size == 0)
150 close (fd);
151 return;
154 struct cache_file *cache
155 = mmap (NULL, st.st_size, PROT_READ, MAP_PRIVATE, fd, 0);
156 if (cache == MAP_FAILED)
157 error (EXIT_FAILURE, errno, _("mmap of cache file failed.\n"));
159 size_t cache_size = st.st_size;
160 if (cache_size < sizeof (struct cache_file))
161 error (EXIT_FAILURE, 0, _("File is not a cache file.\n"));
163 struct cache_file_new *cache_new = NULL;
164 const char *cache_data;
165 int format = 0;
167 if (memcmp (cache->magic, CACHEMAGIC, sizeof CACHEMAGIC - 1))
169 /* This can only be the new format without the old one. */
170 cache_new = (struct cache_file_new *) cache;
172 if (memcmp (cache_new->magic, CACHEMAGIC_NEW, sizeof CACHEMAGIC_NEW - 1)
173 || memcmp (cache_new->version, CACHE_VERSION,
174 sizeof CACHE_VERSION - 1))
175 error (EXIT_FAILURE, 0, _("File is not a cache file.\n"));
176 format = 1;
177 /* This is where the strings start. */
178 cache_data = (const char *) cache_new;
180 else
182 size_t offset = ALIGN_CACHE (sizeof (struct cache_file)
183 + (cache->nlibs
184 * sizeof (struct file_entry)));
185 /* This is where the strings start. */
186 cache_data = (const char *) &cache->libs[cache->nlibs];
188 /* Check for a new cache embedded in the old format. */
189 if (cache_size >
190 (offset + sizeof (struct cache_file_new)))
193 cache_new = (struct cache_file_new *) ((void *)cache + offset);
195 if (memcmp (cache_new->magic, CACHEMAGIC_NEW,
196 sizeof CACHEMAGIC_NEW - 1) == 0
197 && memcmp (cache_new->version, CACHE_VERSION,
198 sizeof CACHE_VERSION - 1) == 0)
200 cache_data = (const char *) cache_new;
201 format = 1;
206 if (format == 0)
208 printf (_("%d libs found in cache `%s'\n"), cache->nlibs, cache_name);
210 /* Print everything. */
211 for (unsigned int i = 0; i < cache->nlibs; i++)
212 print_entry (cache_data + cache->libs[i].key,
213 cache->libs[i].flags, 0, 0,
214 cache_data + cache->libs[i].value);
216 else if (format == 1)
218 printf (_("%d libs found in cache `%s'\n"),
219 cache_new->nlibs, cache_name);
221 /* Print everything. */
222 for (unsigned int i = 0; i < cache_new->nlibs; i++)
223 print_entry (cache_data + cache_new->libs[i].key,
224 cache_new->libs[i].flags,
225 cache_new->libs[i].osversion,
226 cache_new->libs[i].hwcap,
227 cache_data + cache_new->libs[i].value);
229 /* Cleanup. */
230 munmap (cache, cache_size);
231 close (fd);
234 /* Initialize cache data structures. */
235 void
236 init_cache (void)
238 entries = NULL;
241 static int
242 compare (const struct cache_entry *e1, const struct cache_entry *e2)
244 /* We need to swap entries here to get the correct sort order. */
245 int res = _dl_cache_libcmp (e2->lib, e1->lib);
246 if (res == 0)
248 if (e1->flags < e2->flags)
249 return 1;
250 else if (e1->flags > e2->flags)
251 return -1;
252 /* Sort by most specific hwcap. */
253 else if (e2->bits_hwcap > e1->bits_hwcap)
254 return 1;
255 else if (e2->bits_hwcap < e1->bits_hwcap)
256 return -1;
257 else if (e2->hwcap > e1->hwcap)
258 return 1;
259 else if (e2->hwcap < e1->hwcap)
260 return -1;
261 if (e2->osversion > e1->osversion)
262 return 1;
263 if (e2->osversion < e1->osversion)
264 return -1;
266 return res;
269 /* Save the contents of the cache. */
270 void
271 save_cache (const char *cache_name)
273 /* The cache entries are sorted already, save them in this order. */
275 /* Count the length of all strings. */
276 /* The old format doesn't contain hwcap entries and doesn't contain
277 libraries in subdirectories with hwcaps entries. Count therefore
278 also all entries with hwcap == 0. */
279 size_t total_strlen = 0;
280 struct cache_entry *entry;
281 /* Number of cache entries. */
282 int cache_entry_count = 0;
283 /* Number of normal cache entries. */
284 int cache_entry_old_count = 0;
286 for (entry = entries; entry != NULL; entry = entry->next)
288 /* Account the final NULs. */
289 total_strlen += strlen (entry->lib) + strlen (entry->path) + 2;
290 ++cache_entry_count;
291 if (entry->hwcap == 0)
292 ++cache_entry_old_count;
295 /* Create the on disk cache structure. */
296 struct cache_file *file_entries = NULL;
297 size_t file_entries_size = 0;
299 if (opt_format != 2)
301 /* struct cache_file_new is 64-bit aligned on some arches while
302 only 32-bit aligned on other arches. Duplicate last old
303 cache entry so that new cache in ld.so.cache can be used by
304 both. */
305 if (opt_format != 0)
306 cache_entry_old_count = (cache_entry_old_count + 1) & ~1;
308 /* And the list of all entries in the old format. */
309 file_entries_size = sizeof (struct cache_file)
310 + cache_entry_old_count * sizeof (struct file_entry);
311 file_entries = xmalloc (file_entries_size);
313 /* Fill in the header. */
314 memset (file_entries, '\0', sizeof (struct cache_file));
315 memcpy (file_entries->magic, CACHEMAGIC, sizeof CACHEMAGIC - 1);
317 file_entries->nlibs = cache_entry_old_count;
320 struct cache_file_new *file_entries_new = NULL;
321 size_t file_entries_new_size = 0;
323 if (opt_format != 0)
325 /* And the list of all entries in the new format. */
326 file_entries_new_size = sizeof (struct cache_file_new)
327 + cache_entry_count * sizeof (struct file_entry_new);
328 file_entries_new = xmalloc (file_entries_new_size);
330 /* Fill in the header. */
331 memset (file_entries_new, '\0', sizeof (struct cache_file_new));
332 memcpy (file_entries_new->magic, CACHEMAGIC_NEW,
333 sizeof CACHEMAGIC_NEW - 1);
334 memcpy (file_entries_new->version, CACHE_VERSION,
335 sizeof CACHE_VERSION - 1);
337 file_entries_new->nlibs = cache_entry_count;
338 file_entries_new->len_strings = total_strlen;
341 /* Pad for alignment of cache_file_new. */
342 size_t pad = ALIGN_CACHE (file_entries_size) - file_entries_size;
344 /* If we have both formats, we hide the new format in the strings
345 table, we have to adjust all string indices for this so that
346 old libc5/glibc 2 dynamic linkers just ignore them. */
347 unsigned int str_offset;
348 if (opt_format != 0)
349 str_offset = file_entries_new_size;
350 else
351 str_offset = 0;
353 /* An array for all strings. */
354 char *strings = xmalloc (total_strlen);
355 char *str = strings;
356 int idx_old;
357 int idx_new;
359 for (idx_old = 0, idx_new = 0, entry = entries; entry != NULL;
360 entry = entry->next, ++idx_new)
362 /* First the library. */
363 if (opt_format != 2 && entry->hwcap == 0)
365 file_entries->libs[idx_old].flags = entry->flags;
366 /* XXX: Actually we can optimize here and remove duplicates. */
367 file_entries->libs[idx_old].key = str_offset + pad;
369 if (opt_format != 0)
371 /* We could subtract file_entries_new_size from str_offset -
372 not doing so makes the code easier, the string table
373 always begins at the beginning of the new cache
374 struct. */
375 file_entries_new->libs[idx_new].flags = entry->flags;
376 file_entries_new->libs[idx_new].osversion = entry->osversion;
377 file_entries_new->libs[idx_new].hwcap = entry->hwcap;
378 file_entries_new->libs[idx_new].key = str_offset;
381 size_t len = strlen (entry->lib) + 1;
382 str = mempcpy (str, entry->lib, len);
383 str_offset += len;
384 /* Then the path. */
385 if (opt_format != 2 && entry->hwcap == 0)
386 file_entries->libs[idx_old].value = str_offset + pad;
387 if (opt_format != 0)
388 file_entries_new->libs[idx_new].value = str_offset;
389 len = strlen (entry->path) + 1;
390 str = mempcpy (str, entry->path, len);
391 str_offset += len;
392 /* Ignore entries with hwcap for old format. */
393 if (entry->hwcap == 0)
394 ++idx_old;
397 /* Duplicate last old cache entry if needed. */
398 if (opt_format != 2
399 && idx_old < cache_entry_old_count)
400 file_entries->libs[idx_old] = file_entries->libs[idx_old - 1];
402 /* Write out the cache. */
404 /* Write cache first to a temporary file and rename it later. */
405 char *temp_name = xmalloc (strlen (cache_name) + 2);
406 sprintf (temp_name, "%s~", cache_name);
408 /* Create file. */
409 int fd = open (temp_name, O_CREAT|O_WRONLY|O_TRUNC|O_NOFOLLOW,
410 S_IRUSR|S_IWUSR);
411 if (fd < 0)
412 error (EXIT_FAILURE, errno, _("Can't create temporary cache file %s"),
413 temp_name);
415 /* Write contents. */
416 if (opt_format != 2)
418 if (write (fd, file_entries, file_entries_size)
419 != (ssize_t) file_entries_size)
420 error (EXIT_FAILURE, errno, _("Writing of cache data failed"));
422 if (opt_format != 0)
424 /* Align cache. */
425 if (opt_format != 2)
427 char zero[pad];
428 memset (zero, '\0', pad);
429 if (write (fd, zero, pad) != (ssize_t) pad)
430 error (EXIT_FAILURE, errno, _("Writing of cache data failed"));
432 if (write (fd, file_entries_new, file_entries_new_size)
433 != (ssize_t) file_entries_new_size)
434 error (EXIT_FAILURE, errno, _("Writing of cache data failed"));
437 if (write (fd, strings, total_strlen) != (ssize_t) total_strlen
438 || close (fd))
439 error (EXIT_FAILURE, errno, _("Writing of cache data failed"));
441 /* Make sure user can always read cache file */
442 if (chmod (temp_name, S_IROTH|S_IRGRP|S_IRUSR|S_IWUSR))
443 error (EXIT_FAILURE, errno,
444 _("Changing access rights of %s to %#o failed"), temp_name,
445 S_IROTH|S_IRGRP|S_IRUSR|S_IWUSR);
447 /* Move temporary to its final location. */
448 if (rename (temp_name, cache_name))
449 error (EXIT_FAILURE, errno, _("Renaming of %s to %s failed"), temp_name,
450 cache_name);
452 /* Free all allocated memory. */
453 free (file_entries_new);
454 free (file_entries);
455 free (strings);
457 while (entries)
459 entry = entries;
460 entries = entries->next;
461 free (entry);
466 /* Add one library to the cache. */
467 void
468 add_to_cache (const char *path, const char *lib, int flags,
469 unsigned int osversion, uint64_t hwcap)
471 size_t liblen = strlen (lib) + 1;
472 size_t len = liblen + strlen (path) + 1;
473 struct cache_entry *new_entry
474 = xmalloc (sizeof (struct cache_entry) + liblen + len);
476 new_entry->lib = memcpy ((char *) (new_entry + 1), lib, liblen);
477 new_entry->path = new_entry->lib + liblen;
478 snprintf (new_entry->path, len, "%s/%s", path, lib);
479 new_entry->flags = flags;
480 new_entry->osversion = osversion;
481 new_entry->hwcap = hwcap;
482 new_entry->bits_hwcap = 0;
484 /* Count the number of bits set in the masked value. */
485 for (size_t i = 0;
486 (~((1ULL << i) - 1) & hwcap) != 0 && i < 8 * sizeof (hwcap); ++i)
487 if ((hwcap & (1ULL << i)) != 0)
488 ++new_entry->bits_hwcap;
491 /* Keep the list sorted - search for right place to insert. */
492 struct cache_entry *ptr = entries;
493 struct cache_entry *prev = entries;
494 while (ptr != NULL)
496 if (compare (ptr, new_entry) > 0)
497 break;
498 prev = ptr;
499 ptr = ptr->next;
501 /* Is this the first entry? */
502 if (ptr == entries)
504 new_entry->next = entries;
505 entries = new_entry;
507 else
509 new_entry->next = prev->next;
510 prev->next = new_entry;
515 /* Auxiliary cache. */
517 struct aux_cache_entry_id
519 uint64_t ino;
520 uint64_t ctime;
521 uint64_t size;
522 uint64_t dev;
525 struct aux_cache_entry
527 struct aux_cache_entry_id id;
528 int flags;
529 unsigned int osversion;
530 int used;
531 char *soname;
532 struct aux_cache_entry *next;
535 #define AUX_CACHEMAGIC "glibc-ld.so.auxcache-1.0"
537 struct aux_cache_file_entry
539 struct aux_cache_entry_id id; /* Unique id of entry. */
540 int32_t flags; /* This is 1 for an ELF library. */
541 uint32_t soname; /* String table indice. */
542 uint32_t osversion; /* Required OS version. */
543 int32_t pad;
546 /* ldconfig maintains an auxiliary cache file that allows
547 only reading those libraries that have changed since the last iteration.
548 For this for each library some information is cached in the auxiliary
549 cache. */
550 struct aux_cache_file
552 char magic[sizeof AUX_CACHEMAGIC - 1];
553 uint32_t nlibs; /* Number of entries. */
554 uint32_t len_strings; /* Size of string table. */
555 struct aux_cache_file_entry libs[0]; /* Entries describing libraries. */
556 /* After this the string table of size len_strings is found. */
559 static const unsigned int primes[] =
561 1021, 2039, 4093, 8191, 16381, 32749, 65521, 131071, 262139,
562 524287, 1048573, 2097143, 4194301, 8388593, 16777213, 33554393,
563 67108859, 134217689, 268435399, 536870909, 1073741789, 2147483647
566 static size_t aux_hash_size;
567 static struct aux_cache_entry **aux_hash;
569 /* Simplistic hash function for aux_cache_entry_id. */
570 static unsigned int
571 aux_cache_entry_id_hash (struct aux_cache_entry_id *id)
573 uint64_t ret = ((id->ino * 11 + id->ctime) * 11 + id->size) * 11 + id->dev;
574 return ret ^ (ret >> 32);
577 static size_t nextprime (size_t x)
579 for (unsigned int i = 0; i < sizeof (primes) / sizeof (primes[0]); ++i)
580 if (primes[i] >= x)
581 return primes[i];
582 return x;
585 void
586 init_aux_cache (void)
588 aux_hash_size = primes[3];
589 aux_hash = xcalloc (aux_hash_size, sizeof (struct aux_cache_entry *));
593 search_aux_cache (struct stat64 *stat_buf, int *flags,
594 unsigned int *osversion, char **soname)
596 struct aux_cache_entry_id id;
597 id.ino = (uint64_t) stat_buf->st_ino;
598 id.ctime = (uint64_t) stat_buf->st_ctime;
599 id.size = (uint64_t) stat_buf->st_size;
600 id.dev = (uint64_t) stat_buf->st_dev;
602 unsigned int hash = aux_cache_entry_id_hash (&id);
603 struct aux_cache_entry *entry;
604 for (entry = aux_hash[hash % aux_hash_size]; entry; entry = entry->next)
605 if (id.ino == entry->id.ino
606 && id.ctime == entry->id.ctime
607 && id.size == entry->id.size
608 && id.dev == entry->id.dev)
610 *flags = entry->flags;
611 *osversion = entry->osversion;
612 if (entry->soname != NULL)
613 *soname = xstrdup (entry->soname);
614 else
615 *soname = NULL;
616 entry->used = 1;
617 return 1;
620 return 0;
623 static void
624 insert_to_aux_cache (struct aux_cache_entry_id *id, int flags,
625 unsigned int osversion, const char *soname, int used)
627 size_t hash = aux_cache_entry_id_hash (id) % aux_hash_size;
628 struct aux_cache_entry *entry;
629 for (entry = aux_hash[hash]; entry; entry = entry->next)
630 if (id->ino == entry->id.ino
631 && id->ctime == entry->id.ctime
632 && id->size == entry->id.size
633 && id->dev == entry->id.dev)
634 abort ();
636 size_t len = soname ? strlen (soname) + 1 : 0;
637 entry = xmalloc (sizeof (struct aux_cache_entry) + len);
638 entry->id = *id;
639 entry->flags = flags;
640 entry->osversion = osversion;
641 entry->used = used;
642 if (soname != NULL)
643 entry->soname = memcpy ((char *) (entry + 1), soname, len);
644 else
645 entry->soname = NULL;
646 entry->next = aux_hash[hash];
647 aux_hash[hash] = entry;
650 void
651 add_to_aux_cache (struct stat64 *stat_buf, int flags,
652 unsigned int osversion, const char *soname)
654 struct aux_cache_entry_id id;
655 id.ino = (uint64_t) stat_buf->st_ino;
656 id.ctime = (uint64_t) stat_buf->st_ctime;
657 id.size = (uint64_t) stat_buf->st_size;
658 id.dev = (uint64_t) stat_buf->st_dev;
659 insert_to_aux_cache (&id, flags, osversion, soname, 1);
662 /* Load auxiliary cache to search for unchanged entries. */
663 void
664 load_aux_cache (const char *aux_cache_name)
666 int fd = open (aux_cache_name, O_RDONLY);
667 if (fd < 0)
669 init_aux_cache ();
670 return;
673 struct stat64 st;
674 if (fstat64 (fd, &st) < 0 || st.st_size < sizeof (struct aux_cache_file))
676 close (fd);
677 init_aux_cache ();
678 return;
681 size_t aux_cache_size = st.st_size;
682 struct aux_cache_file *aux_cache
683 = mmap (NULL, aux_cache_size, PROT_READ, MAP_PRIVATE, fd, 0);
684 if (aux_cache == MAP_FAILED
685 || aux_cache_size < sizeof (struct aux_cache_file)
686 || memcmp (aux_cache->magic, AUX_CACHEMAGIC, sizeof AUX_CACHEMAGIC - 1)
687 || aux_cache->nlibs >= aux_cache_size)
689 close (fd);
690 init_aux_cache ();
691 return;
694 aux_hash_size = nextprime (aux_cache->nlibs);
695 aux_hash = xcalloc (aux_hash_size, sizeof (struct aux_cache_entry *));
697 const char *aux_cache_data
698 = (const char *) &aux_cache->libs[aux_cache->nlibs];
699 for (unsigned int i = 0; i < aux_cache->nlibs; ++i)
700 insert_to_aux_cache (&aux_cache->libs[i].id,
701 aux_cache->libs[i].flags,
702 aux_cache->libs[i].osversion,
703 aux_cache->libs[i].soname == 0
704 ? NULL : aux_cache_data + aux_cache->libs[i].soname,
707 munmap (aux_cache, aux_cache_size);
708 close (fd);
711 /* Save the contents of the auxiliary cache. */
712 void
713 save_aux_cache (const char *aux_cache_name)
715 /* Count the length of all sonames. We start with empty string. */
716 size_t total_strlen = 1;
717 /* Number of cache entries. */
718 int cache_entry_count = 0;
720 for (size_t i = 0; i < aux_hash_size; ++i)
721 for (struct aux_cache_entry *entry = aux_hash[i];
722 entry != NULL; entry = entry->next)
723 if (entry->used)
725 ++cache_entry_count;
726 if (entry->soname != NULL)
727 total_strlen += strlen (entry->soname) + 1;
730 /* Auxiliary cache. */
731 size_t file_entries_size
732 = sizeof (struct aux_cache_file)
733 + cache_entry_count * sizeof (struct aux_cache_file_entry);
734 struct aux_cache_file *file_entries
735 = xmalloc (file_entries_size + total_strlen);
737 /* Fill in the header of the auxiliary cache. */
738 memset (file_entries, '\0', sizeof (struct aux_cache_file));
739 memcpy (file_entries->magic, AUX_CACHEMAGIC, sizeof AUX_CACHEMAGIC - 1);
741 file_entries->nlibs = cache_entry_count;
742 file_entries->len_strings = total_strlen;
744 /* Initial String offset for auxiliary cache is always after the
745 special empty string. */
746 unsigned int str_offset = 1;
748 /* An array for all strings. */
749 char *str = (char *) file_entries + file_entries_size;
750 *str++ = '\0';
752 size_t idx = 0;
753 for (size_t i = 0; i < aux_hash_size; ++i)
754 for (struct aux_cache_entry *entry = aux_hash[i];
755 entry != NULL; entry = entry->next)
756 if (entry->used)
758 file_entries->libs[idx].id = entry->id;
759 file_entries->libs[idx].flags = entry->flags;
760 if (entry->soname == NULL)
761 file_entries->libs[idx].soname = 0;
762 else
764 file_entries->libs[idx].soname = str_offset;
766 size_t len = strlen (entry->soname) + 1;
767 str = mempcpy (str, entry->soname, len);
768 str_offset += len;
770 file_entries->libs[idx].osversion = entry->osversion;
771 file_entries->libs[idx++].pad = 0;
774 /* Write out auxiliary cache file. */
775 /* Write auxiliary cache first to a temporary file and rename it later. */
777 char *temp_name = xmalloc (strlen (aux_cache_name) + 2);
778 sprintf (temp_name, "%s~", aux_cache_name);
780 /* Check that directory exists and create if needed. */
781 char *dir = strdupa (aux_cache_name);
782 dir = dirname (dir);
784 struct stat64 st;
785 if (stat64 (dir, &st) < 0)
787 if (mkdir (dir, 0700) < 0)
788 goto out_fail;
791 /* Create file. */
792 int fd = open (temp_name, O_CREAT|O_WRONLY|O_TRUNC|O_NOFOLLOW,
793 S_IRUSR|S_IWUSR);
794 if (fd < 0)
795 goto out_fail;
797 if (write (fd, file_entries, file_entries_size + total_strlen)
798 != (ssize_t) (file_entries_size + total_strlen)
799 || close (fd))
801 unlink (temp_name);
802 goto out_fail;
805 /* Move temporary to its final location. */
806 if (rename (temp_name, aux_cache_name))
807 unlink (temp_name);
809 out_fail:
810 /* Free allocated memory. */
811 free (temp_name);
812 free (file_entries);