2004-04-21 Andrew Cagney <cagney@redhat.com>
* opncls.c (_bfd_new_bfd_contained_in): Copy "iovec". (struct opncls, opncls_btell, opncls_bseek, opncls_bread) (opncls_bwrite, opncls_bclose, opncls_bflush) (opncls_bstat, opncls_iovec, bfd_openr_iovec): Implement a bfd iovec that uses function callbacks. (bfd_close): Use the iovec's bclose. * cache.c (cache_btell, cache_bseek, cache_bread, cache_bwrite) (cache_bclose, cache_bflush, cache_bstat) (cache_iovec): New functions and global variable, implement a cache "iovec", where applicable set bfd_error. (bfd_cache_init, bfd_cache_close): Set/test the bfd's iovec. * bfdio.c (struct bfd_iovec): Define. (real_read): Delete function. (bfd_bread, bfd_bread, bfd_bwrite, bfd_tell, bfd_flush, bfd_stat) (bfd_seek, bfd_get_mtime, bfd_get_size): Use the bfd's "iovec", assume that bread and bwrite set bfd_error. * bfd.c (struct bfd): Add "iovec", update comments. * bfd-in2.h, libbfd.h: Re-generate.
This commit is contained in:
parent
7f919c8471
commit
40838a725a
7 changed files with 388 additions and 80 deletions
|
@ -1,3 +1,24 @@
|
|||
2004-04-21 Andrew Cagney <cagney@redhat.com>
|
||||
|
||||
* opncls.c (_bfd_new_bfd_contained_in): Copy "iovec".
|
||||
(struct opncls, opncls_btell, opncls_bseek, opncls_bread)
|
||||
(opncls_bwrite, opncls_bclose, opncls_bflush)
|
||||
(opncls_bstat, opncls_iovec, bfd_openr_iovec): Implement a
|
||||
bfd iovec that uses function callbacks.
|
||||
(bfd_close): Use the iovec's bclose.
|
||||
* cache.c (cache_btell, cache_bseek, cache_bread, cache_bwrite)
|
||||
(cache_bclose, cache_bflush, cache_bstat)
|
||||
(cache_iovec): New functions and global variable, implement a
|
||||
cache "iovec", where applicable set bfd_error.
|
||||
(bfd_cache_init, bfd_cache_close): Set/test the bfd's iovec.
|
||||
* bfdio.c (struct bfd_iovec): Define.
|
||||
(real_read): Delete function.
|
||||
(bfd_bread, bfd_bread, bfd_bwrite, bfd_tell, bfd_flush, bfd_stat)
|
||||
(bfd_seek, bfd_get_mtime, bfd_get_size): Use the bfd's "iovec",
|
||||
assume that bread and bwrite set bfd_error.
|
||||
* bfd.c (struct bfd): Add "iovec", update comments.
|
||||
* bfd-in2.h, libbfd.h: Re-generate.
|
||||
|
||||
2004-04-21 Andrew Cagney <cagney@redhat.com>
|
||||
|
||||
* libaout.h (enum machine_type): Add M_POWERPC_NETBSD.
|
||||
|
|
|
@ -839,6 +839,18 @@ bfd *bfd_fdopenr (const char *filename, const char *target, int fd);
|
|||
|
||||
bfd *bfd_openstreamr (const char *, const char *, void *);
|
||||
|
||||
bfd *bfd_openr_iovec (const char *filename, const char *target,
|
||||
void *(*open) (struct bfd *nbfd,
|
||||
void *open_closure),
|
||||
void *open_closure,
|
||||
file_ptr (*pread) (struct bfd *nbfd,
|
||||
void *stream,
|
||||
void *buf,
|
||||
file_ptr nbytes,
|
||||
file_ptr offset),
|
||||
int (*close) (struct bfd *nbfd,
|
||||
void *stream));
|
||||
|
||||
bfd *bfd_openw (const char *filename, const char *target);
|
||||
|
||||
bfd_boolean bfd_close (bfd *abfd);
|
||||
|
@ -3708,14 +3720,10 @@ struct bfd
|
|||
/* A pointer to the target jump table. */
|
||||
const struct bfd_target *xvec;
|
||||
|
||||
/* To avoid dragging too many header files into every file that
|
||||
includes `<<bfd.h>>', IOSTREAM has been declared as a "char *",
|
||||
and MTIME as a "long". Their correct types, to which they
|
||||
are cast when used, are "FILE *" and "time_t". The iostream
|
||||
is the result of an fopen on the filename. However, if the
|
||||
BFD_IN_MEMORY flag is set, then iostream is actually a pointer
|
||||
to a bfd_in_memory struct. */
|
||||
/* The IOSTREAM, and corresponding IO vector that provide access
|
||||
to the file backing the BFD. */
|
||||
void *iostream;
|
||||
const struct bfd_iovec *iovec;
|
||||
|
||||
/* Is the file descriptor being cached? That is, can it be closed as
|
||||
needed, and re-opened when accessed later? */
|
||||
|
|
10
bfd/bfd.c
10
bfd/bfd.c
|
@ -45,14 +45,10 @@ CODE_FRAGMENT
|
|||
. {* A pointer to the target jump table. *}
|
||||
. const struct bfd_target *xvec;
|
||||
.
|
||||
. {* To avoid dragging too many header files into every file that
|
||||
. includes `<<bfd.h>>', IOSTREAM has been declared as a "char *",
|
||||
. and MTIME as a "long". Their correct types, to which they
|
||||
. are cast when used, are "FILE *" and "time_t". The iostream
|
||||
. is the result of an fopen on the filename. However, if the
|
||||
. BFD_IN_MEMORY flag is set, then iostream is actually a pointer
|
||||
. to a bfd_in_memory struct. *}
|
||||
. {* The IOSTREAM, and corresponding IO vector that provide access
|
||||
. to the file backing the BFD. *}
|
||||
. void *iostream;
|
||||
. const struct bfd_iovec *iovec;
|
||||
.
|
||||
. {* Is the file descriptor being cached? That is, can it be closed as
|
||||
. needed, and re-opened when accessed later? *}
|
||||
|
|
102
bfd/bfdio.c
102
bfd/bfdio.c
|
@ -62,37 +62,41 @@ real_fseek (FILE *file, file_ptr offset, int whence)
|
|||
#endif
|
||||
}
|
||||
|
||||
/* 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.
|
||||
/*
|
||||
INTERNAL_DEFINITION
|
||||
struct bfd_iovec
|
||||
|
||||
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. */
|
||||
DESCRIPTION
|
||||
|
||||
static size_t
|
||||
real_read (void *where, size_t a, size_t b, FILE *file)
|
||||
{
|
||||
/* 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 (a == 0 || b == 0)
|
||||
return 0;
|
||||
The <<struct bfd_iovec>> contains the internal file I/O class.
|
||||
Each <<BFD>> has an instance of this class and all file I/O is
|
||||
routed through it (it is assumed that the instance implements
|
||||
all methods listed below).
|
||||
|
||||
.struct bfd_iovec
|
||||
.{
|
||||
. {* To avoid problems with macros, a "b" rather than "f"
|
||||
. prefix is prepended to each method name. *}
|
||||
. {* Attempt to read/write NBYTES on ABFD's IOSTREAM storing/fetching
|
||||
. bytes starting at PTR. Return the number of bytes actually
|
||||
. transfered (a read past end-of-file returns less than NBYTES),
|
||||
. or -1 (setting <<bfd_error>>) if an error occurs. *}
|
||||
. file_ptr (*bread) (struct bfd *abfd, void *ptr, file_ptr nbytes);
|
||||
. file_ptr (*bwrite) (struct bfd *abfd, const void *ptr,
|
||||
. file_ptr nbytes);
|
||||
. {* Return the current IOSTREAM file offset, or -1 (setting <<bfd_error>>
|
||||
. if an error occurs. *}
|
||||
. file_ptr (*btell) (struct bfd *abfd);
|
||||
. {* For the following, on successful completion a value of 0 is returned.
|
||||
. Otherwise, a value of -1 is returned (and <<bfd_error>> is set). *}
|
||||
. int (*bseek) (struct bfd *abfd, file_ptr offset, int whence);
|
||||
. int (*bclose) (struct bfd *abfd);
|
||||
. int (*bflush) (struct bfd *abfd);
|
||||
. int (*bstat) (struct bfd *abfd, struct stat *sb);
|
||||
.};
|
||||
|
||||
*/
|
||||
|
||||
#if defined (__VAX) && defined (VMS)
|
||||
/* Apparently fread on Vax VMS does not keep the record length
|
||||
information. */
|
||||
return read (fileno (file), where, a * b);
|
||||
#else
|
||||
return fread (where, a, b, file);
|
||||
#endif
|
||||
}
|
||||
|
||||
/* Return value is amount read. */
|
||||
|
||||
|
@ -121,25 +125,10 @@ bfd_bread (void *ptr, bfd_size_type size, bfd *abfd)
|
|||
return get;
|
||||
}
|
||||
|
||||
nread = real_read (ptr, 1, (size_t) size, bfd_cache_lookup (abfd));
|
||||
nread = abfd->iovec->bread (abfd, ptr, size);
|
||||
if (nread != (size_t) -1)
|
||||
abfd->where += nread;
|
||||
|
||||
/* 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.
|
||||
|
||||
A BFD backend may wish to override bfd_error_file_truncated to
|
||||
provide something more useful (eg. no_symbols or wrong_format). */
|
||||
if (nread != size)
|
||||
{
|
||||
if (ferror (bfd_cache_lookup (abfd)))
|
||||
bfd_set_error (bfd_error_system_call);
|
||||
else
|
||||
bfd_set_error (bfd_error_file_truncated);
|
||||
}
|
||||
|
||||
return nread;
|
||||
}
|
||||
|
||||
|
@ -175,7 +164,7 @@ bfd_bwrite (const void *ptr, bfd_size_type size, bfd *abfd)
|
|||
return size;
|
||||
}
|
||||
|
||||
nwrote = fwrite (ptr, 1, (size_t) size, bfd_cache_lookup (abfd));
|
||||
nwrote = abfd->iovec->bwrite (abfd, ptr, size);
|
||||
if (nwrote != (size_t) -1)
|
||||
abfd->where += nwrote;
|
||||
if (nwrote != size)
|
||||
|
@ -196,7 +185,7 @@ bfd_tell (bfd *abfd)
|
|||
if ((abfd->flags & BFD_IN_MEMORY) != 0)
|
||||
return abfd->where;
|
||||
|
||||
ptr = real_ftell (bfd_cache_lookup (abfd));
|
||||
ptr = abfd->iovec->btell (abfd);
|
||||
|
||||
if (abfd->my_archive)
|
||||
ptr -= abfd->origin;
|
||||
|
@ -209,7 +198,7 @@ bfd_flush (bfd *abfd)
|
|||
{
|
||||
if ((abfd->flags & BFD_IN_MEMORY) != 0)
|
||||
return 0;
|
||||
return fflush (bfd_cache_lookup(abfd));
|
||||
return abfd->iovec->bflush (abfd);
|
||||
}
|
||||
|
||||
/* Returns 0 for success, negative value for failure (in which case
|
||||
|
@ -217,19 +206,12 @@ bfd_flush (bfd *abfd)
|
|||
int
|
||||
bfd_stat (bfd *abfd, struct stat *statbuf)
|
||||
{
|
||||
FILE *f;
|
||||
int result;
|
||||
|
||||
if ((abfd->flags & BFD_IN_MEMORY) != 0)
|
||||
abort ();
|
||||
|
||||
f = bfd_cache_lookup (abfd);
|
||||
if (f == NULL)
|
||||
{
|
||||
bfd_set_error (bfd_error_system_call);
|
||||
return -1;
|
||||
}
|
||||
result = fstat (fileno (f), statbuf);
|
||||
result = abfd->iovec->bstat (abfd, statbuf);
|
||||
if (result < 0)
|
||||
bfd_set_error (bfd_error_system_call);
|
||||
return result;
|
||||
|
@ -242,7 +224,6 @@ int
|
|||
bfd_seek (bfd *abfd, file_ptr position, int direction)
|
||||
{
|
||||
int result;
|
||||
FILE *f;
|
||||
file_ptr file_position;
|
||||
/* For the time being, a BFD may not seek to it's end. The problem
|
||||
is that we don't easily have a way to recognize the end of an
|
||||
|
@ -328,12 +309,11 @@ bfd_seek (bfd *abfd, file_ptr position, int direction)
|
|||
In the meantime, no optimization for archives. */
|
||||
}
|
||||
|
||||
f = bfd_cache_lookup (abfd);
|
||||
file_position = position;
|
||||
if (direction == SEEK_SET && abfd->my_archive != NULL)
|
||||
file_position += abfd->origin;
|
||||
|
||||
result = real_fseek (f, file_position, direction);
|
||||
result = abfd->iovec->bseek (abfd, file_position, direction);
|
||||
if (result != 0)
|
||||
{
|
||||
int hold_errno = errno;
|
||||
|
@ -378,14 +358,12 @@ DESCRIPTION
|
|||
long
|
||||
bfd_get_mtime (bfd *abfd)
|
||||
{
|
||||
FILE *fp;
|
||||
struct stat buf;
|
||||
|
||||
if (abfd->mtime_set)
|
||||
return abfd->mtime;
|
||||
|
||||
fp = bfd_cache_lookup (abfd);
|
||||
if (0 != fstat (fileno (fp), &buf))
|
||||
if (abfd->iovec->bstat (abfd, &buf) != 0)
|
||||
return 0;
|
||||
|
||||
abfd->mtime = buf.st_mtime; /* Save value in case anyone wants it */
|
||||
|
@ -428,14 +406,12 @@ DESCRIPTION
|
|||
long
|
||||
bfd_get_size (bfd *abfd)
|
||||
{
|
||||
FILE *fp;
|
||||
struct stat buf;
|
||||
|
||||
if ((abfd->flags & BFD_IN_MEMORY) != 0)
|
||||
return ((struct bfd_in_memory *) abfd->iostream)->size;
|
||||
|
||||
fp = bfd_cache_lookup (abfd);
|
||||
if (0 != fstat (fileno (fp), & buf))
|
||||
if (abfd->iovec->bstat (abfd, &buf) != 0)
|
||||
return 0;
|
||||
|
||||
return buf.st_size;
|
||||
|
|
107
bfd/cache.c
107
bfd/cache.c
|
@ -44,6 +44,109 @@ SECTION
|
|||
|
||||
static bfd_boolean bfd_cache_delete (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
|
||||
BFD_CACHE_MAX_OPEN macro
|
||||
|
@ -205,6 +308,7 @@ bfd_cache_init (bfd *abfd)
|
|||
if (! close_one ())
|
||||
return FALSE;
|
||||
}
|
||||
abfd->iovec = &cache_iovec;
|
||||
insert (abfd);
|
||||
++open_files;
|
||||
return TRUE;
|
||||
|
@ -229,8 +333,7 @@ RETURNS
|
|||
bfd_boolean
|
||||
bfd_cache_close (bfd *abfd)
|
||||
{
|
||||
if (abfd->iostream == NULL
|
||||
|| (abfd->flags & BFD_IN_MEMORY) != 0)
|
||||
if (abfd->iovec != &cache_iovec)
|
||||
return TRUE;
|
||||
|
||||
return bfd_cache_delete (abfd);
|
||||
|
|
21
bfd/libbfd.h
21
bfd/libbfd.h
|
@ -657,6 +657,27 @@ bfd_boolean bfd_write_bigendian_4byte_int (bfd *, unsigned int);
|
|||
unsigned int bfd_log2 (bfd_vma x);
|
||||
|
||||
/* Extracted from bfdio.c. */
|
||||
struct bfd_iovec
|
||||
{
|
||||
/* To avoid problems with macros, a "b" rather than "f"
|
||||
prefix is prepended to each method name. */
|
||||
/* Attempt to read/write NBYTES on ABFD's IOSTREAM storing/fetching
|
||||
bytes starting at PTR. Return the number of bytes actually
|
||||
transfered (a read past end-of-file returns less than NBYTES),
|
||||
or -1 (setting <<bfd_error>>) if an error occurs. */
|
||||
file_ptr (*bread) (struct bfd *abfd, void *ptr, file_ptr nbytes);
|
||||
file_ptr (*bwrite) (struct bfd *abfd, const void *ptr,
|
||||
file_ptr nbytes);
|
||||
/* Return the current IOSTREAM file offset, or -1 (setting <<bfd_error>>
|
||||
if an error occurs. */
|
||||
file_ptr (*btell) (struct bfd *abfd);
|
||||
/* For the following, on successful completion a value of 0 is returned.
|
||||
Otherwise, a value of -1 is returned (and <<bfd_error>> is set). */
|
||||
int (*bseek) (struct bfd *abfd, file_ptr offset, int whence);
|
||||
int (*bclose) (struct bfd *abfd);
|
||||
int (*bflush) (struct bfd *abfd);
|
||||
int (*bstat) (struct bfd *abfd, struct stat *sb);
|
||||
};
|
||||
/* Extracted from bfdwin.c. */
|
||||
struct _bfd_window_internal {
|
||||
struct _bfd_window_internal *next;
|
||||
|
|
185
bfd/opncls.c
185
bfd/opncls.c
|
@ -103,6 +103,7 @@ _bfd_new_bfd_contained_in (bfd *obfd)
|
|||
if (nbfd == NULL)
|
||||
return NULL;
|
||||
nbfd->xvec = obfd->xvec;
|
||||
nbfd->iovec = obfd->iovec;
|
||||
nbfd->my_archive = obfd;
|
||||
nbfd->direction = read_direction;
|
||||
nbfd->target_defaulted = obfd->target_defaulted;
|
||||
|
@ -322,6 +323,183 @@ bfd_openstreamr (const char *filename, const char *target, void *streamarg)
|
|||
|
||||
return nbfd;
|
||||
}
|
||||
|
||||
/*
|
||||
FUNCTION
|
||||
bfd_openr_iovec
|
||||
|
||||
SYNOPSIS
|
||||
bfd *bfd_openr_iovec (const char *filename, const char *target,
|
||||
void *(*open) (struct bfd *nbfd,
|
||||
void *open_closure),
|
||||
void *open_closure,
|
||||
file_ptr (*pread) (struct bfd *nbfd,
|
||||
void *stream,
|
||||
void *buf,
|
||||
file_ptr nbytes,
|
||||
file_ptr offset),
|
||||
int (*close) (struct bfd *nbfd,
|
||||
void *stream));
|
||||
|
||||
DESCRIPTION
|
||||
|
||||
Create and return a BFD backed by a read-only @var{stream}.
|
||||
The @var{stream} is created using @var{open}, accessed using
|
||||
@var{pread} and destroyed using @var{close}.
|
||||
|
||||
Calls <<bfd_find_target>>, so @var{target} is interpreted as by
|
||||
that function.
|
||||
|
||||
Calls @var{open} (which can call <<bfd_zalloc>> and
|
||||
<<bfd_get_filename>>) to obtain the read-only stream backing
|
||||
the BFD. @var{open} either succeeds returning the
|
||||
non-<<NULL>> @var{stream}, or fails returning <<NULL>>
|
||||
(setting <<bfd_error>>).
|
||||
|
||||
Calls @var{pread} to request @var{nbytes} of data from
|
||||
@var{stream} starting at @var{offset} (e.g., via a call to
|
||||
<<bfd_read>>). @var{pread} either succeeds returning the
|
||||
number of bytes read (which can be less than @var{nbytes} when
|
||||
end-of-file), or fails returning -1 (setting <<bfd_error>>).
|
||||
|
||||
Calls @var{close} when the BFD is later closed using
|
||||
<<bfd_close>>. @var{close} either succeeds returning 0, or
|
||||
fails returning -1 (setting <<bfd_error>>).
|
||||
|
||||
If <<bfd_openr_iovec>> returns <<NULL>> then an error has
|
||||
occurred. Possible errors are <<bfd_error_no_memory>>,
|
||||
<<bfd_error_invalid_target>> and <<bfd_error_system_call>>.
|
||||
|
||||
*/
|
||||
|
||||
struct opncls
|
||||
{
|
||||
void *stream;
|
||||
file_ptr (*pread) (struct bfd *abfd, void *stream, void *buf,
|
||||
file_ptr nbytes, file_ptr offset);
|
||||
int (*close) (struct bfd *abfd, void *stream);
|
||||
file_ptr where;
|
||||
};
|
||||
|
||||
static file_ptr
|
||||
opncls_btell (struct bfd *abfd)
|
||||
{
|
||||
struct opncls *vec = abfd->iostream;
|
||||
return vec->where;
|
||||
}
|
||||
|
||||
static int
|
||||
opncls_bseek (struct bfd *abfd, file_ptr offset, int whence)
|
||||
{
|
||||
struct opncls *vec = abfd->iostream;
|
||||
switch (whence)
|
||||
{
|
||||
case SEEK_SET: vec->where = offset; break;
|
||||
case SEEK_CUR: vec->where += offset; break;
|
||||
case SEEK_END: return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static file_ptr
|
||||
opncls_bread (struct bfd *abfd, void *buf, file_ptr nbytes)
|
||||
{
|
||||
struct opncls *vec = abfd->iostream;
|
||||
file_ptr nread = vec->pread (abfd, vec->stream, buf, nbytes, vec->where);
|
||||
if (nread < 0)
|
||||
return nread;
|
||||
vec->where += nread;
|
||||
return nread;
|
||||
}
|
||||
|
||||
static file_ptr
|
||||
opncls_bwrite (struct bfd *abfd ATTRIBUTE_UNUSED,
|
||||
const void *where ATTRIBUTE_UNUSED,
|
||||
file_ptr nbytes ATTRIBUTE_UNUSED)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
static int
|
||||
opncls_bclose (struct bfd *abfd)
|
||||
{
|
||||
struct opncls *vec = abfd->iostream;
|
||||
/* Since the VEC's memory is bound to the bfd deleting the bfd will
|
||||
free it. */
|
||||
int status = 0;
|
||||
if (vec->close != NULL)
|
||||
status = vec->close (abfd, vec->stream);
|
||||
abfd->iostream = NULL;
|
||||
return status;
|
||||
}
|
||||
|
||||
static int
|
||||
opncls_bflush (struct bfd *abfd ATTRIBUTE_UNUSED)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
opncls_bstat (struct bfd *abfd ATTRIBUTE_UNUSED, struct stat *sb)
|
||||
{
|
||||
memset (sb, 0, sizeof (*sb));
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct bfd_iovec opncls_iovec = {
|
||||
&opncls_bread, &opncls_bwrite, &opncls_btell, &opncls_bseek,
|
||||
&opncls_bclose, &opncls_bflush, &opncls_bstat
|
||||
};
|
||||
|
||||
bfd *
|
||||
bfd_openr_iovec (const char *filename, const char *target,
|
||||
void *(*open) (struct bfd *nbfd,
|
||||
void *open_closure),
|
||||
void *open_closure,
|
||||
file_ptr (*pread) (struct bfd *abfd,
|
||||
void *stream,
|
||||
void *buf,
|
||||
file_ptr nbytes,
|
||||
file_ptr offset),
|
||||
int (*close) (struct bfd *nbfd,
|
||||
void *stream))
|
||||
{
|
||||
bfd *nbfd;
|
||||
const bfd_target *target_vec;
|
||||
struct opncls *vec;
|
||||
void *stream;
|
||||
|
||||
nbfd = _bfd_new_bfd ();
|
||||
if (nbfd == NULL)
|
||||
return NULL;
|
||||
|
||||
target_vec = bfd_find_target (target, nbfd);
|
||||
if (target_vec == NULL)
|
||||
{
|
||||
_bfd_delete_bfd (nbfd);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
nbfd->filename = filename;
|
||||
nbfd->direction = read_direction;
|
||||
|
||||
stream = open (nbfd, open_closure);
|
||||
if (stream == NULL)
|
||||
{
|
||||
_bfd_delete_bfd (nbfd);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
vec = bfd_zalloc (nbfd, sizeof (struct opncls));
|
||||
vec->stream = stream;
|
||||
vec->pread = pread;
|
||||
vec->close = close;
|
||||
|
||||
nbfd->iovec = &opncls_iovec;
|
||||
nbfd->iostream = vec;
|
||||
|
||||
return nbfd;
|
||||
}
|
||||
|
||||
/* bfd_openw -- open for writing.
|
||||
Returns a pointer to a freshly-allocated BFD on success, or NULL.
|
||||
|
@ -415,7 +593,12 @@ bfd_close (bfd *abfd)
|
|||
if (! BFD_SEND (abfd, _close_and_cleanup, (abfd)))
|
||||
return FALSE;
|
||||
|
||||
ret = bfd_cache_close (abfd);
|
||||
/* FIXME: cagney/2004-02-15: Need to implement a BFD_IN_MEMORY io
|
||||
vector. */
|
||||
if (!(abfd->flags & BFD_IN_MEMORY))
|
||||
ret = abfd->iovec->bclose (abfd);
|
||||
else
|
||||
ret = 0;
|
||||
|
||||
/* If the file was open for writing and is now executable,
|
||||
make it so. */
|
||||
|
|
Loading…
Reference in a new issue