(root)/
binutils-2.41/
bfd/
bfdio.c
       1  /* Low-level I/O routines for BFDs.
       2  
       3     Copyright (C) 1990-2023 Free Software Foundation, Inc.
       4  
       5     Written by Cygnus Support.
       6  
       7     This file is part of BFD, the Binary File Descriptor library.
       8  
       9     This program is free software; you can redistribute it and/or modify
      10     it under the terms of the GNU General Public License as published by
      11     the Free Software Foundation; either version 3 of the License, or
      12     (at your option) any later version.
      13  
      14     This program is distributed in the hope that it will be useful,
      15     but WITHOUT ANY WARRANTY; without even the implied warranty of
      16     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
      17     GNU General Public License for more details.
      18  
      19     You should have received a copy of the GNU General Public License
      20     along with this program; if not, write to the Free Software
      21     Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston,
      22     MA 02110-1301, USA.  */
      23  
      24  #include "sysdep.h"
      25  #include <limits.h>
      26  #include "bfd.h"
      27  #include "libbfd.h"
      28  #include "aout/ar.h"
      29  #if defined (_WIN32)
      30  #include <windows.h>
      31  #include <locale.h>
      32  #endif
      33  
      34  #ifndef S_IXUSR
      35  #define S_IXUSR 0100    /* Execute by owner.  */
      36  #endif
      37  #ifndef S_IXGRP
      38  #define S_IXGRP 0010    /* Execute by group.  */
      39  #endif
      40  #ifndef S_IXOTH
      41  #define S_IXOTH 0001    /* Execute by others.  */
      42  #endif
      43  
      44  #ifndef FD_CLOEXEC
      45  #define FD_CLOEXEC 1
      46  #endif
      47  
      48  file_ptr
      49  _bfd_real_ftell (FILE *file)
      50  {
      51  #if defined (HAVE_FTELLO64)
      52    return ftello64 (file);
      53  #elif defined (HAVE_FTELLO)
      54    return ftello (file);
      55  #else
      56    return ftell (file);
      57  #endif
      58  }
      59  
      60  int
      61  _bfd_real_fseek (FILE *file, file_ptr offset, int whence)
      62  {
      63  #if defined (HAVE_FSEEKO64)
      64    return fseeko64 (file, offset, whence);
      65  #elif defined (HAVE_FSEEKO)
      66    return fseeko (file, offset, whence);
      67  #else
      68    return fseek (file, offset, whence);
      69  #endif
      70  }
      71  
      72  /* Mark FILE as close-on-exec.  Return FILE.  FILE may be NULL, in
      73     which case nothing is done.  */
      74  static FILE *
      75  close_on_exec (FILE *file)
      76  {
      77  #if defined (HAVE_FILENO) && defined (F_GETFD)
      78    if (file)
      79      {
      80        int fd = fileno (file);
      81        int old = fcntl (fd, F_GETFD, 0);
      82        if (old >= 0)
      83  	fcntl (fd, F_SETFD, old | FD_CLOEXEC);
      84      }
      85  #endif
      86    return file;
      87  }
      88  
      89  FILE *
      90  _bfd_real_fopen (const char *filename, const char *modes)
      91  {
      92  #ifdef VMS
      93    char *vms_attr;
      94  
      95    /* On VMS, fopen allows file attributes as optional arguments.
      96       We need to use them but we'd better to use the common prototype.
      97       In fopen-vms.h, they are separated from the mode with a comma.
      98       Split here.  */
      99    vms_attr = strchr (modes, ',');
     100    if (vms_attr != NULL)
     101      {
     102        /* Attributes found.  Split.  */
     103        size_t modes_len = strlen (modes) + 1;
     104        char attrs[modes_len + 1];
     105        char *at[3];
     106        int i;
     107  
     108        memcpy (attrs, modes, modes_len);
     109        at[0] = attrs;
     110        for (i = 0; i < 2; i++)
     111  	{
     112  	  at[i + 1] = strchr (at[i], ',');
     113  	  BFD_ASSERT (at[i + 1] != NULL);
     114  	  *(at[i + 1]++) = 0; /* Replace ',' with a nul, and skip it.  */
     115  	}
     116        return close_on_exec (fopen (filename, at[0], at[1], at[2]));
     117      }
     118  
     119  #elif defined (_WIN32)
     120    /* PR 25713: Handle extra long path names possibly containing '..' and '.'.  */
     121     wchar_t **     lpFilePart = {NULL};
     122     const wchar_t  prefix[] = L"\\\\?\\";
     123     const size_t   partPathLen = strlen (filename) + 1;
     124  #ifdef __MINGW32__
     125  #if !HAVE_DECL____LC_CODEPAGE_FUNC
     126  /* This prototype was added to locale.h in version 9.0 of MinGW-w64.  */
     127     _CRTIMP unsigned int __cdecl ___lc_codepage_func (void);
     128  #endif
     129     const unsigned int cp = ___lc_codepage_func ();
     130  #else
     131     const unsigned int cp = CP_UTF8;
     132  #endif
     133  
     134     /* Converting the partial path from ascii to unicode.
     135        1) Get the length: Calling with lpWideCharStr set to null returns the length.
     136        2) Convert the string: Calling with cbMultiByte set to -1 includes the terminating null.  */
     137     size_t         partPathWSize = MultiByteToWideChar (cp, 0, filename, -1, NULL, 0);
     138     wchar_t *      partPath = calloc (partPathWSize, sizeof(wchar_t));
     139     size_t         ix;
     140  
     141     MultiByteToWideChar (cp, 0, filename, -1, partPath, partPathWSize);
     142  
     143     /* Convert any UNIX style path separators into the DOS i.e. backslash separator.  */
     144     for (ix = 0; ix < partPathLen; ix++)
     145       if (IS_UNIX_DIR_SEPARATOR(filename[ix]))
     146         partPath[ix] = '\\';
     147  
     148     /* Getting the full path from the provided partial path.
     149        1) Get the length.
     150        2) Resolve the path.  */
     151     long       fullPathWSize = GetFullPathNameW (partPath, 0, NULL, lpFilePart);
     152     wchar_t *  fullPath = calloc (fullPathWSize + sizeof(prefix) + 1, sizeof(wchar_t));
     153  
     154     wcscpy (fullPath, prefix);
     155  
     156     int        prefixLen = sizeof(prefix) / sizeof(wchar_t);
     157  
     158     /* Do not add a prefix to the null device.  */
     159     if (stricmp (filename, "nul") == 0)
     160      prefixLen = 1;
     161  
     162     wchar_t *  fullPathOffset = fullPath + prefixLen - 1;
     163  
     164     GetFullPathNameW (partPath, fullPathWSize, fullPathOffset, lpFilePart);
     165     free (partPath);
     166  
     167     /* It is non-standard for modes to exceed 16 characters.  */
     168     wchar_t    modesW[16];
     169  
     170     MultiByteToWideChar (cp, 0, modes, -1, modesW, sizeof(modesW));
     171  
     172     FILE *     file = _wfopen (fullPath, modesW);
     173     free (fullPath);
     174  
     175     return close_on_exec (file);
     176  
     177  #elif defined (HAVE_FOPEN64)
     178    return close_on_exec (fopen64 (filename, modes));
     179  
     180  #else
     181    return close_on_exec (fopen (filename, modes));
     182  #endif
     183  }
     184  
     185  /*
     186  INTERNAL_DEFINITION
     187  	struct bfd_iovec
     188  
     189  DESCRIPTION
     190  
     191  	The <<struct bfd_iovec>> contains the internal file I/O class.
     192  	Each <<BFD>> has an instance of this class and all file I/O is
     193  	routed through it (it is assumed that the instance implements
     194  	all methods listed below).
     195  
     196  .struct bfd_iovec
     197  .{
     198  .  {* To avoid problems with macros, a "b" rather than "f"
     199  .     prefix is prepended to each method name.  *}
     200  .  {* Attempt to read/write NBYTES on ABFD's IOSTREAM storing/fetching
     201  .     bytes starting at PTR.  Return the number of bytes actually
     202  .     transfered (a read past end-of-file returns less than NBYTES),
     203  .     or -1 (setting <<bfd_error>>) if an error occurs.  *}
     204  .  file_ptr (*bread) (struct bfd *abfd, void *ptr, file_ptr nbytes);
     205  .  file_ptr (*bwrite) (struct bfd *abfd, const void *ptr,
     206  .		       file_ptr nbytes);
     207  .  {* Return the current IOSTREAM file offset, or -1 (setting <<bfd_error>>
     208  .     if an error occurs.  *}
     209  .  file_ptr (*btell) (struct bfd *abfd);
     210  .  {* For the following, on successful completion a value of 0 is returned.
     211  .     Otherwise, a value of -1 is returned (and <<bfd_error>> is set).  *}
     212  .  int (*bseek) (struct bfd *abfd, file_ptr offset, int whence);
     213  .  int (*bclose) (struct bfd *abfd);
     214  .  int (*bflush) (struct bfd *abfd);
     215  .  int (*bstat) (struct bfd *abfd, struct stat *sb);
     216  .  {* Mmap a part of the files. ADDR, LEN, PROT, FLAGS and OFFSET are the usual
     217  .     mmap parameter, except that LEN and OFFSET do not need to be page
     218  .     aligned.  Returns (void *)-1 on failure, mmapped address on success.
     219  .     Also write in MAP_ADDR the address of the page aligned buffer and in
     220  .     MAP_LEN the size mapped (a page multiple).  Use unmap with MAP_ADDR and
     221  .     MAP_LEN to unmap.  *}
     222  .  void *(*bmmap) (struct bfd *abfd, void *addr, bfd_size_type len,
     223  .		   int prot, int flags, file_ptr offset,
     224  .		   void **map_addr, bfd_size_type *map_len);
     225  .};
     226  
     227  .extern const struct bfd_iovec _bfd_memory_iovec;
     228  .
     229  */
     230  
     231  
     232  /*
     233  FUNCTION
     234  	bfd_bread
     235  
     236  SYNOPSIS
     237  	bfd_size_type bfd_bread (void *, bfd_size_type, bfd *);
     238  
     239  DESCRIPTION
     240  	Attempt to read SIZE bytes from ABFD's iostream to PTR.
     241  	Return the amount read.
     242  */
     243  
     244  bfd_size_type
     245  bfd_bread (void *ptr, bfd_size_type size, bfd *abfd)
     246  {
     247    file_ptr nread;
     248    bfd *element_bfd = abfd;
     249    ufile_ptr offset = 0;
     250  
     251    while (abfd->my_archive != NULL
     252  	 && !bfd_is_thin_archive (abfd->my_archive))
     253      {
     254        offset += abfd->origin;
     255        abfd = abfd->my_archive;
     256      }
     257    offset += abfd->origin;
     258  
     259    /* If this is a non-thin archive element, don't read past the end of
     260       this element.  */
     261    if (element_bfd->arelt_data != NULL
     262        && element_bfd->my_archive != NULL
     263        && !bfd_is_thin_archive (element_bfd->my_archive))
     264      {
     265        bfd_size_type maxbytes = arelt_size (element_bfd);
     266  
     267        if (abfd->where < offset || abfd->where - offset >= maxbytes)
     268  	{
     269  	  bfd_set_error (bfd_error_invalid_operation);
     270  	  return -1;
     271  	}
     272        if (abfd->where - offset + size > maxbytes)
     273  	size = maxbytes - (abfd->where - offset);
     274      }
     275  
     276    if (abfd->iovec == NULL)
     277      {
     278        bfd_set_error (bfd_error_invalid_operation);
     279        return -1;
     280      }
     281  
     282    nread = abfd->iovec->bread (abfd, ptr, size);
     283    if (nread != -1)
     284      abfd->where += nread;
     285  
     286    return nread;
     287  }
     288  
     289  /*
     290  FUNCTION
     291  	bfd_bwrite
     292  
     293  SYNOPSIS
     294  	bfd_size_type bfd_bwrite (const void *, bfd_size_type, bfd *);
     295  
     296  DESCRIPTION
     297  	Attempt to write SIZE bytes to ABFD's iostream from PTR.
     298  	Return the amount written.
     299  */
     300  
     301  bfd_size_type
     302  bfd_bwrite (const void *ptr, bfd_size_type size, bfd *abfd)
     303  {
     304    file_ptr nwrote;
     305  
     306    while (abfd->my_archive != NULL
     307  	 && !bfd_is_thin_archive (abfd->my_archive))
     308      abfd = abfd->my_archive;
     309  
     310    if (abfd->iovec == NULL)
     311      {
     312        bfd_set_error (bfd_error_invalid_operation);
     313        return -1;
     314      }
     315  
     316    nwrote = abfd->iovec->bwrite (abfd, ptr, size);
     317    if (nwrote != -1)
     318      abfd->where += nwrote;
     319    if ((bfd_size_type) nwrote != size)
     320      {
     321  #ifdef ENOSPC
     322        errno = ENOSPC;
     323  #endif
     324        bfd_set_error (bfd_error_system_call);
     325      }
     326    return nwrote;
     327  }
     328  
     329  /*
     330  FUNCTION
     331  	bfd_tell
     332  
     333  SYNOPSIS
     334  	file_ptr bfd_tell (bfd *);
     335  
     336  DESCRIPTION
     337  	Return ABFD's iostream file position.
     338  */
     339  
     340  file_ptr
     341  bfd_tell (bfd *abfd)
     342  {
     343    ufile_ptr offset = 0;
     344    file_ptr ptr;
     345  
     346    while (abfd->my_archive != NULL
     347  	 && !bfd_is_thin_archive (abfd->my_archive))
     348      {
     349        offset += abfd->origin;
     350        abfd = abfd->my_archive;
     351      }
     352    offset += abfd->origin;
     353  
     354    if (abfd->iovec == NULL)
     355      return 0;
     356  
     357    ptr = abfd->iovec->btell (abfd);
     358    abfd->where = ptr;
     359    return ptr - offset;
     360  }
     361  
     362  /*
     363  FUNCTION
     364  	bfd_flush
     365  
     366  SYNOPSIS
     367  	int bfd_flush (bfd *);
     368  
     369  DESCRIPTION
     370  	Flush ABFD's iostream pending IO.
     371  */
     372  
     373  int
     374  bfd_flush (bfd *abfd)
     375  {
     376    while (abfd->my_archive != NULL
     377  	 && !bfd_is_thin_archive (abfd->my_archive))
     378      abfd = abfd->my_archive;
     379  
     380    if (abfd->iovec == NULL)
     381      return 0;
     382  
     383    return abfd->iovec->bflush (abfd);
     384  }
     385  
     386  /*
     387  FUNCTION
     388  	bfd_stat
     389  
     390  SYNOPSIS
     391  	int bfd_stat (bfd *, struct stat *);
     392  
     393  DESCRIPTION
     394  	Call fstat on ABFD's iostream.  Return 0 on success, and a
     395  	negative value on failure.
     396  */
     397  
     398  int
     399  bfd_stat (bfd *abfd, struct stat *statbuf)
     400  {
     401    int result;
     402  
     403    while (abfd->my_archive != NULL
     404  	 && !bfd_is_thin_archive (abfd->my_archive))
     405      abfd = abfd->my_archive;
     406  
     407    if (abfd->iovec == NULL)
     408      {
     409        bfd_set_error (bfd_error_invalid_operation);
     410        return -1;
     411      }
     412  
     413    result = abfd->iovec->bstat (abfd, statbuf);
     414    if (result < 0)
     415      bfd_set_error (bfd_error_system_call);
     416    return result;
     417  }
     418  
     419  /*
     420  FUNCTION
     421  	bfd_seek
     422  
     423  SYNOPSIS
     424  	int bfd_seek (bfd *, file_ptr, int);
     425  
     426  DESCRIPTION
     427  	Call fseek on ABFD's iostream.  Return 0 on success, and a
     428  	negative value on failure.
     429  */
     430  
     431  int
     432  bfd_seek (bfd *abfd, file_ptr position, int direction)
     433  {
     434    int result;
     435    ufile_ptr offset = 0;
     436  
     437    while (abfd->my_archive != NULL
     438  	 && !bfd_is_thin_archive (abfd->my_archive))
     439      {
     440        offset += abfd->origin;
     441        abfd = abfd->my_archive;
     442      }
     443    offset += abfd->origin;
     444  
     445    if (abfd->iovec == NULL)
     446      {
     447        bfd_set_error (bfd_error_invalid_operation);
     448        return -1;
     449      }
     450  
     451    /* For the time being, a BFD may not seek to it's end.  The problem
     452       is that we don't easily have a way to recognize the end of an
     453       element in an archive.  */
     454    BFD_ASSERT (direction == SEEK_SET || direction == SEEK_CUR);
     455  
     456    if (direction != SEEK_CUR)
     457      position += offset;
     458  
     459    result = abfd->iovec->bseek (abfd, position, direction);
     460    if (result != 0)
     461      {
     462        /* An EINVAL error probably means that the file offset was
     463  	 absurd.  */
     464        if (errno == EINVAL)
     465  	bfd_set_error (bfd_error_file_truncated);
     466        else
     467  	bfd_set_error (bfd_error_system_call);
     468      }
     469    else
     470      {
     471        /* Adjust `where' field.  */
     472        if (direction == SEEK_CUR)
     473  	abfd->where += position;
     474        else
     475  	abfd->where = position;
     476      }
     477  
     478    return result;
     479  }
     480  
     481  /*
     482  FUNCTION
     483  	bfd_get_mtime
     484  
     485  SYNOPSIS
     486  	long bfd_get_mtime (bfd *abfd);
     487  
     488  DESCRIPTION
     489  	Return the file modification time (as read from the file system, or
     490  	from the archive header for archive members).
     491  
     492  */
     493  
     494  long
     495  bfd_get_mtime (bfd *abfd)
     496  {
     497    struct stat buf;
     498  
     499    if (abfd->mtime_set)
     500      return abfd->mtime;
     501  
     502    if (bfd_stat (abfd, &buf) != 0)
     503      return 0;
     504  
     505    abfd->mtime = buf.st_mtime;		/* Save value in case anyone wants it */
     506    return buf.st_mtime;
     507  }
     508  
     509  /*
     510  FUNCTION
     511  	bfd_get_size
     512  
     513  SYNOPSIS
     514  	ufile_ptr bfd_get_size (bfd *abfd);
     515  
     516  DESCRIPTION
     517  	Return the file size (as read from file system) for the file
     518  	associated with BFD @var{abfd}.
     519  
     520  	The initial motivation for, and use of, this routine is not
     521  	so we can get the exact size of the object the BFD applies to, since
     522  	that might not be generally possible (archive members for example).
     523  	It would be ideal if someone could eventually modify
     524  	it so that such results were guaranteed.
     525  
     526  	Instead, we want to ask questions like "is this NNN byte sized
     527  	object I'm about to try read from file offset YYY reasonable?"
     528  	As as example of where we might do this, some object formats
     529  	use string tables for which the first <<sizeof (long)>> bytes of the
     530  	table contain the size of the table itself, including the size bytes.
     531  	If an application tries to read what it thinks is one of these
     532  	string tables, without some way to validate the size, and for
     533  	some reason the size is wrong (byte swapping error, wrong location
     534  	for the string table, etc.), the only clue is likely to be a read
     535  	error when it tries to read the table, or a "virtual memory
     536  	exhausted" error when it tries to allocate 15 bazillon bytes
     537  	of space for the 15 bazillon byte table it is about to read.
     538  	This function at least allows us to answer the question, "is the
     539  	size reasonable?".
     540  
     541  	A return value of zero indicates the file size is unknown.
     542  */
     543  
     544  ufile_ptr
     545  bfd_get_size (bfd *abfd)
     546  {
     547    /* A size of 0 means we haven't yet called bfd_stat.  A size of 1
     548       means we have a cached value of 0, ie. unknown.  */
     549    if (abfd->size <= 1 || bfd_write_p (abfd))
     550      {
     551        struct stat buf;
     552  
     553        if (abfd->size == 1 && !bfd_write_p (abfd))
     554  	return 0;
     555  
     556        if (bfd_stat (abfd, &buf) != 0
     557  	  || buf.st_size == 0
     558  	  || buf.st_size - (ufile_ptr) buf.st_size != 0)
     559  	{
     560  	  abfd->size = 1;
     561  	  return 0;
     562  	}
     563        abfd->size = buf.st_size;
     564      }
     565    return abfd->size;
     566  }
     567  
     568  /*
     569  FUNCTION
     570  	bfd_get_file_size
     571  
     572  SYNOPSIS
     573  	ufile_ptr bfd_get_file_size (bfd *abfd);
     574  
     575  DESCRIPTION
     576  	Return the file size (as read from file system) for the file
     577  	associated with BFD @var{abfd}.  It supports both normal files
     578  	and archive elements.
     579  
     580  */
     581  
     582  ufile_ptr
     583  bfd_get_file_size (bfd *abfd)
     584  {
     585    ufile_ptr file_size, archive_size = (ufile_ptr) -1;
     586    unsigned int compression_p2 = 0;
     587  
     588    if (abfd->my_archive != NULL
     589        && !bfd_is_thin_archive (abfd->my_archive))
     590      {
     591        struct areltdata *adata = (struct areltdata *) abfd->arelt_data;
     592        if (adata != NULL)
     593  	{
     594  	  archive_size = adata->parsed_size;
     595  	  /* If the archive is compressed, assume an element won't
     596  	     expand more than eight times file size.  */
     597  	  if (adata->arch_header != NULL
     598  	      && memcmp (((struct ar_hdr *) adata->arch_header)->ar_fmag,
     599  			 "Z\012", 2) == 0)
     600  	    compression_p2 = 3;
     601  	  abfd = abfd->my_archive;
     602  	}
     603      }
     604  
     605    file_size = bfd_get_size (abfd) << compression_p2;
     606    if (archive_size < file_size)
     607      return archive_size;
     608    return file_size;
     609  }
     610  
     611  /*
     612  FUNCTION
     613  	bfd_mmap
     614  
     615  SYNOPSIS
     616  	void *bfd_mmap (bfd *abfd, void *addr, bfd_size_type len,
     617  			int prot, int flags, file_ptr offset,
     618  			void **map_addr, bfd_size_type *map_len);
     619  
     620  DESCRIPTION
     621  	Return mmap()ed region of the file, if possible and implemented.
     622  	LEN and OFFSET do not need to be page aligned.  The page aligned
     623  	address and length are written to MAP_ADDR and MAP_LEN.
     624  
     625  */
     626  
     627  void *
     628  bfd_mmap (bfd *abfd, void *addr, bfd_size_type len,
     629  	  int prot, int flags, file_ptr offset,
     630  	  void **map_addr, bfd_size_type *map_len)
     631  {
     632    while (abfd->my_archive != NULL
     633  	 && !bfd_is_thin_archive (abfd->my_archive))
     634      {
     635        offset += abfd->origin;
     636        abfd = abfd->my_archive;
     637      }
     638    offset += abfd->origin;
     639  
     640    if (abfd->iovec == NULL)
     641      {
     642        bfd_set_error (bfd_error_invalid_operation);
     643        return (void *) -1;
     644      }
     645  
     646    return abfd->iovec->bmmap (abfd, addr, len, prot, flags, offset,
     647  			     map_addr, map_len);
     648  }
     649  
     650  /* Memory file I/O operations.  */
     651  
     652  static file_ptr
     653  memory_bread (bfd *abfd, void *ptr, file_ptr size)
     654  {
     655    struct bfd_in_memory *bim;
     656    bfd_size_type get;
     657  
     658    bim = (struct bfd_in_memory *) abfd->iostream;
     659    get = size;
     660    if (abfd->where + get > bim->size)
     661      {
     662        if (bim->size < (bfd_size_type) abfd->where)
     663  	get = 0;
     664        else
     665  	get = bim->size - abfd->where;
     666        bfd_set_error (bfd_error_file_truncated);
     667      }
     668    memcpy (ptr, bim->buffer + abfd->where, (size_t) get);
     669    return get;
     670  }
     671  
     672  static file_ptr
     673  memory_bwrite (bfd *abfd, const void *ptr, file_ptr size)
     674  {
     675    struct bfd_in_memory *bim = (struct bfd_in_memory *) abfd->iostream;
     676  
     677    if (abfd->where + size > bim->size)
     678      {
     679        bfd_size_type newsize, oldsize;
     680  
     681        oldsize = (bim->size + 127) & ~(bfd_size_type) 127;
     682        bim->size = abfd->where + size;
     683        /* Round up to cut down on memory fragmentation */
     684        newsize = (bim->size + 127) & ~(bfd_size_type) 127;
     685        if (newsize > oldsize)
     686  	{
     687  	  bim->buffer = (bfd_byte *) bfd_realloc_or_free (bim->buffer, newsize);
     688  	  if (bim->buffer == NULL)
     689  	    {
     690  	      bim->size = 0;
     691  	      return 0;
     692  	    }
     693  	  if (newsize > bim->size)
     694  	    memset (bim->buffer + bim->size, 0, newsize - bim->size);
     695  	}
     696      }
     697    memcpy (bim->buffer + abfd->where, ptr, (size_t) size);
     698    return size;
     699  }
     700  
     701  static file_ptr
     702  memory_btell (bfd *abfd)
     703  {
     704    return abfd->where;
     705  }
     706  
     707  static int
     708  memory_bseek (bfd *abfd, file_ptr position, int direction)
     709  {
     710    file_ptr nwhere;
     711    struct bfd_in_memory *bim;
     712  
     713    bim = (struct bfd_in_memory *) abfd->iostream;
     714  
     715    if (direction == SEEK_SET)
     716      nwhere = position;
     717    else
     718      nwhere = abfd->where + position;
     719  
     720    if (nwhere < 0)
     721      {
     722        abfd->where = 0;
     723        errno = EINVAL;
     724        return -1;
     725      }
     726  
     727    if ((bfd_size_type)nwhere > bim->size)
     728      {
     729        if (abfd->direction == write_direction
     730  	  || abfd->direction == both_direction)
     731  	{
     732  	  bfd_size_type newsize, oldsize;
     733  
     734  	  oldsize = (bim->size + 127) & ~(bfd_size_type) 127;
     735  	  bim->size = nwhere;
     736  	  /* Round up to cut down on memory fragmentation */
     737  	  newsize = (bim->size + 127) & ~(bfd_size_type) 127;
     738  	  if (newsize > oldsize)
     739  	    {
     740  	      bim->buffer = (bfd_byte *) bfd_realloc_or_free (bim->buffer, newsize);
     741  	      if (bim->buffer == NULL)
     742  		{
     743  		  errno = EINVAL;
     744  		  bim->size = 0;
     745  		  return -1;
     746  		}
     747  	      memset (bim->buffer + oldsize, 0, newsize - oldsize);
     748  	    }
     749  	}
     750        else
     751  	{
     752  	  abfd->where = bim->size;
     753  	  errno = EINVAL;
     754  	  bfd_set_error (bfd_error_file_truncated);
     755  	  return -1;
     756  	}
     757      }
     758    return 0;
     759  }
     760  
     761  static int
     762  memory_bclose (struct bfd *abfd)
     763  {
     764    struct bfd_in_memory *bim = (struct bfd_in_memory *) abfd->iostream;
     765  
     766    free (bim->buffer);
     767    free (bim);
     768    abfd->iostream = NULL;
     769  
     770    return 0;
     771  }
     772  
     773  static int
     774  memory_bflush (bfd *abfd ATTRIBUTE_UNUSED)
     775  {
     776    return 0;
     777  }
     778  
     779  static int
     780  memory_bstat (bfd *abfd, struct stat *statbuf)
     781  {
     782    struct bfd_in_memory *bim = (struct bfd_in_memory *) abfd->iostream;
     783  
     784    memset (statbuf, 0, sizeof (*statbuf));
     785    statbuf->st_size = bim->size;
     786  
     787    return 0;
     788  }
     789  
     790  static void *
     791  memory_bmmap (bfd *abfd ATTRIBUTE_UNUSED, void *addr ATTRIBUTE_UNUSED,
     792  	      bfd_size_type len ATTRIBUTE_UNUSED, int prot ATTRIBUTE_UNUSED,
     793  	      int flags ATTRIBUTE_UNUSED, file_ptr offset ATTRIBUTE_UNUSED,
     794  	      void **map_addr ATTRIBUTE_UNUSED,
     795  	      bfd_size_type *map_len ATTRIBUTE_UNUSED)
     796  {
     797    return (void *)-1;
     798  }
     799  
     800  const struct bfd_iovec _bfd_memory_iovec =
     801  {
     802    &memory_bread, &memory_bwrite, &memory_btell, &memory_bseek,
     803    &memory_bclose, &memory_bflush, &memory_bstat, &memory_bmmap
     804  };