1 /* Copyright (C) 1999-2017 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/>. */
29 #include <sys/fcntl.h>
32 #include <sys/types.h>
39 char *lib
; /* Library name. */
40 char *path
; /* Path to find library. */
41 int flags
; /* Flags to indicate kind of library. */
42 unsigned int osversion
; /* Required OS version. */
43 uint64_t hwcap
; /* Important hardware capabilities. */
44 int bits_hwcap
; /* Number of bits set in hwcap. */
45 struct cache_entry
*next
; /* Next entry in list. */
48 /* List of all cache entries. */
49 static struct cache_entry
*entries
;
51 static const char *flag_descr
[] =
52 { "libc4", "ELF", "libc5", "libc6"};
54 /* Print a single entry. */
56 print_entry (const char *lib
, int flag
, unsigned int osversion
,
57 uint64_t hwcap
, const char *key
)
59 printf ("\t%s (", lib
);
60 switch (flag
& FLAG_TYPE_MASK
)
66 fputs (flag_descr
[flag
& FLAG_TYPE_MASK
], stdout
);
69 fputs (_("unknown"), stdout
);
72 switch (flag
& FLAG_REQUIRED_MASK
)
74 case FLAG_SPARC_LIB64
:
75 fputs (",64bit", stdout
);
78 fputs (",IA-64", stdout
);
80 case FLAG_X8664_LIB64
:
81 fputs (",x86-64", stdout
);
84 fputs (",64bit", stdout
);
86 case FLAG_POWERPC_LIB64
:
87 fputs (",64bit", stdout
);
89 case FLAG_MIPS64_LIBN32
:
90 fputs (",N32", stdout
);
92 case FLAG_MIPS64_LIBN64
:
93 fputs (",64bit", stdout
);
95 case FLAG_X8664_LIBX32
:
96 fputs (",x32", stdout
);
99 fputs (",hard-float", stdout
);
101 case FLAG_AARCH64_LIB64
:
102 fputs (",AArch64", stdout
);
104 /* Uses the ARM soft-float ABI. */
106 fputs (",soft-float", stdout
);
108 case FLAG_MIPS_LIB32_NAN2008
:
109 fputs (",nan2008", stdout
);
111 case FLAG_MIPS64_LIBN32_NAN2008
:
112 fputs (",N32,nan2008", stdout
);
114 case FLAG_MIPS64_LIBN64_NAN2008
:
115 fputs (",64bit,nan2008", stdout
);
120 printf (",%d", flag
& FLAG_REQUIRED_MASK
);
124 printf (", hwcap: %#.16" PRIx64
, hwcap
);
127 static const char *const abi_tag_os
[] =
135 [6] = N_("Unknown OS")
137 #define MAXTAG (sizeof abi_tag_os / sizeof abi_tag_os[0] - 1)
138 unsigned int os
= osversion
>> 24;
140 printf (_(", OS ABI: %s %d.%d.%d"),
141 _(abi_tag_os
[os
> MAXTAG
? MAXTAG
: os
]),
142 (osversion
>> 16) & 0xff,
143 (osversion
>> 8) & 0xff,
146 printf (") => %s\n", key
);
150 /* Print the whole cache file, if a file contains the new cache format
151 hidden in the old one, print the contents of the new format. */
153 print_cache (const char *cache_name
)
155 int fd
= open (cache_name
, O_RDONLY
);
157 error (EXIT_FAILURE
, errno
, _("Can't open cache file %s\n"), cache_name
);
160 if (fstat64 (fd
, &st
) < 0
161 /* No need to map the file if it is empty. */
168 struct cache_file
*cache
169 = mmap (NULL
, st
.st_size
, PROT_READ
, MAP_PRIVATE
, fd
, 0);
170 if (cache
== MAP_FAILED
)
171 error (EXIT_FAILURE
, errno
, _("mmap of cache file failed.\n"));
173 size_t cache_size
= st
.st_size
;
174 if (cache_size
< sizeof (struct cache_file
))
175 error (EXIT_FAILURE
, 0, _("File is not a cache file.\n"));
177 struct cache_file_new
*cache_new
= NULL
;
178 const char *cache_data
;
181 if (memcmp (cache
->magic
, CACHEMAGIC
, sizeof CACHEMAGIC
- 1))
183 /* This can only be the new format without the old one. */
184 cache_new
= (struct cache_file_new
*) cache
;
186 if (memcmp (cache_new
->magic
, CACHEMAGIC_NEW
, sizeof CACHEMAGIC_NEW
- 1)
187 || memcmp (cache_new
->version
, CACHE_VERSION
,
188 sizeof CACHE_VERSION
- 1))
189 error (EXIT_FAILURE
, 0, _("File is not a cache file.\n"));
191 /* This is where the strings start. */
192 cache_data
= (const char *) cache_new
;
196 size_t offset
= ALIGN_CACHE (sizeof (struct cache_file
)
198 * sizeof (struct file_entry
)));
199 /* This is where the strings start. */
200 cache_data
= (const char *) &cache
->libs
[cache
->nlibs
];
202 /* Check for a new cache embedded in the old format. */
204 (offset
+ sizeof (struct cache_file_new
)))
207 cache_new
= (struct cache_file_new
*) ((void *)cache
+ offset
);
209 if (memcmp (cache_new
->magic
, CACHEMAGIC_NEW
,
210 sizeof CACHEMAGIC_NEW
- 1) == 0
211 && memcmp (cache_new
->version
, CACHE_VERSION
,
212 sizeof CACHE_VERSION
- 1) == 0)
214 cache_data
= (const char *) cache_new
;
222 printf (_("%d libs found in cache `%s'\n"), cache
->nlibs
, cache_name
);
224 /* Print everything. */
225 for (unsigned int i
= 0; i
< cache
->nlibs
; i
++)
226 print_entry (cache_data
+ cache
->libs
[i
].key
,
227 cache
->libs
[i
].flags
, 0, 0,
228 cache_data
+ cache
->libs
[i
].value
);
230 else if (format
== 1)
232 printf (_("%d libs found in cache `%s'\n"),
233 cache_new
->nlibs
, cache_name
);
235 /* Print everything. */
236 for (unsigned int i
= 0; i
< cache_new
->nlibs
; i
++)
237 print_entry (cache_data
+ cache_new
->libs
[i
].key
,
238 cache_new
->libs
[i
].flags
,
239 cache_new
->libs
[i
].osversion
,
240 cache_new
->libs
[i
].hwcap
,
241 cache_data
+ cache_new
->libs
[i
].value
);
244 munmap (cache
, cache_size
);
248 /* Initialize cache data structures. */
256 compare (const struct cache_entry
*e1
, const struct cache_entry
*e2
)
258 /* We need to swap entries here to get the correct sort order. */
259 int res
= _dl_cache_libcmp (e2
->lib
, e1
->lib
);
262 if (e1
->flags
< e2
->flags
)
264 else if (e1
->flags
> e2
->flags
)
266 /* Sort by most specific hwcap. */
267 else if (e2
->bits_hwcap
> e1
->bits_hwcap
)
269 else if (e2
->bits_hwcap
< e1
->bits_hwcap
)
271 else if (e2
->hwcap
> e1
->hwcap
)
273 else if (e2
->hwcap
< e1
->hwcap
)
275 if (e2
->osversion
> e1
->osversion
)
277 if (e2
->osversion
< e1
->osversion
)
283 /* Save the contents of the cache. */
285 save_cache (const char *cache_name
)
287 /* The cache entries are sorted already, save them in this order. */
289 /* Count the length of all strings. */
290 /* The old format doesn't contain hwcap entries and doesn't contain
291 libraries in subdirectories with hwcaps entries. Count therefore
292 also all entries with hwcap == 0. */
293 size_t total_strlen
= 0;
294 struct cache_entry
*entry
;
295 /* Number of cache entries. */
296 int cache_entry_count
= 0;
297 /* Number of normal cache entries. */
298 int cache_entry_old_count
= 0;
300 for (entry
= entries
; entry
!= NULL
; entry
= entry
->next
)
302 /* Account the final NULs. */
303 total_strlen
+= strlen (entry
->lib
) + strlen (entry
->path
) + 2;
305 if (entry
->hwcap
== 0)
306 ++cache_entry_old_count
;
309 /* Create the on disk cache structure. */
310 struct cache_file
*file_entries
= NULL
;
311 size_t file_entries_size
= 0;
315 /* struct cache_file_new is 64-bit aligned on some arches while
316 only 32-bit aligned on other arches. Duplicate last old
317 cache entry so that new cache in ld.so.cache can be used by
320 cache_entry_old_count
= (cache_entry_old_count
+ 1) & ~1;
322 /* And the list of all entries in the old format. */
323 file_entries_size
= sizeof (struct cache_file
)
324 + cache_entry_old_count
* sizeof (struct file_entry
);
325 file_entries
= xmalloc (file_entries_size
);
327 /* Fill in the header. */
328 memset (file_entries
, '\0', sizeof (struct cache_file
));
329 memcpy (file_entries
->magic
, CACHEMAGIC
, sizeof CACHEMAGIC
- 1);
331 file_entries
->nlibs
= cache_entry_old_count
;
334 struct cache_file_new
*file_entries_new
= NULL
;
335 size_t file_entries_new_size
= 0;
339 /* And the list of all entries in the new format. */
340 file_entries_new_size
= sizeof (struct cache_file_new
)
341 + cache_entry_count
* sizeof (struct file_entry_new
);
342 file_entries_new
= xmalloc (file_entries_new_size
);
344 /* Fill in the header. */
345 memset (file_entries_new
, '\0', sizeof (struct cache_file_new
));
346 memcpy (file_entries_new
->magic
, CACHEMAGIC_NEW
,
347 sizeof CACHEMAGIC_NEW
- 1);
348 memcpy (file_entries_new
->version
, CACHE_VERSION
,
349 sizeof CACHE_VERSION
- 1);
351 file_entries_new
->nlibs
= cache_entry_count
;
352 file_entries_new
->len_strings
= total_strlen
;
355 /* Pad for alignment of cache_file_new. */
356 size_t pad
= ALIGN_CACHE (file_entries_size
) - file_entries_size
;
358 /* If we have both formats, we hide the new format in the strings
359 table, we have to adjust all string indices for this so that
360 old libc5/glibc 2 dynamic linkers just ignore them. */
361 unsigned int str_offset
;
363 str_offset
= file_entries_new_size
;
367 /* An array for all strings. */
368 char *strings
= xmalloc (total_strlen
);
373 for (idx_old
= 0, idx_new
= 0, entry
= entries
; entry
!= NULL
;
374 entry
= entry
->next
, ++idx_new
)
376 /* First the library. */
377 if (opt_format
!= 2 && entry
->hwcap
== 0)
379 file_entries
->libs
[idx_old
].flags
= entry
->flags
;
380 /* XXX: Actually we can optimize here and remove duplicates. */
381 file_entries
->libs
[idx_old
].key
= str_offset
+ pad
;
385 /* We could subtract file_entries_new_size from str_offset -
386 not doing so makes the code easier, the string table
387 always begins at the beginning of the new cache
389 file_entries_new
->libs
[idx_new
].flags
= entry
->flags
;
390 file_entries_new
->libs
[idx_new
].osversion
= entry
->osversion
;
391 file_entries_new
->libs
[idx_new
].hwcap
= entry
->hwcap
;
392 file_entries_new
->libs
[idx_new
].key
= str_offset
;
395 size_t len
= strlen (entry
->lib
) + 1;
396 str
= mempcpy (str
, entry
->lib
, len
);
399 if (opt_format
!= 2 && entry
->hwcap
== 0)
400 file_entries
->libs
[idx_old
].value
= str_offset
+ pad
;
402 file_entries_new
->libs
[idx_new
].value
= str_offset
;
403 len
= strlen (entry
->path
) + 1;
404 str
= mempcpy (str
, entry
->path
, len
);
406 /* Ignore entries with hwcap for old format. */
407 if (entry
->hwcap
== 0)
411 /* Duplicate last old cache entry if needed. */
413 && idx_old
< cache_entry_old_count
)
414 file_entries
->libs
[idx_old
] = file_entries
->libs
[idx_old
- 1];
416 /* Write out the cache. */
418 /* Write cache first to a temporary file and rename it later. */
419 char *temp_name
= xmalloc (strlen (cache_name
) + 2);
420 sprintf (temp_name
, "%s~", cache_name
);
423 int fd
= open (temp_name
, O_CREAT
|O_WRONLY
|O_TRUNC
|O_NOFOLLOW
,
426 error (EXIT_FAILURE
, errno
, _("Can't create temporary cache file %s"),
429 /* Write contents. */
432 if (write (fd
, file_entries
, file_entries_size
)
433 != (ssize_t
) file_entries_size
)
434 error (EXIT_FAILURE
, errno
, _("Writing of cache data failed"));
442 memset (zero
, '\0', pad
);
443 if (write (fd
, zero
, pad
) != (ssize_t
) pad
)
444 error (EXIT_FAILURE
, errno
, _("Writing of cache data failed"));
446 if (write (fd
, file_entries_new
, file_entries_new_size
)
447 != (ssize_t
) file_entries_new_size
)
448 error (EXIT_FAILURE
, errno
, _("Writing of cache data failed"));
451 if (write (fd
, strings
, total_strlen
) != (ssize_t
) total_strlen
453 error (EXIT_FAILURE
, errno
, _("Writing of cache data failed"));
455 /* Make sure user can always read cache file */
456 if (chmod (temp_name
, S_IROTH
|S_IRGRP
|S_IRUSR
|S_IWUSR
))
457 error (EXIT_FAILURE
, errno
,
458 _("Changing access rights of %s to %#o failed"), temp_name
,
459 S_IROTH
|S_IRGRP
|S_IRUSR
|S_IWUSR
);
461 /* Move temporary to its final location. */
462 if (rename (temp_name
, cache_name
))
463 error (EXIT_FAILURE
, errno
, _("Renaming of %s to %s failed"), temp_name
,
466 /* Free all allocated memory. */
467 free (file_entries_new
);
474 entries
= entries
->next
;
480 /* Add one library to the cache. */
482 add_to_cache (const char *path
, const char *lib
, int flags
,
483 unsigned int osversion
, uint64_t hwcap
)
485 size_t liblen
= strlen (lib
) + 1;
486 size_t len
= liblen
+ strlen (path
) + 1;
487 struct cache_entry
*new_entry
488 = xmalloc (sizeof (struct cache_entry
) + liblen
+ len
);
490 new_entry
->lib
= memcpy ((char *) (new_entry
+ 1), lib
, liblen
);
491 new_entry
->path
= new_entry
->lib
+ liblen
;
492 snprintf (new_entry
->path
, len
, "%s/%s", path
, lib
);
493 new_entry
->flags
= flags
;
494 new_entry
->osversion
= osversion
;
495 new_entry
->hwcap
= hwcap
;
496 new_entry
->bits_hwcap
= 0;
498 /* Count the number of bits set in the masked value. */
500 (~((1ULL << i
) - 1) & hwcap
) != 0 && i
< 8 * sizeof (hwcap
); ++i
)
501 if ((hwcap
& (1ULL << i
)) != 0)
502 ++new_entry
->bits_hwcap
;
505 /* Keep the list sorted - search for right place to insert. */
506 struct cache_entry
*ptr
= entries
;
507 struct cache_entry
*prev
= entries
;
510 if (compare (ptr
, new_entry
) > 0)
515 /* Is this the first entry? */
518 new_entry
->next
= entries
;
523 new_entry
->next
= prev
->next
;
524 prev
->next
= new_entry
;
529 /* Auxiliary cache. */
531 struct aux_cache_entry_id
539 struct aux_cache_entry
541 struct aux_cache_entry_id id
;
543 unsigned int osversion
;
546 struct aux_cache_entry
*next
;
549 #define AUX_CACHEMAGIC "glibc-ld.so.auxcache-1.0"
551 struct aux_cache_file_entry
553 struct aux_cache_entry_id id
; /* Unique id of entry. */
554 int32_t flags
; /* This is 1 for an ELF library. */
555 uint32_t soname
; /* String table indice. */
556 uint32_t osversion
; /* Required OS version. */
560 /* ldconfig maintains an auxiliary cache file that allows
561 only reading those libraries that have changed since the last iteration.
562 For this for each library some information is cached in the auxiliary
564 struct aux_cache_file
566 char magic
[sizeof AUX_CACHEMAGIC
- 1];
567 uint32_t nlibs
; /* Number of entries. */
568 uint32_t len_strings
; /* Size of string table. */
569 struct aux_cache_file_entry libs
[0]; /* Entries describing libraries. */
570 /* After this the string table of size len_strings is found. */
573 static const unsigned int primes
[] =
575 1021, 2039, 4093, 8191, 16381, 32749, 65521, 131071, 262139,
576 524287, 1048573, 2097143, 4194301, 8388593, 16777213, 33554393,
577 67108859, 134217689, 268435399, 536870909, 1073741789, 2147483647
580 static size_t aux_hash_size
;
581 static struct aux_cache_entry
**aux_hash
;
583 /* Simplistic hash function for aux_cache_entry_id. */
585 aux_cache_entry_id_hash (struct aux_cache_entry_id
*id
)
587 uint64_t ret
= ((id
->ino
* 11 + id
->ctime
) * 11 + id
->size
) * 11 + id
->dev
;
588 return ret
^ (ret
>> 32);
591 static size_t nextprime (size_t x
)
593 for (unsigned int i
= 0; i
< sizeof (primes
) / sizeof (primes
[0]); ++i
)
600 init_aux_cache (void)
602 aux_hash_size
= primes
[3];
603 aux_hash
= xcalloc (aux_hash_size
, sizeof (struct aux_cache_entry
*));
607 search_aux_cache (struct stat64
*stat_buf
, int *flags
,
608 unsigned int *osversion
, char **soname
)
610 struct aux_cache_entry_id id
;
611 id
.ino
= (uint64_t) stat_buf
->st_ino
;
612 id
.ctime
= (uint64_t) stat_buf
->st_ctime
;
613 id
.size
= (uint64_t) stat_buf
->st_size
;
614 id
.dev
= (uint64_t) stat_buf
->st_dev
;
616 unsigned int hash
= aux_cache_entry_id_hash (&id
);
617 struct aux_cache_entry
*entry
;
618 for (entry
= aux_hash
[hash
% aux_hash_size
]; entry
; entry
= entry
->next
)
619 if (id
.ino
== entry
->id
.ino
620 && id
.ctime
== entry
->id
.ctime
621 && id
.size
== entry
->id
.size
622 && id
.dev
== entry
->id
.dev
)
624 *flags
= entry
->flags
;
625 *osversion
= entry
->osversion
;
626 if (entry
->soname
!= NULL
)
627 *soname
= xstrdup (entry
->soname
);
638 insert_to_aux_cache (struct aux_cache_entry_id
*id
, int flags
,
639 unsigned int osversion
, const char *soname
, int used
)
641 size_t hash
= aux_cache_entry_id_hash (id
) % aux_hash_size
;
642 struct aux_cache_entry
*entry
;
643 for (entry
= aux_hash
[hash
]; entry
; entry
= entry
->next
)
644 if (id
->ino
== entry
->id
.ino
645 && id
->ctime
== entry
->id
.ctime
646 && id
->size
== entry
->id
.size
647 && id
->dev
== entry
->id
.dev
)
650 size_t len
= soname
? strlen (soname
) + 1 : 0;
651 entry
= xmalloc (sizeof (struct aux_cache_entry
) + len
);
653 entry
->flags
= flags
;
654 entry
->osversion
= osversion
;
657 entry
->soname
= memcpy ((char *) (entry
+ 1), soname
, len
);
659 entry
->soname
= NULL
;
660 entry
->next
= aux_hash
[hash
];
661 aux_hash
[hash
] = entry
;
665 add_to_aux_cache (struct stat64
*stat_buf
, int flags
,
666 unsigned int osversion
, const char *soname
)
668 struct aux_cache_entry_id id
;
669 id
.ino
= (uint64_t) stat_buf
->st_ino
;
670 id
.ctime
= (uint64_t) stat_buf
->st_ctime
;
671 id
.size
= (uint64_t) stat_buf
->st_size
;
672 id
.dev
= (uint64_t) stat_buf
->st_dev
;
673 insert_to_aux_cache (&id
, flags
, osversion
, soname
, 1);
676 /* Load auxiliary cache to search for unchanged entries. */
678 load_aux_cache (const char *aux_cache_name
)
680 int fd
= open (aux_cache_name
, O_RDONLY
);
688 if (fstat64 (fd
, &st
) < 0 || st
.st_size
< sizeof (struct aux_cache_file
))
695 size_t aux_cache_size
= st
.st_size
;
696 struct aux_cache_file
*aux_cache
697 = mmap (NULL
, aux_cache_size
, PROT_READ
, MAP_PRIVATE
, fd
, 0);
698 if (aux_cache
== MAP_FAILED
699 || aux_cache_size
< sizeof (struct aux_cache_file
)
700 || memcmp (aux_cache
->magic
, AUX_CACHEMAGIC
, sizeof AUX_CACHEMAGIC
- 1)
701 || aux_cache_size
!= (sizeof(struct aux_cache_file
) +
702 aux_cache
->nlibs
* sizeof(struct aux_cache_file_entry
) +
703 aux_cache
->len_strings
))
710 aux_hash_size
= nextprime (aux_cache
->nlibs
);
711 aux_hash
= xcalloc (aux_hash_size
, sizeof (struct aux_cache_entry
*));
713 const char *aux_cache_data
714 = (const char *) &aux_cache
->libs
[aux_cache
->nlibs
];
715 for (unsigned int i
= 0; i
< aux_cache
->nlibs
; ++i
)
716 insert_to_aux_cache (&aux_cache
->libs
[i
].id
,
717 aux_cache
->libs
[i
].flags
,
718 aux_cache
->libs
[i
].osversion
,
719 aux_cache
->libs
[i
].soname
== 0
720 ? NULL
: aux_cache_data
+ aux_cache
->libs
[i
].soname
,
723 munmap (aux_cache
, aux_cache_size
);
727 /* Save the contents of the auxiliary cache. */
729 save_aux_cache (const char *aux_cache_name
)
731 /* Count the length of all sonames. We start with empty string. */
732 size_t total_strlen
= 1;
733 /* Number of cache entries. */
734 int cache_entry_count
= 0;
736 for (size_t i
= 0; i
< aux_hash_size
; ++i
)
737 for (struct aux_cache_entry
*entry
= aux_hash
[i
];
738 entry
!= NULL
; entry
= entry
->next
)
742 if (entry
->soname
!= NULL
)
743 total_strlen
+= strlen (entry
->soname
) + 1;
746 /* Auxiliary cache. */
747 size_t file_entries_size
748 = sizeof (struct aux_cache_file
)
749 + cache_entry_count
* sizeof (struct aux_cache_file_entry
);
750 struct aux_cache_file
*file_entries
751 = xmalloc (file_entries_size
+ total_strlen
);
753 /* Fill in the header of the auxiliary cache. */
754 memset (file_entries
, '\0', sizeof (struct aux_cache_file
));
755 memcpy (file_entries
->magic
, AUX_CACHEMAGIC
, sizeof AUX_CACHEMAGIC
- 1);
757 file_entries
->nlibs
= cache_entry_count
;
758 file_entries
->len_strings
= total_strlen
;
760 /* Initial String offset for auxiliary cache is always after the
761 special empty string. */
762 unsigned int str_offset
= 1;
764 /* An array for all strings. */
765 char *str
= (char *) file_entries
+ file_entries_size
;
769 for (size_t i
= 0; i
< aux_hash_size
; ++i
)
770 for (struct aux_cache_entry
*entry
= aux_hash
[i
];
771 entry
!= NULL
; entry
= entry
->next
)
774 file_entries
->libs
[idx
].id
= entry
->id
;
775 file_entries
->libs
[idx
].flags
= entry
->flags
;
776 if (entry
->soname
== NULL
)
777 file_entries
->libs
[idx
].soname
= 0;
780 file_entries
->libs
[idx
].soname
= str_offset
;
782 size_t len
= strlen (entry
->soname
) + 1;
783 str
= mempcpy (str
, entry
->soname
, len
);
786 file_entries
->libs
[idx
].osversion
= entry
->osversion
;
787 file_entries
->libs
[idx
++].pad
= 0;
790 /* Write out auxiliary cache file. */
791 /* Write auxiliary cache first to a temporary file and rename it later. */
793 char *temp_name
= xmalloc (strlen (aux_cache_name
) + 2);
794 sprintf (temp_name
, "%s~", aux_cache_name
);
796 /* Check that directory exists and create if needed. */
797 char *dir
= strdupa (aux_cache_name
);
801 if (stat64 (dir
, &st
) < 0)
803 if (mkdir (dir
, 0700) < 0)
808 int fd
= open (temp_name
, O_CREAT
|O_WRONLY
|O_TRUNC
|O_NOFOLLOW
,
813 if (write (fd
, file_entries
, file_entries_size
+ total_strlen
)
814 != (ssize_t
) (file_entries_size
+ total_strlen
)
821 /* Move temporary to its final location. */
822 if (rename (temp_name
, aux_cache_name
))
826 /* Free allocated memory. */