/* BFD library -- caching of file descriptors.
- Copyright 1990, 91, 92, 93, 94, 95, 1996, 2000, 2001
- Free Software Foundation, Inc.
+
+ Copyright 1990, 1991, 1992, 1993, 1994, 1996, 2000, 2001, 2002,
+ 2003, 2004 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.
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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
+Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA. */
/*
SECTION
close, closes it and opens the one wanted, returning its file
handle.
+SUBSECTION
+ Caching functions
*/
#include "bfd.h"
#include "sysdep.h"
#include "libbfd.h"
+#include "libiberty.h"
+
+static bfd_boolean bfd_cache_delete (bfd *);
+
-static void insert PARAMS ((bfd *));
-static void snip PARAMS ((bfd *));
-static boolean close_one PARAMS ((void));
-static boolean bfd_cache_delete PARAMS ((bfd *));
+static file_ptr
+cache_btell (struct bfd *abfd)
+{
+ return real_ftell (bfd_cache_lookup (abfd));
+}
+
+static int
+cache_bseek (struct bfd *abfd, file_ptr offset, int whence)
+{
+ return real_fseek (bfd_cache_lookup (abfd), offset, whence);
+}
+
+/* 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 (struct bfd *abfd, void *buf, file_ptr nbytes)
+{
+ file_ptr nread;
+ /* FIXME - this looks like an optimization, but it's really to cover
+ up for a feature of some OSs (not solaris - sigh) that
+ ld/pe-dll.c takes advantage of (apparently) when it creates BFDs
+ internally and tries to link against them. BFD seems to be smart
+ enough to realize there are no symbol records in the "file" that
+ doesn't exist but attempts to read them anyway. On Solaris,
+ attempting to read zero bytes from a NULL file results in a core
+ dump, but on other platforms it just returns zero bytes read.
+ This makes it to something reasonable. - DJ */
+ if (nbytes == 0)
+ return 0;
+
+#if defined (__VAX) && defined (VMS)
+ /* Apparently fread on Vax VMS does not keep the record length
+ information. */
+ nread = read (fileno (bfd_cache_lookup (abfd)), 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 -1;
+ }
+#else
+ nread = fread (buf, 1, nbytes, bfd_cache_lookup (abfd));
+ /* 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 (bfd_cache_lookup (abfd)))
+ {
+ bfd_set_error (bfd_error_system_call);
+ return -1;
+ }
+#endif
+ return nread;
+}
+
+static file_ptr
+cache_bwrite (struct bfd *abfd, const void *where, file_ptr nbytes)
+{
+ file_ptr nwrite = fwrite (where, 1, nbytes, bfd_cache_lookup (abfd));
+ if (nwrite < nbytes && ferror (bfd_cache_lookup (abfd)))
+ {
+ bfd_set_error (bfd_error_system_call);
+ return -1;
+ }
+ return nwrite;
+}
+
+static int
+cache_bclose (struct bfd *abfd)
+{
+ return bfd_cache_close (abfd);
+}
+
+static int
+cache_bflush (struct bfd *abfd)
+{
+ int sts = fflush (bfd_cache_lookup (abfd));
+ if (sts < 0)
+ bfd_set_error (bfd_error_system_call);
+ return sts;
+}
+
+static int
+cache_bstat (struct bfd *abfd, struct stat *sb)
+{
+ int sts = fstat (fileno (bfd_cache_lookup (abfd)), sb);
+ if (sts < 0)
+ bfd_set_error (bfd_error_system_call);
+ return sts;
+}
+
+static const struct bfd_iovec cache_iovec = {
+ &cache_bread, &cache_bwrite, &cache_btell, &cache_bseek,
+ &cache_bclose, &cache_bflush, &cache_bstat
+};
/*
INTERNAL_FUNCTION
determine when it can avoid a function call.
*/
-bfd *bfd_last_cache;
+bfd *bfd_last_cache = NULL;
/*
INTERNAL_FUNCTION
otherwise, it has to perform the complicated lookup function.
.#define bfd_cache_lookup(x) \
- . ((x)==bfd_last_cache? \
- . (FILE*) (bfd_last_cache->iostream): \
- . bfd_cache_lookup_worker(x))
+ . ((x) == bfd_last_cache ? \
+ . (FILE *) (bfd_last_cache->iostream): \
+ . bfd_cache_lookup_worker (x))
*/
/* Insert a BFD into the cache. */
-static INLINE void
-insert (abfd)
- bfd *abfd;
+static void
+insert (bfd *abfd)
{
if (bfd_last_cache == NULL)
{
/* Remove a BFD from the cache. */
-static INLINE void
-snip (abfd)
- bfd *abfd;
+static void
+snip (bfd *abfd)
{
abfd->lru_prev->lru_next = abfd->lru_next;
abfd->lru_next->lru_prev = abfd->lru_prev;
/* We need to open a new file, and the cache is full. Find the least
recently used cacheable BFD and close it. */
-static boolean
-close_one ()
+static bfd_boolean
+close_one (void)
{
register bfd *kill;
if (kill == NULL)
{
/* There are no open cacheable BFD's. */
- return true;
+ return TRUE;
}
- kill->where = ftell ((FILE *) kill->iostream);
+ kill->where = real_ftell ((FILE *) kill->iostream);
return bfd_cache_delete (kill);
}
/* Close a BFD and remove it from the cache. */
-static boolean
-bfd_cache_delete (abfd)
- bfd *abfd;
+static bfd_boolean
+bfd_cache_delete (bfd *abfd)
{
- boolean ret;
+ bfd_boolean ret;
if (fclose ((FILE *) abfd->iostream) == 0)
- ret = true;
+ ret = TRUE;
else
{
- ret = false;
+ ret = FALSE;
bfd_set_error (bfd_error_system_call);
}
bfd_cache_init
SYNOPSIS
- boolean bfd_cache_init (bfd *abfd);
+ bfd_boolean bfd_cache_init (bfd *abfd);
DESCRIPTION
Add a newly opened BFD to the cache.
*/
-boolean
-bfd_cache_init (abfd)
- bfd *abfd;
+bfd_boolean
+bfd_cache_init (bfd *abfd)
{
BFD_ASSERT (abfd->iostream != NULL);
if (open_files >= BFD_CACHE_MAX_OPEN)
{
if (! close_one ())
- return false;
+ return FALSE;
}
+ abfd->iovec = &cache_iovec;
insert (abfd);
++open_files;
- return true;
+ return TRUE;
}
/*
bfd_cache_close
SYNOPSIS
- boolean bfd_cache_close (bfd *abfd);
+ bfd_boolean bfd_cache_close (bfd *abfd);
DESCRIPTION
Remove the BFD @var{abfd} from the cache. If the attached file is open,
then close it too.
RETURNS
- <<false>> is returned if closing the file fails, <<true>> is
+ <<FALSE>> is returned if closing the file fails, <<TRUE>> is
returned if all is well.
*/
-boolean
-bfd_cache_close (abfd)
- bfd *abfd;
+bfd_boolean
+bfd_cache_close (bfd *abfd)
{
- if (abfd->iostream == NULL
- || (abfd->flags & BFD_IN_MEMORY) != 0)
- return true;
+ if (abfd->iovec != &cache_iovec)
+ return TRUE;
+
+ if (abfd->iostream == NULL)
+ /* Previously closed. */
+ return TRUE;
return bfd_cache_delete (abfd);
}
+/*
+FUNCTION
+ bfd_cache_close_all
+
+SYNOPSIS
+ bfd_boolean bfd_cache_close_all (void);
+
+DESCRIPTION
+ Remove all BFDs from the cache. If the attached file is open,
+ then close it too.
+
+RETURNS
+ <<FALSE>> is returned if closing one of the file fails, <<TRUE>> is
+ returned if all is well.
+*/
+
+bfd_boolean
+bfd_cache_close_all ()
+{
+ bfd_boolean ret = TRUE;
+
+ while (bfd_last_cache != NULL)
+ ret &= bfd_cache_close (bfd_last_cache);
+
+ return ret;
+}
+
/*
INTERNAL_FUNCTION
bfd_open_file
SYNOPSIS
- FILE* bfd_open_file(bfd *abfd);
+ FILE* bfd_open_file (bfd *abfd);
DESCRIPTION
Call the OS to open a file for @var{abfd}. Return the <<FILE *>>
*/
FILE *
-bfd_open_file (abfd)
- bfd *abfd;
+bfd_open_file (bfd *abfd)
{
- abfd->cacheable = true; /* Allow it to be closed later. */
+ abfd->cacheable = TRUE; /* Allow it to be closed later. */
if (open_files >= BFD_CACHE_MAX_OPEN)
{
break;
case both_direction:
case write_direction:
- if (abfd->opened_once == true)
+ if (abfd->opened_once)
{
abfd->iostream = (PTR) fopen (abfd->filename, FOPEN_RUB);
if (abfd->iostream == NULL)
struct stat s;
if (stat (abfd->filename, &s) == 0 && s.st_size != 0)
- unlink (abfd->filename);
+ unlink_if_ordinary (abfd->filename);
#endif
abfd->iostream = (PTR) fopen (abfd->filename, FOPEN_WUB);
- abfd->opened_once = true;
+ abfd->opened_once = TRUE;
}
break;
}
bfd_cache_lookup_worker
SYNOPSIS
- FILE *bfd_cache_lookup_worker(bfd *abfd);
+ FILE *bfd_cache_lookup_worker (bfd *abfd);
DESCRIPTION
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.
+ avoid running out of file descriptors. It will abort rather than
+ returning NULL if it is unable to (re)open the @var{abfd}.
*/
FILE *
-bfd_cache_lookup_worker (abfd)
- bfd *abfd;
+bfd_cache_lookup_worker (bfd *abfd)
{
if ((abfd->flags & BFD_IN_MEMORY) != 0)
abort ();
}
else
{
- if (bfd_open_file (abfd) == NULL)
- return NULL;
- if (fseek ((FILE *) abfd->iostream, abfd->where, SEEK_SET) != 0)
- return NULL;
+ if (bfd_open_file (abfd) == NULL
+ || abfd->where != (unsigned long) abfd->where
+ || real_fseek ((FILE *) abfd->iostream, abfd->where, SEEK_SET) != 0)
+ abort ();
}
return (FILE *) abfd->iostream;