xref: /openbsd-src/gnu/usr.bin/binutils-2.17/bfd/bfdio.c (revision d04417c8bbac460f44f2231b23295dffb631d02d)
13d8817e4Smiod /* Low-level I/O routines for BFDs.
23d8817e4Smiod 
33d8817e4Smiod    Copyright 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1997, 1998,
43d8817e4Smiod    1999, 2000, 2001, 2002, 2003, 2004, 2005
53d8817e4Smiod    Free Software Foundation, Inc.
63d8817e4Smiod 
73d8817e4Smiod    Written by Cygnus Support.
83d8817e4Smiod 
93d8817e4Smiod This file is part of BFD, the Binary File Descriptor library.
103d8817e4Smiod 
113d8817e4Smiod This program is free software; you can redistribute it and/or modify
123d8817e4Smiod it under the terms of the GNU General Public License as published by
133d8817e4Smiod the Free Software Foundation; either version 2 of the License, or
143d8817e4Smiod (at your option) any later version.
153d8817e4Smiod 
163d8817e4Smiod This program is distributed in the hope that it will be useful,
173d8817e4Smiod but WITHOUT ANY WARRANTY; without even the implied warranty of
183d8817e4Smiod MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
193d8817e4Smiod GNU General Public License for more details.
203d8817e4Smiod 
213d8817e4Smiod You should have received a copy of the GNU General Public License
223d8817e4Smiod along with this program; if not, write to the Free Software
233d8817e4Smiod Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA.  */
243d8817e4Smiod 
253d8817e4Smiod #include "sysdep.h"
263d8817e4Smiod 
273d8817e4Smiod #include "bfd.h"
283d8817e4Smiod #include "libbfd.h"
293d8817e4Smiod 
303d8817e4Smiod #include <limits.h>
313d8817e4Smiod 
323d8817e4Smiod #ifndef S_IXUSR
333d8817e4Smiod #define S_IXUSR 0100    /* Execute by owner.  */
343d8817e4Smiod #endif
353d8817e4Smiod #ifndef S_IXGRP
363d8817e4Smiod #define S_IXGRP 0010    /* Execute by group.  */
373d8817e4Smiod #endif
383d8817e4Smiod #ifndef S_IXOTH
393d8817e4Smiod #define S_IXOTH 0001    /* Execute by others.  */
403d8817e4Smiod #endif
413d8817e4Smiod 
423d8817e4Smiod file_ptr
real_ftell(FILE * file)433d8817e4Smiod real_ftell (FILE *file)
443d8817e4Smiod {
453d8817e4Smiod #if defined (HAVE_FTELLO64)
463d8817e4Smiod   return ftello64 (file);
473d8817e4Smiod #elif defined (HAVE_FTELLO)
483d8817e4Smiod   return ftello (file);
493d8817e4Smiod #else
503d8817e4Smiod   return ftell (file);
513d8817e4Smiod #endif
523d8817e4Smiod }
533d8817e4Smiod 
543d8817e4Smiod int
real_fseek(FILE * file,file_ptr offset,int whence)553d8817e4Smiod real_fseek (FILE *file, file_ptr offset, int whence)
563d8817e4Smiod {
573d8817e4Smiod #if defined (HAVE_FSEEKO64)
583d8817e4Smiod   return fseeko64 (file, offset, whence);
593d8817e4Smiod #elif defined (HAVE_FSEEKO)
603d8817e4Smiod   return fseeko (file, offset, whence);
613d8817e4Smiod #else
623d8817e4Smiod   return fseek (file, offset, whence);
633d8817e4Smiod #endif
643d8817e4Smiod }
653d8817e4Smiod 
663d8817e4Smiod FILE *
real_fopen(const char * filename,const char * modes)673d8817e4Smiod real_fopen (const char *filename, const char *modes)
683d8817e4Smiod {
693d8817e4Smiod #if defined (HAVE_FOPEN64)
703d8817e4Smiod   return fopen64 (filename, modes);
713d8817e4Smiod #else
723d8817e4Smiod   return fopen (filename, modes);
733d8817e4Smiod #endif
743d8817e4Smiod }
753d8817e4Smiod 
763d8817e4Smiod /*
773d8817e4Smiod INTERNAL_DEFINITION
783d8817e4Smiod 	struct bfd_iovec
793d8817e4Smiod 
803d8817e4Smiod DESCRIPTION
813d8817e4Smiod 
823d8817e4Smiod 	The <<struct bfd_iovec>> contains the internal file I/O class.
833d8817e4Smiod 	Each <<BFD>> has an instance of this class and all file I/O is
843d8817e4Smiod 	routed through it (it is assumed that the instance implements
853d8817e4Smiod 	all methods listed below).
863d8817e4Smiod 
873d8817e4Smiod .struct bfd_iovec
883d8817e4Smiod .{
893d8817e4Smiod .  {* To avoid problems with macros, a "b" rather than "f"
903d8817e4Smiod .     prefix is prepended to each method name.  *}
913d8817e4Smiod .  {* Attempt to read/write NBYTES on ABFD's IOSTREAM storing/fetching
923d8817e4Smiod .     bytes starting at PTR.  Return the number of bytes actually
933d8817e4Smiod .     transfered (a read past end-of-file returns less than NBYTES),
943d8817e4Smiod .     or -1 (setting <<bfd_error>>) if an error occurs.  *}
953d8817e4Smiod .  file_ptr (*bread) (struct bfd *abfd, void *ptr, file_ptr nbytes);
963d8817e4Smiod .  file_ptr (*bwrite) (struct bfd *abfd, const void *ptr,
973d8817e4Smiod .                      file_ptr nbytes);
983d8817e4Smiod .  {* Return the current IOSTREAM file offset, or -1 (setting <<bfd_error>>
993d8817e4Smiod .     if an error occurs.  *}
1003d8817e4Smiod .  file_ptr (*btell) (struct bfd *abfd);
1013d8817e4Smiod .  {* For the following, on successful completion a value of 0 is returned.
1023d8817e4Smiod .     Otherwise, a value of -1 is returned (and  <<bfd_error>> is set).  *}
1033d8817e4Smiod .  int (*bseek) (struct bfd *abfd, file_ptr offset, int whence);
1043d8817e4Smiod .  int (*bclose) (struct bfd *abfd);
1053d8817e4Smiod .  int (*bflush) (struct bfd *abfd);
1063d8817e4Smiod .  int (*bstat) (struct bfd *abfd, struct stat *sb);
1073d8817e4Smiod .};
1083d8817e4Smiod 
1093d8817e4Smiod */
1103d8817e4Smiod 
1113d8817e4Smiod 
1123d8817e4Smiod /* Return value is amount read.  */
1133d8817e4Smiod 
1143d8817e4Smiod bfd_size_type
bfd_bread(void * ptr,bfd_size_type size,bfd * abfd)1153d8817e4Smiod bfd_bread (void *ptr, bfd_size_type size, bfd *abfd)
1163d8817e4Smiod {
1173d8817e4Smiod   size_t nread;
1183d8817e4Smiod 
1193d8817e4Smiod   if ((abfd->flags & BFD_IN_MEMORY) != 0)
1203d8817e4Smiod     {
1213d8817e4Smiod       struct bfd_in_memory *bim;
1223d8817e4Smiod       bfd_size_type get;
1233d8817e4Smiod 
1243d8817e4Smiod       bim = abfd->iostream;
1253d8817e4Smiod       get = size;
1263d8817e4Smiod       if (abfd->where + get > bim->size)
1273d8817e4Smiod 	{
1283d8817e4Smiod 	  if (bim->size < (bfd_size_type) abfd->where)
1293d8817e4Smiod 	    get = 0;
1303d8817e4Smiod 	  else
1313d8817e4Smiod 	    get = bim->size - abfd->where;
1323d8817e4Smiod 	  bfd_set_error (bfd_error_file_truncated);
1333d8817e4Smiod 	}
1343d8817e4Smiod       memcpy (ptr, bim->buffer + abfd->where, (size_t) get);
1353d8817e4Smiod       abfd->where += get;
1363d8817e4Smiod       return get;
1373d8817e4Smiod     }
1383d8817e4Smiod 
1393d8817e4Smiod   if (abfd->iovec)
1403d8817e4Smiod     nread = abfd->iovec->bread (abfd, ptr, size);
1413d8817e4Smiod   else
1423d8817e4Smiod     nread = 0;
1433d8817e4Smiod   if (nread != (size_t) -1)
1443d8817e4Smiod     abfd->where += nread;
1453d8817e4Smiod 
1463d8817e4Smiod   return nread;
1473d8817e4Smiod }
1483d8817e4Smiod 
1493d8817e4Smiod bfd_size_type
bfd_bwrite(const void * ptr,bfd_size_type size,bfd * abfd)1503d8817e4Smiod bfd_bwrite (const void *ptr, bfd_size_type size, bfd *abfd)
1513d8817e4Smiod {
1523d8817e4Smiod   size_t nwrote;
1533d8817e4Smiod 
1543d8817e4Smiod   if ((abfd->flags & BFD_IN_MEMORY) != 0)
1553d8817e4Smiod     {
1563d8817e4Smiod       struct bfd_in_memory *bim = abfd->iostream;
1573d8817e4Smiod 
1583d8817e4Smiod       size = (size_t) size;
1593d8817e4Smiod       if (abfd->where + size > bim->size)
1603d8817e4Smiod 	{
1613d8817e4Smiod 	  bfd_size_type newsize, oldsize;
1623d8817e4Smiod 
1633d8817e4Smiod 	  oldsize = (bim->size + 127) & ~(bfd_size_type) 127;
1643d8817e4Smiod 	  bim->size = abfd->where + size;
1653d8817e4Smiod 	  /* Round up to cut down on memory fragmentation */
1663d8817e4Smiod 	  newsize = (bim->size + 127) & ~(bfd_size_type) 127;
1673d8817e4Smiod 	  if (newsize > oldsize)
1683d8817e4Smiod 	    {
1693d8817e4Smiod 	      bim->buffer = bfd_realloc (bim->buffer, newsize);
1703d8817e4Smiod 	      if (bim->buffer == 0)
1713d8817e4Smiod 		{
1723d8817e4Smiod 		  bim->size = 0;
1733d8817e4Smiod 		  return 0;
1743d8817e4Smiod 		}
1753d8817e4Smiod 	    }
1763d8817e4Smiod 	}
1773d8817e4Smiod       memcpy (bim->buffer + abfd->where, ptr, (size_t) size);
1783d8817e4Smiod       abfd->where += size;
1793d8817e4Smiod       return size;
1803d8817e4Smiod     }
1813d8817e4Smiod 
1823d8817e4Smiod   if (abfd->iovec)
1833d8817e4Smiod     nwrote = abfd->iovec->bwrite (abfd, ptr, size);
1843d8817e4Smiod   else
1853d8817e4Smiod     nwrote = 0;
1863d8817e4Smiod 
1873d8817e4Smiod   if (nwrote != (size_t) -1)
1883d8817e4Smiod     abfd->where += nwrote;
1893d8817e4Smiod   if (nwrote != size)
1903d8817e4Smiod     {
1913d8817e4Smiod #ifdef ENOSPC
1923d8817e4Smiod       errno = ENOSPC;
1933d8817e4Smiod #endif
1943d8817e4Smiod       bfd_set_error (bfd_error_system_call);
1953d8817e4Smiod     }
1963d8817e4Smiod   return nwrote;
1973d8817e4Smiod }
1983d8817e4Smiod 
1993d8817e4Smiod file_ptr
bfd_tell(bfd * abfd)2003d8817e4Smiod bfd_tell (bfd *abfd)
2013d8817e4Smiod {
2023d8817e4Smiod   file_ptr ptr;
2033d8817e4Smiod 
2043d8817e4Smiod   if ((abfd->flags & BFD_IN_MEMORY) != 0)
2053d8817e4Smiod     return abfd->where;
2063d8817e4Smiod 
2073d8817e4Smiod   if (abfd->iovec)
2083d8817e4Smiod     {
2093d8817e4Smiod       ptr = abfd->iovec->btell (abfd);
2103d8817e4Smiod 
2113d8817e4Smiod       if (abfd->my_archive)
2123d8817e4Smiod 	ptr -= abfd->origin;
2133d8817e4Smiod     }
2143d8817e4Smiod   else
2153d8817e4Smiod     ptr = 0;
2163d8817e4Smiod 
2173d8817e4Smiod   abfd->where = ptr;
2183d8817e4Smiod   return ptr;
2193d8817e4Smiod }
2203d8817e4Smiod 
2213d8817e4Smiod int
bfd_flush(bfd * abfd)2223d8817e4Smiod bfd_flush (bfd *abfd)
2233d8817e4Smiod {
2243d8817e4Smiod   if ((abfd->flags & BFD_IN_MEMORY) != 0)
2253d8817e4Smiod     return 0;
2263d8817e4Smiod 
2273d8817e4Smiod   if (abfd->iovec)
2283d8817e4Smiod     return abfd->iovec->bflush (abfd);
2293d8817e4Smiod   return 0;
2303d8817e4Smiod }
2313d8817e4Smiod 
2323d8817e4Smiod /* Returns 0 for success, negative value for failure (in which case
2333d8817e4Smiod    bfd_get_error can retrieve the error code).  */
2343d8817e4Smiod int
bfd_stat(bfd * abfd,struct stat * statbuf)2353d8817e4Smiod bfd_stat (bfd *abfd, struct stat *statbuf)
2363d8817e4Smiod {
2373d8817e4Smiod   int result;
2383d8817e4Smiod 
2393d8817e4Smiod   if ((abfd->flags & BFD_IN_MEMORY) != 0)
2403d8817e4Smiod     abort ();
2413d8817e4Smiod 
2423d8817e4Smiod   if (abfd->iovec)
2433d8817e4Smiod     result = abfd->iovec->bstat (abfd, statbuf);
2443d8817e4Smiod   else
2453d8817e4Smiod     result = -1;
2463d8817e4Smiod 
2473d8817e4Smiod   if (result < 0)
2483d8817e4Smiod     bfd_set_error (bfd_error_system_call);
2493d8817e4Smiod   return result;
2503d8817e4Smiod }
2513d8817e4Smiod 
2523d8817e4Smiod /* Returns 0 for success, nonzero for failure (in which case bfd_get_error
2533d8817e4Smiod    can retrieve the error code).  */
2543d8817e4Smiod 
2553d8817e4Smiod int
bfd_seek(bfd * abfd,file_ptr position,int direction)2563d8817e4Smiod bfd_seek (bfd *abfd, file_ptr position, int direction)
2573d8817e4Smiod {
2583d8817e4Smiod   int result;
2593d8817e4Smiod   file_ptr file_position;
2603d8817e4Smiod   /* For the time being, a BFD may not seek to it's end.  The problem
2613d8817e4Smiod      is that we don't easily have a way to recognize the end of an
2623d8817e4Smiod      element in an archive.  */
2633d8817e4Smiod 
2643d8817e4Smiod   BFD_ASSERT (direction == SEEK_SET || direction == SEEK_CUR);
2653d8817e4Smiod 
2663d8817e4Smiod   if (direction == SEEK_CUR && position == 0)
2673d8817e4Smiod     return 0;
2683d8817e4Smiod 
2693d8817e4Smiod   if ((abfd->flags & BFD_IN_MEMORY) != 0)
2703d8817e4Smiod     {
2713d8817e4Smiod       struct bfd_in_memory *bim;
2723d8817e4Smiod 
2733d8817e4Smiod       bim = abfd->iostream;
2743d8817e4Smiod 
2753d8817e4Smiod       if (direction == SEEK_SET)
2763d8817e4Smiod 	abfd->where = position;
2773d8817e4Smiod       else
2783d8817e4Smiod 	abfd->where += position;
2793d8817e4Smiod 
2803d8817e4Smiod       if (abfd->where > bim->size)
2813d8817e4Smiod 	{
2823d8817e4Smiod 	  if ((abfd->direction == write_direction) ||
2833d8817e4Smiod 	      (abfd->direction == both_direction))
2843d8817e4Smiod 	    {
2853d8817e4Smiod 	      bfd_size_type newsize, oldsize;
2863d8817e4Smiod 
2873d8817e4Smiod 	      oldsize = (bim->size + 127) & ~(bfd_size_type) 127;
2883d8817e4Smiod 	      bim->size = abfd->where;
2893d8817e4Smiod 	      /* Round up to cut down on memory fragmentation */
2903d8817e4Smiod 	      newsize = (bim->size + 127) & ~(bfd_size_type) 127;
2913d8817e4Smiod 	      if (newsize > oldsize)
2923d8817e4Smiod 	        {
2933d8817e4Smiod 		  bim->buffer = bfd_realloc (bim->buffer, newsize);
2943d8817e4Smiod 		  if (bim->buffer == 0)
2953d8817e4Smiod 		    {
2963d8817e4Smiod 		      bim->size = 0;
2973d8817e4Smiod 		      return -1;
2983d8817e4Smiod 		    }
2993d8817e4Smiod 	        }
3003d8817e4Smiod 	    }
3013d8817e4Smiod 	  else
3023d8817e4Smiod 	    {
3033d8817e4Smiod 	      abfd->where = bim->size;
3043d8817e4Smiod 	      bfd_set_error (bfd_error_file_truncated);
3053d8817e4Smiod 	      return -1;
3063d8817e4Smiod 	    }
3073d8817e4Smiod 	}
3083d8817e4Smiod       return 0;
3093d8817e4Smiod     }
3103d8817e4Smiod 
3113d8817e4Smiod   if (abfd->format != bfd_archive && abfd->my_archive == 0)
3123d8817e4Smiod     {
3133d8817e4Smiod       if (direction == SEEK_SET && (bfd_vma) position == abfd->where)
3143d8817e4Smiod 	return 0;
3153d8817e4Smiod     }
3163d8817e4Smiod   else
3173d8817e4Smiod     {
3183d8817e4Smiod       /* We need something smarter to optimize access to archives.
3193d8817e4Smiod 	 Currently, anything inside an archive is read via the file
3203d8817e4Smiod 	 handle for the archive.  Which means that a bfd_seek on one
3213d8817e4Smiod 	 component affects the `current position' in the archive, as
3223d8817e4Smiod 	 well as in any other component.
3233d8817e4Smiod 
3243d8817e4Smiod 	 It might be sufficient to put a spike through the cache
3253d8817e4Smiod 	 abstraction, and look to the archive for the file position,
3263d8817e4Smiod 	 but I think we should try for something cleaner.
3273d8817e4Smiod 
3283d8817e4Smiod 	 In the meantime, no optimization for archives.  */
3293d8817e4Smiod     }
3303d8817e4Smiod 
3313d8817e4Smiod   file_position = position;
3323d8817e4Smiod   if (direction == SEEK_SET && abfd->my_archive != NULL)
3333d8817e4Smiod     file_position += abfd->origin;
3343d8817e4Smiod 
3353d8817e4Smiod   if (abfd->iovec)
3363d8817e4Smiod     result = abfd->iovec->bseek (abfd, file_position, direction);
3373d8817e4Smiod   else
3383d8817e4Smiod     result = -1;
3393d8817e4Smiod 
3403d8817e4Smiod   if (result != 0)
3413d8817e4Smiod     {
3423d8817e4Smiod       int hold_errno = errno;
3433d8817e4Smiod 
3443d8817e4Smiod       /* Force redetermination of `where' field.  */
3453d8817e4Smiod       bfd_tell (abfd);
3463d8817e4Smiod 
3473d8817e4Smiod       /* An EINVAL error probably means that the file offset was
3483d8817e4Smiod          absurd.  */
3493d8817e4Smiod       if (hold_errno == EINVAL)
3503d8817e4Smiod 	bfd_set_error (bfd_error_file_truncated);
3513d8817e4Smiod       else
3523d8817e4Smiod 	{
3533d8817e4Smiod 	  bfd_set_error (bfd_error_system_call);
3543d8817e4Smiod 	  errno = hold_errno;
3553d8817e4Smiod 	}
3563d8817e4Smiod     }
3573d8817e4Smiod   else
3583d8817e4Smiod     {
3593d8817e4Smiod       /* Adjust `where' field.  */
3603d8817e4Smiod       if (direction == SEEK_SET)
3613d8817e4Smiod 	abfd->where = position;
3623d8817e4Smiod       else
3633d8817e4Smiod 	abfd->where += position;
3643d8817e4Smiod     }
3653d8817e4Smiod   return result;
3663d8817e4Smiod }
3673d8817e4Smiod 
3683d8817e4Smiod /*
3693d8817e4Smiod FUNCTION
3703d8817e4Smiod 	bfd_get_mtime
3713d8817e4Smiod 
3723d8817e4Smiod SYNOPSIS
373*d04417c8Smiod 	time_t bfd_get_mtime (bfd *abfd);
3743d8817e4Smiod 
3753d8817e4Smiod DESCRIPTION
3763d8817e4Smiod 	Return the file modification time (as read from the file system, or
3773d8817e4Smiod 	from the archive header for archive members).
3783d8817e4Smiod 
3793d8817e4Smiod */
3803d8817e4Smiod 
381*d04417c8Smiod time_t
bfd_get_mtime(bfd * abfd)3823d8817e4Smiod bfd_get_mtime (bfd *abfd)
3833d8817e4Smiod {
3843d8817e4Smiod   struct stat buf;
3853d8817e4Smiod 
3863d8817e4Smiod   if (abfd->mtime_set)
3873d8817e4Smiod     return abfd->mtime;
3883d8817e4Smiod 
3893d8817e4Smiod   if (abfd->iovec == NULL)
3903d8817e4Smiod     return 0;
3913d8817e4Smiod 
3923d8817e4Smiod   if (abfd->iovec->bstat (abfd, &buf) != 0)
3933d8817e4Smiod     return 0;
3943d8817e4Smiod 
3953d8817e4Smiod   abfd->mtime = buf.st_mtime;		/* Save value in case anyone wants it */
3963d8817e4Smiod   return buf.st_mtime;
3973d8817e4Smiod }
3983d8817e4Smiod 
3993d8817e4Smiod /*
4003d8817e4Smiod FUNCTION
4013d8817e4Smiod 	bfd_get_size
4023d8817e4Smiod 
4033d8817e4Smiod SYNOPSIS
4043d8817e4Smiod 	long bfd_get_size (bfd *abfd);
4053d8817e4Smiod 
4063d8817e4Smiod DESCRIPTION
4073d8817e4Smiod 	Return the file size (as read from file system) for the file
4083d8817e4Smiod 	associated with BFD @var{abfd}.
4093d8817e4Smiod 
4103d8817e4Smiod 	The initial motivation for, and use of, this routine is not
4113d8817e4Smiod 	so we can get the exact size of the object the BFD applies to, since
4123d8817e4Smiod 	that might not be generally possible (archive members for example).
4133d8817e4Smiod 	It would be ideal if someone could eventually modify
4143d8817e4Smiod 	it so that such results were guaranteed.
4153d8817e4Smiod 
4163d8817e4Smiod 	Instead, we want to ask questions like "is this NNN byte sized
4173d8817e4Smiod 	object I'm about to try read from file offset YYY reasonable?"
4183d8817e4Smiod 	As as example of where we might do this, some object formats
4193d8817e4Smiod 	use string tables for which the first <<sizeof (long)>> bytes of the
4203d8817e4Smiod 	table contain the size of the table itself, including the size bytes.
4213d8817e4Smiod 	If an application tries to read what it thinks is one of these
4223d8817e4Smiod 	string tables, without some way to validate the size, and for
4233d8817e4Smiod 	some reason the size is wrong (byte swapping error, wrong location
4243d8817e4Smiod 	for the string table, etc.), the only clue is likely to be a read
4253d8817e4Smiod 	error when it tries to read the table, or a "virtual memory
4263d8817e4Smiod 	exhausted" error when it tries to allocate 15 bazillon bytes
4273d8817e4Smiod 	of space for the 15 bazillon byte table it is about to read.
4283d8817e4Smiod 	This function at least allows us to answer the question, "is the
4293d8817e4Smiod 	size reasonable?".
4303d8817e4Smiod */
4313d8817e4Smiod 
4323d8817e4Smiod long
bfd_get_size(bfd * abfd)4333d8817e4Smiod bfd_get_size (bfd *abfd)
4343d8817e4Smiod {
4353d8817e4Smiod   struct stat buf;
4363d8817e4Smiod 
4373d8817e4Smiod   if ((abfd->flags & BFD_IN_MEMORY) != 0)
4383d8817e4Smiod     return ((struct bfd_in_memory *) abfd->iostream)->size;
4393d8817e4Smiod 
4403d8817e4Smiod   if (abfd->iovec == NULL)
4413d8817e4Smiod     return 0;
4423d8817e4Smiod 
4433d8817e4Smiod   if (abfd->iovec->bstat (abfd, &buf) != 0)
4443d8817e4Smiod     return 0;
4453d8817e4Smiod 
4463d8817e4Smiod   return buf.st_size;
4473d8817e4Smiod }
448