| /* BFD library -- caching of file descriptors. | 
 |  | 
 |    Copyright (C) 1990-2025 Free Software Foundation, Inc. | 
 |  | 
 |    Hacked by Steve Chamberlain of Cygnus Support (steve@cygnus.com). | 
 |  | 
 |    This file is part of BFD, the Binary File Descriptor library. | 
 |  | 
 |    This program is free software; you can redistribute it and/or modify | 
 |    it under the terms of the GNU General Public License as published by | 
 |    the Free Software Foundation; either version 3 of the License, or | 
 |    (at your option) any later version. | 
 |  | 
 |    This program is distributed in the hope that it will be useful, | 
 |    but WITHOUT ANY WARRANTY; without even the implied warranty of | 
 |    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the | 
 |    GNU General Public License for more details. | 
 |  | 
 |    You should have received a copy of the GNU General Public License | 
 |    along with this program; if not, write to the Free Software | 
 |    Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, | 
 |    MA 02110-1301, USA.  */ | 
 |  | 
 | /* | 
 | SECTION | 
 | 	File caching | 
 |  | 
 | 	The file caching mechanism is embedded within BFD and allows | 
 | 	the application to open as many BFDs as it wants without | 
 | 	regard to the underlying operating system's file descriptor | 
 | 	limit (often as low as 20 open files).  The module in | 
 | 	<<cache.c>> maintains a least recently used list of | 
 | 	<<bfd_cache_max_open>> files, and exports the name | 
 | 	<<bfd_cache_lookup>>, which runs around and makes sure that | 
 | 	the required BFD is open. If not, then it chooses a file to | 
 | 	close, closes it and opens the one wanted, returning its file | 
 | 	handle. | 
 |  | 
 | SUBSECTION | 
 | 	Caching functions | 
 | */ | 
 |  | 
 | #include "sysdep.h" | 
 | #include "bfd.h" | 
 | #include "libbfd.h" | 
 | #include "libiberty.h" | 
 |  | 
 | static FILE *_bfd_open_file_unlocked (bfd *abfd); | 
 |  | 
 | /* In some cases we can optimize cache operation when reopening files. | 
 |    For instance, a flush is entirely unnecessary if the file is already | 
 |    closed, so a flush would use CACHE_NO_OPEN.  Similarly, a seek using | 
 |    SEEK_SET or SEEK_END need not first seek to the current position. | 
 |    For stat we ignore seek errors, just in case the file has changed | 
 |    while we weren't looking.  If it has, then it's possible that the | 
 |    file is shorter and we don't want a seek error to prevent us doing | 
 |    the stat.  */ | 
 | enum cache_flag { | 
 |   CACHE_NORMAL = 0, | 
 |   CACHE_NO_OPEN = 1, | 
 |   CACHE_NO_SEEK = 2, | 
 |   CACHE_NO_SEEK_ERROR = 4 | 
 | }; | 
 |  | 
 | /* The maximum number of files which the cache will keep open at | 
 |    one time.  When needed call bfd_cache_max_open to initialize.  */ | 
 |  | 
 | static unsigned max_open_files = 0; | 
 |  | 
 | /* Set max_open_files, if not already set, to 12.5% of the allowed open | 
 |    file descriptors, but at least 10, and return the value.  */ | 
 | static unsigned | 
 | bfd_cache_max_open (void) | 
 | { | 
 |   if (max_open_files == 0) | 
 |     { | 
 |       int max; | 
 | #if defined(__sun) && !defined(__sparcv9) && !defined(__x86_64__) | 
 |       /* PR ld/19260: 32-bit Solaris has very inelegant handling of the 255 | 
 | 	 file descriptor limit.  The problem is that setrlimit(2) can raise | 
 | 	 RLIMIT_NOFILE to a value that is not supported by libc, resulting | 
 | 	 in "Too many open files" errors.  This can happen here even though | 
 | 	 max_open_files is set to rlim.rlim_cur / 8.  For example, if | 
 | 	 a parent process has set rlim.rlim_cur to 65536, then max_open_files | 
 | 	 will be computed as 8192. | 
 |  | 
 | 	 This check essentially reverts to the behavior from binutils 2.23.1 | 
 | 	 for 32-bit Solaris only.  (It is hoped that the 32-bit libc | 
 | 	 limitation will be removed soon).  64-bit Solaris libc does not have | 
 | 	 this limitation.  */ | 
 |       max = 16; | 
 | #else | 
 | #ifdef HAVE_GETRLIMIT | 
 |       struct rlimit rlim; | 
 |  | 
 |       if (getrlimit (RLIMIT_NOFILE, &rlim) == 0 | 
 | 	  && rlim.rlim_cur != (rlim_t) RLIM_INFINITY) | 
 | 	max = rlim.rlim_cur / 8; | 
 |       else | 
 | #endif | 
 | #ifdef _SC_OPEN_MAX | 
 | 	max = sysconf (_SC_OPEN_MAX) / 8; | 
 | #else | 
 | 	max = 10; | 
 | #endif | 
 | #endif /* not 32-bit Solaris */ | 
 |  | 
 |       max_open_files = max < 10 ? 10 : max; | 
 |     } | 
 |  | 
 |   return max_open_files; | 
 | } | 
 |  | 
 | /* The number of BFD files we have open.  */ | 
 |  | 
 | static unsigned open_files; | 
 |  | 
 | /* Zero, or a pointer to the topmost BFD on the chain.  This is | 
 |    used by the <<bfd_cache_lookup>> macro in @file{libbfd.h} to | 
 |    determine when it can avoid a function call.  */ | 
 |  | 
 | static bfd *bfd_last_cache = NULL; | 
 |  | 
 | /* Insert a BFD into the cache.  */ | 
 |  | 
 | static void | 
 | insert (bfd *abfd) | 
 | { | 
 |   if (bfd_last_cache == NULL) | 
 |     { | 
 |       abfd->lru_next = abfd; | 
 |       abfd->lru_prev = abfd; | 
 |     } | 
 |   else | 
 |     { | 
 |       abfd->lru_next = bfd_last_cache; | 
 |       abfd->lru_prev = bfd_last_cache->lru_prev; | 
 |       abfd->lru_prev->lru_next = abfd; | 
 |       abfd->lru_next->lru_prev = abfd; | 
 |     } | 
 |   bfd_last_cache = abfd; | 
 | } | 
 |  | 
 | /* Remove a BFD from the cache.  */ | 
 |  | 
 | static void | 
 | snip (bfd *abfd) | 
 | { | 
 |   abfd->lru_prev->lru_next = abfd->lru_next; | 
 |   abfd->lru_next->lru_prev = abfd->lru_prev; | 
 |   if (abfd == bfd_last_cache) | 
 |     { | 
 |       bfd_last_cache = abfd->lru_next; | 
 |       if (abfd == bfd_last_cache) | 
 | 	bfd_last_cache = NULL; | 
 |     } | 
 | } | 
 |  | 
 | /* Close a BFD and remove it from the cache.  */ | 
 |  | 
 | static bool | 
 | bfd_cache_delete (bfd *abfd) | 
 | { | 
 |   bool ret; | 
 |  | 
 |   if (fclose ((FILE *) abfd->iostream) == 0) | 
 |     ret = true; | 
 |   else | 
 |     { | 
 |       ret = false; | 
 |       bfd_set_error (bfd_error_system_call); | 
 |     } | 
 |  | 
 |   snip (abfd); | 
 |  | 
 |   abfd->iostream = NULL; | 
 |   BFD_ASSERT (open_files > 0); | 
 |   --open_files; | 
 |   abfd->flags |= BFD_CLOSED_BY_CACHE; | 
 |  | 
 |   return ret; | 
 | } | 
 |  | 
 | /* We need to open a new file, and the cache is full.  Find the least | 
 |    recently used cacheable BFD and close it.  */ | 
 |  | 
 | static bool | 
 | close_one (void) | 
 | { | 
 |   register bfd *to_kill; | 
 |  | 
 |   if (bfd_last_cache == NULL) | 
 |     to_kill = NULL; | 
 |   else | 
 |     { | 
 |       for (to_kill = bfd_last_cache->lru_prev; | 
 | 	   ! to_kill->cacheable; | 
 | 	   to_kill = to_kill->lru_prev) | 
 | 	{ | 
 | 	  if (to_kill == bfd_last_cache) | 
 | 	    { | 
 | 	      to_kill = NULL; | 
 | 	      break; | 
 | 	    } | 
 | 	} | 
 |     } | 
 |  | 
 |   if (to_kill == NULL) | 
 |     { | 
 |       /* There are no open cacheable BFD's.  */ | 
 |       return true; | 
 |     } | 
 |  | 
 |   to_kill->where = _bfd_real_ftell ((FILE *) to_kill->iostream); | 
 |  | 
 |   return bfd_cache_delete (to_kill); | 
 | } | 
 |  | 
 | /* Check to see if the required BFD is the same as the last one | 
 |    looked up. If so, then it can use the stream in the BFD with | 
 |    impunity, since it can't have changed since the last lookup; | 
 |    otherwise, it has to perform the complicated lookup function.  */ | 
 |  | 
 | #define bfd_cache_lookup(x, flag) \ | 
 |   ((x) == bfd_last_cache			\ | 
 |    ? (FILE *) (bfd_last_cache->iostream)	\ | 
 |    : bfd_cache_lookup_worker (x, flag)) | 
 |  | 
 | /* A helper function that returns true if ABFD can possibly be cached | 
 |    -- that is, whether bfd_cache_lookup_worker will accept it.  */ | 
 |  | 
 | static bool | 
 | possibly_cached (bfd *abfd) | 
 | { | 
 |   if ((abfd->flags & BFD_IN_MEMORY) != 0) | 
 |     return false; | 
 |   if (abfd->my_archive != NULL | 
 |       && !bfd_is_thin_archive (abfd->my_archive)) | 
 |     return false; | 
 |   return true; | 
 | } | 
 |  | 
 | /* Called when the macro <<bfd_cache_lookup>> fails to find a | 
 |    quick answer.  Find a file descriptor for @var{abfd}.  If | 
 |    necessary, it open it.  If there are already more than | 
 |    <<bfd_cache_max_open>> files open, it tries to close one first, to | 
 |    avoid running out of file descriptors.  It will return NULL | 
 |    if it is unable to (re)open the @var{abfd}.  */ | 
 |  | 
 | static FILE * | 
 | bfd_cache_lookup_worker (bfd *abfd, enum cache_flag flag) | 
 | { | 
 |   if (!possibly_cached (abfd)) | 
 |     abort (); | 
 |  | 
 |   /* If the BFD is being processed by bfd_check_format_matches, it | 
 |      must already be open and won't be on the list.  */ | 
 |   if (abfd->in_format_matches) | 
 |     { | 
 |       if (abfd->iostream == NULL) | 
 | 	abort (); | 
 |       return (FILE *) abfd->iostream; | 
 |     } | 
 |  | 
 |   if (abfd->iostream != NULL) | 
 |     { | 
 |       /* Move the file to the start of the cache.  */ | 
 |       if (abfd != bfd_last_cache) | 
 | 	{ | 
 | 	  snip (abfd); | 
 | 	  insert (abfd); | 
 | 	} | 
 |       return (FILE *) abfd->iostream; | 
 |     } | 
 |  | 
 |   if (flag & CACHE_NO_OPEN) | 
 |     return NULL; | 
 |  | 
 |   if (_bfd_open_file_unlocked (abfd) == NULL) | 
 |     ; | 
 |   else if (!(flag & CACHE_NO_SEEK) | 
 | 	   && _bfd_real_fseek ((FILE *) abfd->iostream, | 
 | 			       abfd->where, SEEK_SET) != 0 | 
 | 	   && !(flag & CACHE_NO_SEEK_ERROR)) | 
 |     bfd_set_error (bfd_error_system_call); | 
 |   else | 
 |     return (FILE *) abfd->iostream; | 
 |  | 
 |   /* xgettext:c-format */ | 
 |   _bfd_error_handler (_("reopening %pB: %s"), | 
 | 		      abfd, bfd_errmsg (bfd_get_error ())); | 
 |   return NULL; | 
 | } | 
 |  | 
 | static file_ptr | 
 | cache_btell (struct bfd *abfd) | 
 | { | 
 |   if (!bfd_lock ()) | 
 |     return -1; | 
 |   FILE *f = bfd_cache_lookup (abfd, CACHE_NO_OPEN); | 
 |   if (f == NULL) | 
 |     { | 
 |       if (!bfd_unlock ()) | 
 | 	return -1; | 
 |       return abfd->where; | 
 |     } | 
 |   file_ptr result = _bfd_real_ftell (f); | 
 |   if (!bfd_unlock ()) | 
 |     return -1; | 
 |   return result; | 
 | } | 
 |  | 
 | static int | 
 | cache_bseek (struct bfd *abfd, file_ptr offset, int whence) | 
 | { | 
 |   if (!bfd_lock ()) | 
 |     return -1; | 
 |   FILE *f = bfd_cache_lookup (abfd, whence != SEEK_CUR ? CACHE_NO_SEEK : CACHE_NORMAL); | 
 |   if (f == NULL) | 
 |     { | 
 |       bfd_unlock (); | 
 |       return -1; | 
 |     } | 
 |   int result = _bfd_real_fseek (f, offset, whence); | 
 |   if (!bfd_unlock ()) | 
 |     return -1; | 
 |   return result; | 
 | } | 
 |  | 
 | /* Note that archive entries don't have streams; they share their parent's. | 
 |    This allows someone to play with the iostream behind BFD's back. | 
 |  | 
 |    Also, note that the origin pointer points to the beginning of a file's | 
 |    contents (0 for non-archive elements).  For archive entries this is the | 
 |    first octet in the file, NOT the beginning of the archive header.  */ | 
 |  | 
 | static file_ptr | 
 | cache_bread_1 (FILE *f, void *buf, file_ptr nbytes) | 
 | { | 
 |   file_ptr nread; | 
 |  | 
 | #if defined (__VAX) && defined (VMS) | 
 |   /* Apparently fread on Vax VMS does not keep the record length | 
 |      information.  */ | 
 |   nread = read (fileno (f), buf, nbytes); | 
 |   /* Set bfd_error if we did not read as much data as we expected.  If | 
 |      the read failed due to an error set the bfd_error_system_call, | 
 |      else set bfd_error_file_truncated.  */ | 
 |   if (nread == (file_ptr)-1) | 
 |     { | 
 |       bfd_set_error (bfd_error_system_call); | 
 |       return nread; | 
 |     } | 
 | #else | 
 |   nread = fread (buf, 1, nbytes, f); | 
 |   /* Set bfd_error if we did not read as much data as we expected.  If | 
 |      the read failed due to an error set the bfd_error_system_call, | 
 |      else set bfd_error_file_truncated.  */ | 
 |   if (nread < nbytes && ferror (f)) | 
 |     { | 
 |       bfd_set_error (bfd_error_system_call); | 
 |       return nread; | 
 |     } | 
 | #endif | 
 |   if (nread < nbytes) | 
 |     /* This may or may not be an error, but in case the calling code | 
 |        bails out because of it, set the right error code.  */ | 
 |     bfd_set_error (bfd_error_file_truncated); | 
 |   return nread; | 
 | } | 
 |  | 
 | static file_ptr | 
 | cache_bread (struct bfd *abfd, void *buf, file_ptr nbytes) | 
 | { | 
 |   if (!bfd_lock ()) | 
 |     return -1; | 
 |   file_ptr nread = 0; | 
 |   FILE *f; | 
 |  | 
 |   f = bfd_cache_lookup (abfd, CACHE_NORMAL); | 
 |   if (f == NULL) | 
 |     { | 
 |       bfd_unlock (); | 
 |       return -1; | 
 |     } | 
 |  | 
 |   /* Some filesystems are unable to handle reads that are too large | 
 |      (for instance, NetApp shares with oplocks turned off).  To avoid | 
 |      hitting this limitation, we read the buffer in chunks of 8MB max.  */ | 
 |   while (nread < nbytes) | 
 |     { | 
 |       const file_ptr max_chunk_size = 0x800000; | 
 |       file_ptr chunk_size = nbytes - nread; | 
 |       file_ptr chunk_nread; | 
 |  | 
 |       if (chunk_size > max_chunk_size) | 
 | 	chunk_size = max_chunk_size; | 
 |  | 
 |       chunk_nread = cache_bread_1 (f, (char *) buf + nread, chunk_size); | 
 |  | 
 |       /* Update the nread count. | 
 |  | 
 | 	 We just have to be careful of the case when cache_bread_1 returns | 
 | 	 a negative count:  If this is our first read, then set nread to | 
 | 	 that negative count in order to return that negative value to the | 
 | 	 caller.  Otherwise, don't add it to our total count, or we would | 
 | 	 end up returning a smaller number of bytes read than we actually | 
 | 	 did.  */ | 
 |       if (nread == 0 || chunk_nread > 0) | 
 | 	nread += chunk_nread; | 
 |  | 
 |       if (chunk_nread < chunk_size) | 
 | 	break; | 
 |     } | 
 |  | 
 |   if (!bfd_unlock ()) | 
 |     return -1; | 
 |   return nread; | 
 | } | 
 |  | 
 | static file_ptr | 
 | cache_bwrite (struct bfd *abfd, const void *from, file_ptr nbytes) | 
 | { | 
 |   if (!bfd_lock ()) | 
 |     return -1; | 
 |   file_ptr nwrite; | 
 |   FILE *f = bfd_cache_lookup (abfd, CACHE_NORMAL); | 
 |  | 
 |   if (f == NULL) | 
 |     { | 
 |       if (!bfd_unlock ()) | 
 | 	return -1; | 
 |       return 0; | 
 |     } | 
 |   nwrite = fwrite (from, 1, nbytes, f); | 
 |   if (nwrite < nbytes && ferror (f)) | 
 |     { | 
 |       bfd_set_error (bfd_error_system_call); | 
 |       bfd_unlock (); | 
 |       return -1; | 
 |     } | 
 |   if (!bfd_unlock ()) | 
 |     return -1; | 
 |   return nwrite; | 
 | } | 
 |  | 
 | static int | 
 | cache_bclose (struct bfd *abfd) | 
 | { | 
 |   /* No locking needed here, it's handled by the callee.  */ | 
 |   return bfd_cache_close (abfd) - 1; | 
 | } | 
 |  | 
 | static int | 
 | cache_bflush (struct bfd *abfd) | 
 | { | 
 |   if (!bfd_lock ()) | 
 |     return -1; | 
 |   int sts; | 
 |   FILE *f = bfd_cache_lookup (abfd, CACHE_NO_OPEN); | 
 |  | 
 |   if (f == NULL) | 
 |     { | 
 |       if (!bfd_unlock ()) | 
 | 	return -1; | 
 |       return 0; | 
 |     } | 
 |   sts = fflush (f); | 
 |   if (sts < 0) | 
 |     bfd_set_error (bfd_error_system_call); | 
 |   if (!bfd_unlock ()) | 
 |     return -1; | 
 |   return sts; | 
 | } | 
 |  | 
 | static int | 
 | cache_bstat (struct bfd *abfd, struct stat *sb) | 
 | { | 
 |   if (!bfd_lock ()) | 
 |     return -1; | 
 |   int sts; | 
 |   FILE *f = bfd_cache_lookup (abfd, CACHE_NO_SEEK_ERROR); | 
 |  | 
 |   if (f == NULL) | 
 |     { | 
 |       bfd_unlock (); | 
 |       return -1; | 
 |     } | 
 |   sts = fstat (fileno (f), sb); | 
 |   if (sts < 0) | 
 |     bfd_set_error (bfd_error_system_call); | 
 |   if (!bfd_unlock ()) | 
 |     return -1; | 
 |   return sts; | 
 | } | 
 |  | 
 | static void * | 
 | cache_bmmap (struct bfd *abfd ATTRIBUTE_UNUSED, | 
 | 	     void *addr ATTRIBUTE_UNUSED, | 
 | 	     size_t len ATTRIBUTE_UNUSED, | 
 | 	     int prot ATTRIBUTE_UNUSED, | 
 | 	     int flags ATTRIBUTE_UNUSED, | 
 | 	     file_ptr offset ATTRIBUTE_UNUSED, | 
 | 	     void **map_addr ATTRIBUTE_UNUSED, | 
 | 	     size_t *map_len ATTRIBUTE_UNUSED) | 
 | { | 
 |   void *ret = MAP_FAILED; | 
 |  | 
 |   if (!bfd_lock ()) | 
 |     return ret; | 
 |   if ((abfd->flags & BFD_IN_MEMORY) != 0) | 
 |     abort (); | 
 | #ifdef HAVE_MMAP | 
 |   else | 
 |     { | 
 |       uintptr_t pagesize_m1 = _bfd_pagesize_m1; | 
 |       FILE *f; | 
 |       file_ptr pg_offset; | 
 |       size_t pg_len; | 
 |  | 
 |       f = bfd_cache_lookup (abfd, CACHE_NO_SEEK_ERROR); | 
 |       if (f == NULL) | 
 | 	{ | 
 | 	  bfd_unlock (); | 
 | 	  return ret; | 
 | 	} | 
 |  | 
 |       /* Align.  */ | 
 |       pg_offset = offset & ~pagesize_m1; | 
 |       pg_len = (len + (offset - pg_offset) + pagesize_m1) & ~pagesize_m1; | 
 |  | 
 |       ret = mmap (addr, pg_len, prot, flags, fileno (f), pg_offset); | 
 |       if (ret == MAP_FAILED) | 
 | 	bfd_set_error (bfd_error_system_call); | 
 |       else | 
 | 	{ | 
 | 	  *map_addr = ret; | 
 | 	  *map_len = pg_len; | 
 | 	  ret = (char *) ret + (offset & pagesize_m1); | 
 | 	} | 
 |     } | 
 | #endif | 
 |  | 
 |   if (!bfd_unlock ()) | 
 |     return MAP_FAILED; | 
 |   return ret; | 
 | } | 
 |  | 
 | static const struct bfd_iovec cache_iovec = | 
 | { | 
 |   &cache_bread, &cache_bwrite, &cache_btell, &cache_bseek, | 
 |   &cache_bclose, &cache_bflush, &cache_bstat, &cache_bmmap | 
 | }; | 
 |  | 
 | static bool | 
 | _bfd_cache_init_unlocked (bfd *abfd) | 
 | { | 
 |   BFD_ASSERT (abfd->iostream != NULL); | 
 |   if (open_files >= bfd_cache_max_open ()) | 
 |     { | 
 |       if (! close_one ()) | 
 | 	return false; | 
 |     } | 
 |   abfd->iovec = &cache_iovec; | 
 |   insert (abfd); | 
 |   abfd->flags &= ~BFD_CLOSED_BY_CACHE; | 
 |   ++open_files; | 
 |   return true; | 
 | } | 
 |  | 
 | /* | 
 | INTERNAL_FUNCTION | 
 | 	bfd_cache_init | 
 |  | 
 | SYNOPSIS | 
 | 	bool bfd_cache_init (bfd *abfd); | 
 |  | 
 | DESCRIPTION | 
 | 	Add a newly opened BFD to the cache. | 
 | */ | 
 |  | 
 | bool | 
 | bfd_cache_init (bfd *abfd) | 
 | { | 
 |   if (!bfd_lock ()) | 
 |     return false; | 
 |   bool result = _bfd_cache_init_unlocked (abfd); | 
 |   if (!bfd_unlock ()) | 
 |     return false; | 
 |   return result; | 
 | } | 
 |  | 
 | static bool | 
 | _bfd_cache_close_unlocked (bfd *abfd) | 
 | { | 
 |   /* Don't remove this test.  bfd_reinit depends on it.  */ | 
 |   if (abfd->iovec != &cache_iovec) | 
 |     return true; | 
 |  | 
 |   if (abfd->iostream == NULL) | 
 |     /* Previously closed.  */ | 
 |     return true; | 
 |  | 
 |   /* Note: no locking needed in this function, as it is handled by | 
 |      bfd_cache_delete.  */ | 
 |   return bfd_cache_delete (abfd); | 
 | } | 
 |  | 
 | /* | 
 | FUNCTION | 
 | 	bfd_cache_close | 
 |  | 
 | SYNOPSIS | 
 | 	bool bfd_cache_close (bfd *abfd); | 
 |  | 
 | DESCRIPTION | 
 | 	Remove the BFD @var{abfd} from the cache. If the attached file is open, | 
 | 	then close it too. | 
 |  | 
 | 	<<FALSE>> is returned if closing the file fails, <<TRUE>> is | 
 | 	returned if all is well. | 
 | */ | 
 |  | 
 | bool | 
 | bfd_cache_close (bfd *abfd) | 
 | { | 
 |   if (!bfd_lock ()) | 
 |     return false; | 
 |   bool result = _bfd_cache_close_unlocked (abfd); | 
 |   if (!bfd_unlock ()) | 
 |     return false; | 
 |   return result; | 
 | } | 
 |  | 
 | /* | 
 | FUNCTION | 
 | 	bfd_cache_close_all | 
 |  | 
 | SYNOPSIS | 
 | 	bool bfd_cache_close_all (void); | 
 |  | 
 | DESCRIPTION | 
 | 	Remove all BFDs from the cache. If the attached file is open, | 
 | 	then close it too.  Note - despite its name this function will | 
 | 	close a BFD even if it is not marked as being cacheable, ie | 
 | 	even if bfd_get_cacheable() returns false. | 
 |  | 
 | 	<<FALSE>> is returned if closing one of the file fails, <<TRUE>> is | 
 | 	returned if all is well. | 
 | */ | 
 |  | 
 | bool | 
 | bfd_cache_close_all (void) | 
 | { | 
 |   bool ret = true; | 
 |  | 
 |   if (!bfd_lock ()) | 
 |     return false; | 
 |   while (bfd_last_cache != NULL) | 
 |     { | 
 |       bfd *prev_bfd_last_cache = bfd_last_cache; | 
 |  | 
 |       ret &= _bfd_cache_close_unlocked (bfd_last_cache); | 
 |  | 
 |       /* Stop a potential infinite loop should bfd_cache_close() | 
 | 	 not update bfd_last_cache.  */ | 
 |       if (bfd_last_cache == prev_bfd_last_cache) | 
 | 	break; | 
 |     } | 
 |  | 
 |   if (!bfd_unlock ()) | 
 |     return false; | 
 |   return ret; | 
 | } | 
 |  | 
 | /* | 
 | INTERNAL_FUNCTION | 
 | 	bfd_cache_set_uncloseable | 
 |  | 
 | SYNOPSIS | 
 | 	bool bfd_cache_set_uncloseable (bfd *abfd, bool value, bool *old); | 
 |  | 
 | DESCRIPTION | 
 | 	Internal function to mark ABFD as either closeable or not. | 
 | 	This is used by bfd_check_format_matches to avoid races | 
 | 	where bfd_cache_close_all is called in another thread. | 
 | 	VALUE is true to mark the BFD as temporarily uncloseable | 
 | 	by the cache; false to mark it as closeable once again. | 
 | 	OLD, if non-NULL, is set to the previous value of the flag. | 
 | 	Returns false on error, true on success. | 
 | */ | 
 |  | 
 | bool | 
 | bfd_cache_set_uncloseable (bfd *abfd, bool value, bool *old) | 
 | { | 
 |   bool result = true; | 
 |  | 
 |   if (!bfd_lock ()) | 
 |     return false; | 
 |   if (old != NULL) | 
 |     *old = abfd->in_format_matches; | 
 |  | 
 |   /* Only perform any action when the state changes,and only when this | 
 |      BFD is actually using the cache.  */ | 
 |   if (value != abfd->in_format_matches | 
 |       && abfd->iovec == &cache_iovec | 
 |       && possibly_cached (abfd)) | 
 |     { | 
 |       if (value) | 
 | 	{ | 
 | 	  /* Marking as uncloseable for the first time.  Ensure the | 
 | 	     file is open, and remove from the cache list.  */ | 
 | 	  FILE *f = bfd_cache_lookup (abfd, CACHE_NORMAL); | 
 | 	  if (f == NULL) | 
 | 	    result = false; | 
 | 	  else | 
 | 	    snip (abfd); | 
 | 	} | 
 |       else | 
 | 	{ | 
 | 	  /* Mark as closeable again.  */ | 
 | 	  insert (abfd); | 
 | 	} | 
 |  | 
 |       abfd->in_format_matches = value; | 
 |     } | 
 |  | 
 |   if (!bfd_unlock ()) | 
 |     return false; | 
 |   return result; | 
 | } | 
 |  | 
 | /* | 
 | FUNCTION | 
 | 	bfd_cache_size | 
 |  | 
 | SYNOPSIS | 
 | 	unsigned bfd_cache_size (void); | 
 |  | 
 | DESCRIPTION | 
 | 	Return the number of open files in the cache. | 
 | */ | 
 |  | 
 | unsigned | 
 | bfd_cache_size (void) | 
 | { | 
 |   return open_files; | 
 | } | 
 |  | 
 | static FILE * | 
 | _bfd_open_file_unlocked (bfd *abfd) | 
 | { | 
 |   abfd->cacheable = true;	/* Allow it to be closed later.  */ | 
 |  | 
 |   if (open_files >= bfd_cache_max_open ()) | 
 |     { | 
 |       if (! close_one ()) | 
 | 	return NULL; | 
 |     } | 
 |  | 
 |   switch (abfd->direction) | 
 |     { | 
 |     case read_direction: | 
 |     case no_direction: | 
 |       abfd->iostream = _bfd_real_fopen (bfd_get_filename (abfd), FOPEN_RB); | 
 |       break; | 
 |     case both_direction: | 
 |     case write_direction: | 
 |       if (abfd->opened_once) | 
 | 	{ | 
 | 	  abfd->iostream = _bfd_real_fopen (bfd_get_filename (abfd), | 
 | 					    FOPEN_RUB); | 
 | 	  if (abfd->iostream == NULL) | 
 | 	    abfd->iostream = _bfd_real_fopen (bfd_get_filename (abfd), | 
 | 					      FOPEN_WUB); | 
 | 	} | 
 |       else | 
 | 	{ | 
 | 	  /* Create the file. | 
 |  | 
 | 	     Some operating systems won't let us overwrite a running | 
 | 	     binary.  For them, we want to unlink the file first. | 
 |  | 
 | 	     However, gcc 2.95 will create temporary files using | 
 | 	     O_EXCL and tight permissions to prevent other users from | 
 | 	     substituting other .o files during the compilation.  gcc | 
 | 	     will then tell the assembler to use the newly created | 
 | 	     file as an output file.  If we unlink the file here, we | 
 | 	     open a brief window when another user could still | 
 | 	     substitute a file. | 
 |  | 
 | 	     So we unlink the output file if and only if it has | 
 | 	     non-zero size.  */ | 
 | #ifndef __MSDOS__ | 
 | 	  /* Don't do this for MSDOS: it doesn't care about overwriting | 
 | 	     a running binary, but if this file is already open by | 
 | 	     another BFD, we will be in deep trouble if we delete an | 
 | 	     open file.  In fact, objdump does just that if invoked with | 
 | 	     the --info option.  */ | 
 | 	  struct stat s; | 
 |  | 
 | 	  if (stat (bfd_get_filename (abfd), &s) == 0 && s.st_size != 0) | 
 | 	    unlink_if_ordinary (bfd_get_filename (abfd)); | 
 | #endif | 
 | 	  abfd->iostream = _bfd_real_fopen (bfd_get_filename (abfd), | 
 | 					    FOPEN_WUB); | 
 | 	  abfd->opened_once = true; | 
 | 	} | 
 |       break; | 
 |     } | 
 |  | 
 |   if (abfd->iostream == NULL) | 
 |     bfd_set_error (bfd_error_system_call); | 
 |   else | 
 |     { | 
 |       if (! _bfd_cache_init_unlocked (abfd)) | 
 | 	return NULL; | 
 |     } | 
 |  | 
 |   return (FILE *) abfd->iostream; | 
 | } | 
 |  | 
 | /* | 
 | INTERNAL_FUNCTION | 
 | 	bfd_open_file | 
 |  | 
 | SYNOPSIS | 
 | 	FILE* bfd_open_file (bfd *abfd); | 
 |  | 
 | DESCRIPTION | 
 | 	Call the OS to open a file for @var{abfd}.  Return the <<FILE *>> | 
 | 	(possibly <<NULL>>) that results from this operation.  Set up the | 
 | 	BFD so that future accesses know the file is open. If the <<FILE *>> | 
 | 	returned is <<NULL>>, then it won't have been put in the | 
 | 	cache, so it won't have to be removed from it. | 
 | */ | 
 |  | 
 | FILE * | 
 | bfd_open_file (bfd *abfd) | 
 | { | 
 |   if (!bfd_lock ()) | 
 |     return NULL; | 
 |   FILE *result = _bfd_open_file_unlocked (abfd); | 
 |   if (!bfd_unlock ()) | 
 |     return NULL; | 
 |   return result; | 
 | } |