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