xref: /dragonfly/contrib/gdb-7/bfd/bfdio.c (revision ef5ccd6c)
15796c8dcSSimon Schubert /* Low-level I/O routines for BFDs.
25796c8dcSSimon Schubert 
35796c8dcSSimon Schubert    Copyright 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1997, 1998,
4a45ae5f8SJohn Marino    1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2011
55796c8dcSSimon Schubert    Free Software Foundation, Inc.
65796c8dcSSimon Schubert 
75796c8dcSSimon Schubert    Written by Cygnus Support.
85796c8dcSSimon Schubert 
95796c8dcSSimon Schubert    This file is part of BFD, the Binary File Descriptor library.
105796c8dcSSimon Schubert 
115796c8dcSSimon Schubert    This program is free software; you can redistribute it and/or modify
125796c8dcSSimon Schubert    it under the terms of the GNU General Public License as published by
135796c8dcSSimon Schubert    the Free Software Foundation; either version 3 of the License, or
145796c8dcSSimon Schubert    (at your option) any later version.
155796c8dcSSimon Schubert 
165796c8dcSSimon Schubert    This program is distributed in the hope that it will be useful,
175796c8dcSSimon Schubert    but WITHOUT ANY WARRANTY; without even the implied warranty of
185796c8dcSSimon Schubert    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
195796c8dcSSimon Schubert    GNU General Public License for more details.
205796c8dcSSimon Schubert 
215796c8dcSSimon Schubert    You should have received a copy of the GNU General Public License
225796c8dcSSimon Schubert    along with this program; if not, write to the Free Software
235796c8dcSSimon Schubert    Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston,
245796c8dcSSimon Schubert    MA 02110-1301, USA.  */
255796c8dcSSimon Schubert 
265796c8dcSSimon Schubert #include "sysdep.h"
275796c8dcSSimon Schubert #include <limits.h>
285796c8dcSSimon Schubert #include "bfd.h"
295796c8dcSSimon Schubert #include "libbfd.h"
305796c8dcSSimon Schubert 
315796c8dcSSimon Schubert #ifndef S_IXUSR
325796c8dcSSimon Schubert #define S_IXUSR 0100    /* Execute by owner.  */
335796c8dcSSimon Schubert #endif
345796c8dcSSimon Schubert #ifndef S_IXGRP
355796c8dcSSimon Schubert #define S_IXGRP 0010    /* Execute by group.  */
365796c8dcSSimon Schubert #endif
375796c8dcSSimon Schubert #ifndef S_IXOTH
385796c8dcSSimon Schubert #define S_IXOTH 0001    /* Execute by others.  */
395796c8dcSSimon Schubert #endif
405796c8dcSSimon Schubert 
415796c8dcSSimon Schubert #ifndef FD_CLOEXEC
425796c8dcSSimon Schubert #define FD_CLOEXEC 1
435796c8dcSSimon Schubert #endif
445796c8dcSSimon Schubert 
455796c8dcSSimon Schubert file_ptr
real_ftell(FILE * file)465796c8dcSSimon Schubert real_ftell (FILE *file)
475796c8dcSSimon Schubert {
485796c8dcSSimon Schubert #if defined (HAVE_FTELLO64)
495796c8dcSSimon Schubert   return ftello64 (file);
505796c8dcSSimon Schubert #elif defined (HAVE_FTELLO)
515796c8dcSSimon Schubert   return ftello (file);
525796c8dcSSimon Schubert #else
535796c8dcSSimon Schubert   return ftell (file);
545796c8dcSSimon Schubert #endif
555796c8dcSSimon Schubert }
565796c8dcSSimon Schubert 
575796c8dcSSimon Schubert int
real_fseek(FILE * file,file_ptr offset,int whence)585796c8dcSSimon Schubert real_fseek (FILE *file, file_ptr offset, int whence)
595796c8dcSSimon Schubert {
605796c8dcSSimon Schubert #if defined (HAVE_FSEEKO64)
615796c8dcSSimon Schubert   return fseeko64 (file, offset, whence);
625796c8dcSSimon Schubert #elif defined (HAVE_FSEEKO)
635796c8dcSSimon Schubert   return fseeko (file, offset, whence);
645796c8dcSSimon Schubert #else
655796c8dcSSimon Schubert   return fseek (file, offset, whence);
665796c8dcSSimon Schubert #endif
675796c8dcSSimon Schubert }
685796c8dcSSimon Schubert 
695796c8dcSSimon Schubert /* Mark FILE as close-on-exec.  Return FILE.  FILE may be NULL, in
705796c8dcSSimon Schubert    which case nothing is done.  */
715796c8dcSSimon Schubert static FILE *
close_on_exec(FILE * file)725796c8dcSSimon Schubert close_on_exec (FILE *file)
735796c8dcSSimon Schubert {
745796c8dcSSimon Schubert #if defined (HAVE_FILENO) && defined (F_GETFD)
755796c8dcSSimon Schubert   if (file)
765796c8dcSSimon Schubert     {
775796c8dcSSimon Schubert       int fd = fileno (file);
785796c8dcSSimon Schubert       int old = fcntl (fd, F_GETFD, 0);
795796c8dcSSimon Schubert       if (old >= 0)
805796c8dcSSimon Schubert 	fcntl (fd, F_SETFD, old | FD_CLOEXEC);
815796c8dcSSimon Schubert     }
825796c8dcSSimon Schubert #endif
835796c8dcSSimon Schubert   return file;
845796c8dcSSimon Schubert }
855796c8dcSSimon Schubert 
865796c8dcSSimon Schubert FILE *
real_fopen(const char * filename,const char * modes)875796c8dcSSimon Schubert real_fopen (const char *filename, const char *modes)
885796c8dcSSimon Schubert {
895796c8dcSSimon Schubert #ifdef VMS
905796c8dcSSimon Schubert   char *vms_attr;
915796c8dcSSimon Schubert 
925796c8dcSSimon Schubert   /* On VMS, fopen allows file attributes as optionnal arguments.
935796c8dcSSimon Schubert      We need to use them but we'd better to use the common prototype.
945796c8dcSSimon Schubert      In fopen-vms.h, they are separated from the mode with a comma.
955796c8dcSSimon Schubert      Split here.  */
965796c8dcSSimon Schubert   vms_attr = strchr (modes, ',');
975796c8dcSSimon Schubert   if (vms_attr == NULL)
985796c8dcSSimon Schubert     {
995796c8dcSSimon Schubert       /* No attributes.  */
1005796c8dcSSimon Schubert       return close_on_exec (fopen (filename, modes));
1015796c8dcSSimon Schubert     }
1025796c8dcSSimon Schubert   else
1035796c8dcSSimon Schubert     {
1045796c8dcSSimon Schubert       /* Attributes found.  Split.  */
1055796c8dcSSimon Schubert       size_t modes_len = strlen (modes) + 1;
1065796c8dcSSimon Schubert       char attrs[modes_len + 1];
1075796c8dcSSimon Schubert       char *at[3];
1085796c8dcSSimon Schubert       int i;
1095796c8dcSSimon Schubert 
1105796c8dcSSimon Schubert       memcpy (attrs, modes, modes_len);
1115796c8dcSSimon Schubert       at[0] = attrs;
1125796c8dcSSimon Schubert       for (i = 0; i < 2; i++)
1135796c8dcSSimon Schubert 	{
1145796c8dcSSimon Schubert 	  at[i + 1] = strchr (at[i], ',');
1155796c8dcSSimon Schubert 	  BFD_ASSERT (at[i + 1] != NULL);
1165796c8dcSSimon Schubert 	  *(at[i + 1]++) = 0; /* Replace ',' with a nul, and skip it.  */
1175796c8dcSSimon Schubert 	}
1185796c8dcSSimon Schubert       return close_on_exec (fopen (filename, at[0], at[1], at[2]));
1195796c8dcSSimon Schubert     }
1205796c8dcSSimon Schubert #else /* !VMS */
1215796c8dcSSimon Schubert #if defined (HAVE_FOPEN64)
1225796c8dcSSimon Schubert   return close_on_exec (fopen64 (filename, modes));
1235796c8dcSSimon Schubert #else
1245796c8dcSSimon Schubert   return close_on_exec (fopen (filename, modes));
1255796c8dcSSimon Schubert #endif
1265796c8dcSSimon Schubert #endif /* !VMS */
1275796c8dcSSimon Schubert }
1285796c8dcSSimon Schubert 
1295796c8dcSSimon Schubert /*
1305796c8dcSSimon Schubert INTERNAL_DEFINITION
1315796c8dcSSimon Schubert 	struct bfd_iovec
1325796c8dcSSimon Schubert 
1335796c8dcSSimon Schubert DESCRIPTION
1345796c8dcSSimon Schubert 
1355796c8dcSSimon Schubert 	The <<struct bfd_iovec>> contains the internal file I/O class.
1365796c8dcSSimon Schubert 	Each <<BFD>> has an instance of this class and all file I/O is
1375796c8dcSSimon Schubert 	routed through it (it is assumed that the instance implements
1385796c8dcSSimon Schubert 	all methods listed below).
1395796c8dcSSimon Schubert 
1405796c8dcSSimon Schubert .struct bfd_iovec
1415796c8dcSSimon Schubert .{
1425796c8dcSSimon Schubert .  {* To avoid problems with macros, a "b" rather than "f"
1435796c8dcSSimon Schubert .     prefix is prepended to each method name.  *}
1445796c8dcSSimon Schubert .  {* Attempt to read/write NBYTES on ABFD's IOSTREAM storing/fetching
1455796c8dcSSimon Schubert .     bytes starting at PTR.  Return the number of bytes actually
1465796c8dcSSimon Schubert .     transfered (a read past end-of-file returns less than NBYTES),
1475796c8dcSSimon Schubert .     or -1 (setting <<bfd_error>>) if an error occurs.  *}
1485796c8dcSSimon Schubert .  file_ptr (*bread) (struct bfd *abfd, void *ptr, file_ptr nbytes);
1495796c8dcSSimon Schubert .  file_ptr (*bwrite) (struct bfd *abfd, const void *ptr,
1505796c8dcSSimon Schubert .                      file_ptr nbytes);
1515796c8dcSSimon Schubert .  {* Return the current IOSTREAM file offset, or -1 (setting <<bfd_error>>
1525796c8dcSSimon Schubert .     if an error occurs.  *}
1535796c8dcSSimon Schubert .  file_ptr (*btell) (struct bfd *abfd);
1545796c8dcSSimon Schubert .  {* For the following, on successful completion a value of 0 is returned.
1555796c8dcSSimon Schubert .     Otherwise, a value of -1 is returned (and  <<bfd_error>> is set).  *}
1565796c8dcSSimon Schubert .  int (*bseek) (struct bfd *abfd, file_ptr offset, int whence);
1575796c8dcSSimon Schubert .  int (*bclose) (struct bfd *abfd);
1585796c8dcSSimon Schubert .  int (*bflush) (struct bfd *abfd);
1595796c8dcSSimon Schubert .  int (*bstat) (struct bfd *abfd, struct stat *sb);
160a45ae5f8SJohn Marino .  {* Mmap a part of the files. ADDR, LEN, PROT, FLAGS and OFFSET are the usual
161a45ae5f8SJohn Marino .     mmap parameter, except that LEN and OFFSET do not need to be page
162a45ae5f8SJohn Marino .     aligned.  Returns (void *)-1 on failure, mmapped address on success.
163a45ae5f8SJohn Marino .     Also write in MAP_ADDR the address of the page aligned buffer and in
164a45ae5f8SJohn Marino .     MAP_LEN the size mapped (a page multiple).  Use unmap with MAP_ADDR and
165a45ae5f8SJohn Marino .     MAP_LEN to unmap.  *}
1665796c8dcSSimon Schubert .  void *(*bmmap) (struct bfd *abfd, void *addr, bfd_size_type len,
167a45ae5f8SJohn Marino .                  int prot, int flags, file_ptr offset,
168a45ae5f8SJohn Marino .                  void **map_addr, bfd_size_type *map_len);
1695796c8dcSSimon Schubert .};
1705796c8dcSSimon Schubert 
171cf7f2e2dSJohn Marino .extern const struct bfd_iovec _bfd_memory_iovec;
172cf7f2e2dSJohn Marino 
1735796c8dcSSimon Schubert */
1745796c8dcSSimon Schubert 
1755796c8dcSSimon Schubert 
1765796c8dcSSimon Schubert /* Return value is amount read.  */
1775796c8dcSSimon Schubert 
1785796c8dcSSimon Schubert bfd_size_type
bfd_bread(void * ptr,bfd_size_type size,bfd * abfd)1795796c8dcSSimon Schubert bfd_bread (void *ptr, bfd_size_type size, bfd *abfd)
1805796c8dcSSimon Schubert {
1815796c8dcSSimon Schubert   size_t nread;
1825796c8dcSSimon Schubert 
1835796c8dcSSimon Schubert   /* If this is an archive element, don't read past the end of
1845796c8dcSSimon Schubert      this element.  */
1855796c8dcSSimon Schubert   if (abfd->arelt_data != NULL)
1865796c8dcSSimon Schubert     {
187*ef5ccd6cSJohn Marino       bfd_size_type maxbytes = arelt_size (abfd);
188*ef5ccd6cSJohn Marino 
189cf7f2e2dSJohn Marino       if (abfd->where + size > maxbytes)
1905796c8dcSSimon Schubert         {
191cf7f2e2dSJohn Marino           if (abfd->where >= maxbytes)
192cf7f2e2dSJohn Marino             return 0;
193cf7f2e2dSJohn Marino           size = maxbytes - abfd->where;
1945796c8dcSSimon Schubert         }
1955796c8dcSSimon Schubert     }
1965796c8dcSSimon Schubert 
1975796c8dcSSimon Schubert   if (abfd->iovec)
1985796c8dcSSimon Schubert     nread = abfd->iovec->bread (abfd, ptr, size);
1995796c8dcSSimon Schubert   else
2005796c8dcSSimon Schubert     nread = 0;
2015796c8dcSSimon Schubert   if (nread != (size_t) -1)
2025796c8dcSSimon Schubert     abfd->where += nread;
2035796c8dcSSimon Schubert 
2045796c8dcSSimon Schubert   return nread;
2055796c8dcSSimon Schubert }
2065796c8dcSSimon Schubert 
2075796c8dcSSimon Schubert bfd_size_type
bfd_bwrite(const void * ptr,bfd_size_type size,bfd * abfd)2085796c8dcSSimon Schubert bfd_bwrite (const void *ptr, bfd_size_type size, bfd *abfd)
2095796c8dcSSimon Schubert {
2105796c8dcSSimon Schubert   size_t nwrote;
2115796c8dcSSimon Schubert 
2125796c8dcSSimon Schubert   if (abfd->iovec)
2135796c8dcSSimon Schubert     nwrote = abfd->iovec->bwrite (abfd, ptr, size);
2145796c8dcSSimon Schubert   else
2155796c8dcSSimon Schubert     nwrote = 0;
2165796c8dcSSimon Schubert 
2175796c8dcSSimon Schubert   if (nwrote != (size_t) -1)
2185796c8dcSSimon Schubert     abfd->where += nwrote;
2195796c8dcSSimon Schubert   if (nwrote != size)
2205796c8dcSSimon Schubert     {
2215796c8dcSSimon Schubert #ifdef ENOSPC
2225796c8dcSSimon Schubert       errno = ENOSPC;
2235796c8dcSSimon Schubert #endif
2245796c8dcSSimon Schubert       bfd_set_error (bfd_error_system_call);
2255796c8dcSSimon Schubert     }
2265796c8dcSSimon Schubert   return nwrote;
2275796c8dcSSimon Schubert }
2285796c8dcSSimon Schubert 
2295796c8dcSSimon Schubert file_ptr
bfd_tell(bfd * abfd)2305796c8dcSSimon Schubert bfd_tell (bfd *abfd)
2315796c8dcSSimon Schubert {
2325796c8dcSSimon Schubert   file_ptr ptr;
2335796c8dcSSimon Schubert 
2345796c8dcSSimon Schubert   if (abfd->iovec)
2355796c8dcSSimon Schubert     {
236*ef5ccd6cSJohn Marino       bfd *parent_bfd = abfd;
2375796c8dcSSimon Schubert       ptr = abfd->iovec->btell (abfd);
2385796c8dcSSimon Schubert 
239*ef5ccd6cSJohn Marino       while (parent_bfd->my_archive != NULL)
240*ef5ccd6cSJohn Marino 	{
241*ef5ccd6cSJohn Marino 	  ptr -= parent_bfd->origin;
242*ef5ccd6cSJohn Marino 	  parent_bfd = parent_bfd->my_archive;
243*ef5ccd6cSJohn Marino 	}
2445796c8dcSSimon Schubert     }
2455796c8dcSSimon Schubert   else
2465796c8dcSSimon Schubert     ptr = 0;
2475796c8dcSSimon Schubert 
2485796c8dcSSimon Schubert   abfd->where = ptr;
2495796c8dcSSimon Schubert   return ptr;
2505796c8dcSSimon Schubert }
2515796c8dcSSimon Schubert 
2525796c8dcSSimon Schubert int
bfd_flush(bfd * abfd)2535796c8dcSSimon Schubert bfd_flush (bfd *abfd)
2545796c8dcSSimon Schubert {
2555796c8dcSSimon Schubert   if (abfd->iovec)
2565796c8dcSSimon Schubert     return abfd->iovec->bflush (abfd);
2575796c8dcSSimon Schubert   return 0;
2585796c8dcSSimon Schubert }
2595796c8dcSSimon Schubert 
2605796c8dcSSimon Schubert /* Returns 0 for success, negative value for failure (in which case
2615796c8dcSSimon Schubert    bfd_get_error can retrieve the error code).  */
2625796c8dcSSimon Schubert int
bfd_stat(bfd * abfd,struct stat * statbuf)2635796c8dcSSimon Schubert bfd_stat (bfd *abfd, struct stat *statbuf)
2645796c8dcSSimon Schubert {
2655796c8dcSSimon Schubert   int result;
2665796c8dcSSimon Schubert 
2675796c8dcSSimon Schubert   if (abfd->iovec)
2685796c8dcSSimon Schubert     result = abfd->iovec->bstat (abfd, statbuf);
2695796c8dcSSimon Schubert   else
2705796c8dcSSimon Schubert     result = -1;
2715796c8dcSSimon Schubert 
2725796c8dcSSimon Schubert   if (result < 0)
2735796c8dcSSimon Schubert     bfd_set_error (bfd_error_system_call);
2745796c8dcSSimon Schubert   return result;
2755796c8dcSSimon Schubert }
2765796c8dcSSimon Schubert 
2775796c8dcSSimon Schubert /* Returns 0 for success, nonzero for failure (in which case bfd_get_error
2785796c8dcSSimon Schubert    can retrieve the error code).  */
2795796c8dcSSimon Schubert 
2805796c8dcSSimon Schubert int
bfd_seek(bfd * abfd,file_ptr position,int direction)2815796c8dcSSimon Schubert bfd_seek (bfd *abfd, file_ptr position, int direction)
2825796c8dcSSimon Schubert {
2835796c8dcSSimon Schubert   int result;
2845796c8dcSSimon Schubert   file_ptr file_position;
2855796c8dcSSimon Schubert   /* For the time being, a BFD may not seek to it's end.  The problem
2865796c8dcSSimon Schubert      is that we don't easily have a way to recognize the end of an
2875796c8dcSSimon Schubert      element in an archive.  */
2885796c8dcSSimon Schubert 
2895796c8dcSSimon Schubert   BFD_ASSERT (direction == SEEK_SET || direction == SEEK_CUR);
2905796c8dcSSimon Schubert 
2915796c8dcSSimon Schubert   if (direction == SEEK_CUR && position == 0)
2925796c8dcSSimon Schubert     return 0;
2935796c8dcSSimon Schubert 
2945796c8dcSSimon Schubert   if (abfd->format != bfd_archive && abfd->my_archive == 0)
2955796c8dcSSimon Schubert     {
2965796c8dcSSimon Schubert       if (direction == SEEK_SET && (bfd_vma) position == abfd->where)
2975796c8dcSSimon Schubert 	return 0;
2985796c8dcSSimon Schubert     }
2995796c8dcSSimon Schubert   else
3005796c8dcSSimon Schubert     {
3015796c8dcSSimon Schubert       /* We need something smarter to optimize access to archives.
3025796c8dcSSimon Schubert 	 Currently, anything inside an archive is read via the file
3035796c8dcSSimon Schubert 	 handle for the archive.  Which means that a bfd_seek on one
3045796c8dcSSimon Schubert 	 component affects the `current position' in the archive, as
3055796c8dcSSimon Schubert 	 well as in any other component.
3065796c8dcSSimon Schubert 
3075796c8dcSSimon Schubert 	 It might be sufficient to put a spike through the cache
3085796c8dcSSimon Schubert 	 abstraction, and look to the archive for the file position,
3095796c8dcSSimon Schubert 	 but I think we should try for something cleaner.
3105796c8dcSSimon Schubert 
3115796c8dcSSimon Schubert 	 In the meantime, no optimization for archives.  */
3125796c8dcSSimon Schubert     }
3135796c8dcSSimon Schubert 
3145796c8dcSSimon Schubert   file_position = position;
315*ef5ccd6cSJohn Marino   if (direction == SEEK_SET)
316*ef5ccd6cSJohn Marino     {
317*ef5ccd6cSJohn Marino       bfd *parent_bfd = abfd;
318*ef5ccd6cSJohn Marino 
319*ef5ccd6cSJohn Marino       while (parent_bfd->my_archive != NULL)
320*ef5ccd6cSJohn Marino         {
321*ef5ccd6cSJohn Marino           file_position += parent_bfd->origin;
322*ef5ccd6cSJohn Marino           parent_bfd = parent_bfd->my_archive;
323*ef5ccd6cSJohn Marino         }
324*ef5ccd6cSJohn Marino     }
3255796c8dcSSimon Schubert 
3265796c8dcSSimon Schubert   if (abfd->iovec)
3275796c8dcSSimon Schubert     result = abfd->iovec->bseek (abfd, file_position, direction);
3285796c8dcSSimon Schubert   else
3295796c8dcSSimon Schubert     result = -1;
3305796c8dcSSimon Schubert 
3315796c8dcSSimon Schubert   if (result != 0)
3325796c8dcSSimon Schubert     {
3335796c8dcSSimon Schubert       int hold_errno = errno;
3345796c8dcSSimon Schubert 
3355796c8dcSSimon Schubert       /* Force redetermination of `where' field.  */
3365796c8dcSSimon Schubert       bfd_tell (abfd);
3375796c8dcSSimon Schubert 
3385796c8dcSSimon Schubert       /* An EINVAL error probably means that the file offset was
3395796c8dcSSimon Schubert          absurd.  */
3405796c8dcSSimon Schubert       if (hold_errno == EINVAL)
3415796c8dcSSimon Schubert 	bfd_set_error (bfd_error_file_truncated);
3425796c8dcSSimon Schubert       else
3435796c8dcSSimon Schubert 	{
3445796c8dcSSimon Schubert 	  bfd_set_error (bfd_error_system_call);
3455796c8dcSSimon Schubert 	  errno = hold_errno;
3465796c8dcSSimon Schubert 	}
3475796c8dcSSimon Schubert     }
3485796c8dcSSimon Schubert   else
3495796c8dcSSimon Schubert     {
3505796c8dcSSimon Schubert       /* Adjust `where' field.  */
3515796c8dcSSimon Schubert       if (direction == SEEK_SET)
3525796c8dcSSimon Schubert 	abfd->where = position;
3535796c8dcSSimon Schubert       else
3545796c8dcSSimon Schubert 	abfd->where += position;
3555796c8dcSSimon Schubert     }
3565796c8dcSSimon Schubert   return result;
3575796c8dcSSimon Schubert }
3585796c8dcSSimon Schubert 
3595796c8dcSSimon Schubert /*
3605796c8dcSSimon Schubert FUNCTION
3615796c8dcSSimon Schubert 	bfd_get_mtime
3625796c8dcSSimon Schubert 
3635796c8dcSSimon Schubert SYNOPSIS
3645796c8dcSSimon Schubert 	long bfd_get_mtime (bfd *abfd);
3655796c8dcSSimon Schubert 
3665796c8dcSSimon Schubert DESCRIPTION
3675796c8dcSSimon Schubert 	Return the file modification time (as read from the file system, or
3685796c8dcSSimon Schubert 	from the archive header for archive members).
3695796c8dcSSimon Schubert 
3705796c8dcSSimon Schubert */
3715796c8dcSSimon Schubert 
3725796c8dcSSimon Schubert long
bfd_get_mtime(bfd * abfd)3735796c8dcSSimon Schubert bfd_get_mtime (bfd *abfd)
3745796c8dcSSimon Schubert {
3755796c8dcSSimon Schubert   struct stat buf;
3765796c8dcSSimon Schubert 
3775796c8dcSSimon Schubert   if (abfd->mtime_set)
3785796c8dcSSimon Schubert     return abfd->mtime;
3795796c8dcSSimon Schubert 
3805796c8dcSSimon Schubert   if (abfd->iovec == NULL)
3815796c8dcSSimon Schubert     return 0;
3825796c8dcSSimon Schubert 
3835796c8dcSSimon Schubert   if (abfd->iovec->bstat (abfd, &buf) != 0)
3845796c8dcSSimon Schubert     return 0;
3855796c8dcSSimon Schubert 
3865796c8dcSSimon Schubert   abfd->mtime = buf.st_mtime;		/* Save value in case anyone wants it */
3875796c8dcSSimon Schubert   return buf.st_mtime;
3885796c8dcSSimon Schubert }
3895796c8dcSSimon Schubert 
3905796c8dcSSimon Schubert /*
3915796c8dcSSimon Schubert FUNCTION
3925796c8dcSSimon Schubert 	bfd_get_size
3935796c8dcSSimon Schubert 
3945796c8dcSSimon Schubert SYNOPSIS
3955796c8dcSSimon Schubert 	file_ptr bfd_get_size (bfd *abfd);
3965796c8dcSSimon Schubert 
3975796c8dcSSimon Schubert DESCRIPTION
3985796c8dcSSimon Schubert 	Return the file size (as read from file system) for the file
3995796c8dcSSimon Schubert 	associated with BFD @var{abfd}.
4005796c8dcSSimon Schubert 
4015796c8dcSSimon Schubert 	The initial motivation for, and use of, this routine is not
4025796c8dcSSimon Schubert 	so we can get the exact size of the object the BFD applies to, since
4035796c8dcSSimon Schubert 	that might not be generally possible (archive members for example).
4045796c8dcSSimon Schubert 	It would be ideal if someone could eventually modify
4055796c8dcSSimon Schubert 	it so that such results were guaranteed.
4065796c8dcSSimon Schubert 
4075796c8dcSSimon Schubert 	Instead, we want to ask questions like "is this NNN byte sized
4085796c8dcSSimon Schubert 	object I'm about to try read from file offset YYY reasonable?"
4095796c8dcSSimon Schubert 	As as example of where we might do this, some object formats
4105796c8dcSSimon Schubert 	use string tables for which the first <<sizeof (long)>> bytes of the
4115796c8dcSSimon Schubert 	table contain the size of the table itself, including the size bytes.
4125796c8dcSSimon Schubert 	If an application tries to read what it thinks is one of these
4135796c8dcSSimon Schubert 	string tables, without some way to validate the size, and for
4145796c8dcSSimon Schubert 	some reason the size is wrong (byte swapping error, wrong location
4155796c8dcSSimon Schubert 	for the string table, etc.), the only clue is likely to be a read
4165796c8dcSSimon Schubert 	error when it tries to read the table, or a "virtual memory
4175796c8dcSSimon Schubert 	exhausted" error when it tries to allocate 15 bazillon bytes
4185796c8dcSSimon Schubert 	of space for the 15 bazillon byte table it is about to read.
4195796c8dcSSimon Schubert 	This function at least allows us to answer the question, "is the
4205796c8dcSSimon Schubert 	size reasonable?".
4215796c8dcSSimon Schubert */
4225796c8dcSSimon Schubert 
4235796c8dcSSimon Schubert file_ptr
bfd_get_size(bfd * abfd)4245796c8dcSSimon Schubert bfd_get_size (bfd *abfd)
4255796c8dcSSimon Schubert {
4265796c8dcSSimon Schubert   struct stat buf;
4275796c8dcSSimon Schubert 
4285796c8dcSSimon Schubert   if (abfd->iovec == NULL)
4295796c8dcSSimon Schubert     return 0;
4305796c8dcSSimon Schubert 
4315796c8dcSSimon Schubert   if (abfd->iovec->bstat (abfd, &buf) != 0)
4325796c8dcSSimon Schubert     return 0;
4335796c8dcSSimon Schubert 
4345796c8dcSSimon Schubert   return buf.st_size;
4355796c8dcSSimon Schubert }
4365796c8dcSSimon Schubert 
4375796c8dcSSimon Schubert 
4385796c8dcSSimon Schubert /*
4395796c8dcSSimon Schubert FUNCTION
4405796c8dcSSimon Schubert 	bfd_mmap
4415796c8dcSSimon Schubert 
4425796c8dcSSimon Schubert SYNOPSIS
4435796c8dcSSimon Schubert 	void *bfd_mmap (bfd *abfd, void *addr, bfd_size_type len,
444a45ae5f8SJohn Marino 	                int prot, int flags, file_ptr offset,
445a45ae5f8SJohn Marino 	                void **map_addr, bfd_size_type *map_len);
4465796c8dcSSimon Schubert 
4475796c8dcSSimon Schubert DESCRIPTION
4485796c8dcSSimon Schubert 	Return mmap()ed region of the file, if possible and implemented.
449a45ae5f8SJohn Marino         LEN and OFFSET do not need to be page aligned.  The page aligned
450a45ae5f8SJohn Marino         address and length are written to MAP_ADDR and MAP_LEN.
4515796c8dcSSimon Schubert 
4525796c8dcSSimon Schubert */
4535796c8dcSSimon Schubert 
4545796c8dcSSimon Schubert void *
bfd_mmap(bfd * abfd,void * addr,bfd_size_type len,int prot,int flags,file_ptr offset,void ** map_addr,bfd_size_type * map_len)4555796c8dcSSimon Schubert bfd_mmap (bfd *abfd, void *addr, bfd_size_type len,
456a45ae5f8SJohn Marino 	  int prot, int flags, file_ptr offset,
457a45ae5f8SJohn Marino           void **map_addr, bfd_size_type *map_len)
4585796c8dcSSimon Schubert {
4595796c8dcSSimon Schubert   void *ret = (void *)-1;
4605796c8dcSSimon Schubert 
4615796c8dcSSimon Schubert   if (abfd->iovec == NULL)
4625796c8dcSSimon Schubert     return ret;
4635796c8dcSSimon Schubert 
464a45ae5f8SJohn Marino   return abfd->iovec->bmmap (abfd, addr, len, prot, flags, offset,
465a45ae5f8SJohn Marino                              map_addr, map_len);
4665796c8dcSSimon Schubert }
467cf7f2e2dSJohn Marino 
468cf7f2e2dSJohn Marino /* Memory file I/O operations.  */
469cf7f2e2dSJohn Marino 
470cf7f2e2dSJohn Marino static file_ptr
memory_bread(bfd * abfd,void * ptr,file_ptr size)471cf7f2e2dSJohn Marino memory_bread (bfd *abfd, void *ptr, file_ptr size)
472cf7f2e2dSJohn Marino {
473cf7f2e2dSJohn Marino   struct bfd_in_memory *bim;
474cf7f2e2dSJohn Marino   bfd_size_type get;
475cf7f2e2dSJohn Marino 
476cf7f2e2dSJohn Marino   bim = (struct bfd_in_memory *) abfd->iostream;
477cf7f2e2dSJohn Marino   get = size;
478cf7f2e2dSJohn Marino   if (abfd->where + get > bim->size)
479cf7f2e2dSJohn Marino     {
480cf7f2e2dSJohn Marino       if (bim->size < (bfd_size_type) abfd->where)
481cf7f2e2dSJohn Marino         get = 0;
482cf7f2e2dSJohn Marino       else
483cf7f2e2dSJohn Marino         get = bim->size - abfd->where;
484cf7f2e2dSJohn Marino       bfd_set_error (bfd_error_file_truncated);
485cf7f2e2dSJohn Marino     }
486cf7f2e2dSJohn Marino   memcpy (ptr, bim->buffer + abfd->where, (size_t) get);
487cf7f2e2dSJohn Marino   return get;
488cf7f2e2dSJohn Marino }
489cf7f2e2dSJohn Marino 
490cf7f2e2dSJohn Marino static file_ptr
memory_bwrite(bfd * abfd,const void * ptr,file_ptr size)491cf7f2e2dSJohn Marino memory_bwrite (bfd *abfd, const void *ptr, file_ptr size)
492cf7f2e2dSJohn Marino {
493cf7f2e2dSJohn Marino   struct bfd_in_memory *bim = (struct bfd_in_memory *) abfd->iostream;
494cf7f2e2dSJohn Marino 
495cf7f2e2dSJohn Marino   if (abfd->where + size > bim->size)
496cf7f2e2dSJohn Marino     {
497cf7f2e2dSJohn Marino       bfd_size_type newsize, oldsize;
498cf7f2e2dSJohn Marino 
499cf7f2e2dSJohn Marino       oldsize = (bim->size + 127) & ~(bfd_size_type) 127;
500cf7f2e2dSJohn Marino       bim->size = abfd->where + size;
501cf7f2e2dSJohn Marino       /* Round up to cut down on memory fragmentation */
502cf7f2e2dSJohn Marino       newsize = (bim->size + 127) & ~(bfd_size_type) 127;
503cf7f2e2dSJohn Marino       if (newsize > oldsize)
504cf7f2e2dSJohn Marino         {
505cf7f2e2dSJohn Marino           bim->buffer = (bfd_byte *) bfd_realloc_or_free (bim->buffer, newsize);
506cf7f2e2dSJohn Marino           if (bim->buffer == NULL)
507cf7f2e2dSJohn Marino             {
508cf7f2e2dSJohn Marino               bim->size = 0;
509cf7f2e2dSJohn Marino               return 0;
510cf7f2e2dSJohn Marino             }
511cf7f2e2dSJohn Marino           if (newsize > bim->size)
512cf7f2e2dSJohn Marino             memset (bim->buffer + bim->size, 0, newsize - bim->size);
513cf7f2e2dSJohn Marino         }
514cf7f2e2dSJohn Marino     }
515cf7f2e2dSJohn Marino   memcpy (bim->buffer + abfd->where, ptr, (size_t) size);
516cf7f2e2dSJohn Marino   return size;
517cf7f2e2dSJohn Marino }
518cf7f2e2dSJohn Marino 
519cf7f2e2dSJohn Marino static file_ptr
memory_btell(bfd * abfd)520cf7f2e2dSJohn Marino memory_btell (bfd *abfd)
521cf7f2e2dSJohn Marino {
522cf7f2e2dSJohn Marino   return abfd->where;
523cf7f2e2dSJohn Marino }
524cf7f2e2dSJohn Marino 
525cf7f2e2dSJohn Marino static int
memory_bseek(bfd * abfd,file_ptr position,int direction)526cf7f2e2dSJohn Marino memory_bseek (bfd *abfd, file_ptr position, int direction)
527cf7f2e2dSJohn Marino {
528cf7f2e2dSJohn Marino   file_ptr nwhere;
529cf7f2e2dSJohn Marino   struct bfd_in_memory *bim;
530cf7f2e2dSJohn Marino 
531cf7f2e2dSJohn Marino   bim = (struct bfd_in_memory *) abfd->iostream;
532cf7f2e2dSJohn Marino 
533cf7f2e2dSJohn Marino   if (direction == SEEK_SET)
534cf7f2e2dSJohn Marino     nwhere = position;
535cf7f2e2dSJohn Marino   else
536cf7f2e2dSJohn Marino     nwhere = abfd->where + position;
537cf7f2e2dSJohn Marino 
538cf7f2e2dSJohn Marino   if (nwhere < 0)
539cf7f2e2dSJohn Marino     {
540cf7f2e2dSJohn Marino       abfd->where = 0;
541cf7f2e2dSJohn Marino       errno = EINVAL;
542cf7f2e2dSJohn Marino       return -1;
543cf7f2e2dSJohn Marino     }
544cf7f2e2dSJohn Marino 
545cf7f2e2dSJohn Marino   if ((bfd_size_type)nwhere > bim->size)
546cf7f2e2dSJohn Marino     {
547cf7f2e2dSJohn Marino       if (abfd->direction == write_direction
548cf7f2e2dSJohn Marino           || abfd->direction == both_direction)
549cf7f2e2dSJohn Marino         {
550cf7f2e2dSJohn Marino           bfd_size_type newsize, oldsize;
551cf7f2e2dSJohn Marino 
552cf7f2e2dSJohn Marino           oldsize = (bim->size + 127) & ~(bfd_size_type) 127;
553cf7f2e2dSJohn Marino           bim->size = nwhere;
554cf7f2e2dSJohn Marino           /* Round up to cut down on memory fragmentation */
555cf7f2e2dSJohn Marino           newsize = (bim->size + 127) & ~(bfd_size_type) 127;
556cf7f2e2dSJohn Marino           if (newsize > oldsize)
557cf7f2e2dSJohn Marino             {
558cf7f2e2dSJohn Marino               bim->buffer = (bfd_byte *) bfd_realloc_or_free (bim->buffer, newsize);
559cf7f2e2dSJohn Marino               if (bim->buffer == NULL)
560cf7f2e2dSJohn Marino                 {
561cf7f2e2dSJohn Marino                   errno = EINVAL;
562cf7f2e2dSJohn Marino                   bim->size = 0;
563cf7f2e2dSJohn Marino                   return -1;
564cf7f2e2dSJohn Marino                 }
565cf7f2e2dSJohn Marino               memset (bim->buffer + oldsize, 0, newsize - oldsize);
566cf7f2e2dSJohn Marino             }
567cf7f2e2dSJohn Marino         }
568cf7f2e2dSJohn Marino       else
569cf7f2e2dSJohn Marino         {
570cf7f2e2dSJohn Marino           abfd->where = bim->size;
571cf7f2e2dSJohn Marino           errno = EINVAL;
572cf7f2e2dSJohn Marino           bfd_set_error (bfd_error_file_truncated);
573cf7f2e2dSJohn Marino           return -1;
574cf7f2e2dSJohn Marino         }
575cf7f2e2dSJohn Marino     }
576cf7f2e2dSJohn Marino   return 0;
577cf7f2e2dSJohn Marino }
578cf7f2e2dSJohn Marino 
579cf7f2e2dSJohn Marino static int
memory_bclose(struct bfd * abfd)580cf7f2e2dSJohn Marino memory_bclose (struct bfd *abfd)
581cf7f2e2dSJohn Marino {
582cf7f2e2dSJohn Marino   struct bfd_in_memory *bim = (struct bfd_in_memory *) abfd->iostream;
583cf7f2e2dSJohn Marino 
584cf7f2e2dSJohn Marino   if (bim->buffer != NULL)
585cf7f2e2dSJohn Marino     free (bim->buffer);
586cf7f2e2dSJohn Marino   free (bim);
587cf7f2e2dSJohn Marino   abfd->iostream = NULL;
588cf7f2e2dSJohn Marino 
589*ef5ccd6cSJohn Marino   return 0;
590cf7f2e2dSJohn Marino }
591cf7f2e2dSJohn Marino 
592cf7f2e2dSJohn Marino static int
memory_bflush(bfd * abfd ATTRIBUTE_UNUSED)593cf7f2e2dSJohn Marino memory_bflush (bfd *abfd ATTRIBUTE_UNUSED)
594cf7f2e2dSJohn Marino {
595cf7f2e2dSJohn Marino   return 0;
596cf7f2e2dSJohn Marino }
597cf7f2e2dSJohn Marino 
598cf7f2e2dSJohn Marino static int
memory_bstat(bfd * abfd,struct stat * statbuf)599cf7f2e2dSJohn Marino memory_bstat (bfd *abfd, struct stat *statbuf)
600cf7f2e2dSJohn Marino {
601cf7f2e2dSJohn Marino   struct bfd_in_memory *bim = (struct bfd_in_memory *) abfd->iostream;
602cf7f2e2dSJohn Marino 
603a45ae5f8SJohn Marino   memset (statbuf, 0, sizeof (*statbuf));
604cf7f2e2dSJohn Marino   statbuf->st_size = bim->size;
605cf7f2e2dSJohn Marino 
606cf7f2e2dSJohn Marino   return 0;
607cf7f2e2dSJohn Marino }
608cf7f2e2dSJohn Marino 
609cf7f2e2dSJohn Marino static void *
memory_bmmap(bfd * abfd ATTRIBUTE_UNUSED,void * addr ATTRIBUTE_UNUSED,bfd_size_type len ATTRIBUTE_UNUSED,int prot ATTRIBUTE_UNUSED,int flags ATTRIBUTE_UNUSED,file_ptr offset ATTRIBUTE_UNUSED,void ** map_addr ATTRIBUTE_UNUSED,bfd_size_type * map_len ATTRIBUTE_UNUSED)610cf7f2e2dSJohn Marino memory_bmmap (bfd *abfd ATTRIBUTE_UNUSED, void *addr ATTRIBUTE_UNUSED,
611cf7f2e2dSJohn Marino               bfd_size_type len ATTRIBUTE_UNUSED, int prot ATTRIBUTE_UNUSED,
612a45ae5f8SJohn Marino               int flags ATTRIBUTE_UNUSED, file_ptr offset ATTRIBUTE_UNUSED,
613a45ae5f8SJohn Marino               void **map_addr ATTRIBUTE_UNUSED,
614a45ae5f8SJohn Marino               bfd_size_type *map_len ATTRIBUTE_UNUSED)
615cf7f2e2dSJohn Marino {
616cf7f2e2dSJohn Marino   return (void *)-1;
617cf7f2e2dSJohn Marino }
618cf7f2e2dSJohn Marino 
619cf7f2e2dSJohn Marino const struct bfd_iovec _bfd_memory_iovec =
620cf7f2e2dSJohn Marino {
621cf7f2e2dSJohn Marino   &memory_bread, &memory_bwrite, &memory_btell, &memory_bseek,
622cf7f2e2dSJohn Marino   &memory_bclose, &memory_bflush, &memory_bstat, &memory_bmmap
623cf7f2e2dSJohn Marino };
624