Back to index

cell-binutils  2.17cvs20070401
bfdio.c
Go to the documentation of this file.
00001 /* Low-level I/O routines for BFDs.
00002 
00003    Copyright 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1997, 1998,
00004    1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006
00005    Free Software Foundation, Inc.
00006 
00007    Written by Cygnus Support.
00008 
00009 This file is part of BFD, the Binary File Descriptor library.
00010 
00011 This program is free software; you can redistribute it and/or modify
00012 it under the terms of the GNU General Public License as published by
00013 the Free Software Foundation; either version 2 of the License, or
00014 (at your option) any later version.
00015 
00016 This program is distributed in the hope that it will be useful,
00017 but WITHOUT ANY WARRANTY; without even the implied warranty of
00018 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00019 GNU General Public License for more details.
00020 
00021 You should have received a copy of the GNU General Public License
00022 along with this program; if not, write to the Free Software
00023 Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA.  */
00024 
00025 #include "sysdep.h"
00026 
00027 #include "bfd.h"
00028 #include "libbfd.h"
00029 
00030 #include <limits.h>
00031 
00032 #ifndef S_IXUSR
00033 #define S_IXUSR 0100    /* Execute by owner.  */
00034 #endif
00035 #ifndef S_IXGRP
00036 #define S_IXGRP 0010    /* Execute by group.  */
00037 #endif
00038 #ifndef S_IXOTH
00039 #define S_IXOTH 0001    /* Execute by others.  */
00040 #endif
00041 
00042 file_ptr
00043 real_ftell (FILE *file)
00044 {
00045 #if defined (HAVE_FTELLO64)
00046   return ftello64 (file);
00047 #elif defined (HAVE_FTELLO)
00048   return ftello (file);
00049 #else
00050   return ftell (file);
00051 #endif
00052 }
00053 
00054 int
00055 real_fseek (FILE *file, file_ptr offset, int whence)
00056 {
00057 #if defined (HAVE_FSEEKO64)
00058   return fseeko64 (file, offset, whence);
00059 #elif defined (HAVE_FSEEKO)
00060   return fseeko (file, offset, whence);
00061 #else
00062   return fseek (file, offset, whence);
00063 #endif
00064 }
00065 
00066 FILE *
00067 real_fopen (const char *filename, const char *modes)
00068 {
00069 #if defined (HAVE_FOPEN64)
00070   return fopen64 (filename, modes);
00071 #else
00072   return fopen (filename, modes);
00073 #endif
00074 }
00075 
00076 /*
00077 INTERNAL_DEFINITION
00078        struct bfd_iovec
00079 
00080 DESCRIPTION
00081 
00082        The <<struct bfd_iovec>> contains the internal file I/O class.
00083        Each <<BFD>> has an instance of this class and all file I/O is
00084        routed through it (it is assumed that the instance implements
00085        all methods listed below).
00086 
00087 .struct bfd_iovec
00088 .{
00089 .  {* To avoid problems with macros, a "b" rather than "f"
00090 .     prefix is prepended to each method name.  *}
00091 .  {* Attempt to read/write NBYTES on ABFD's IOSTREAM storing/fetching
00092 .     bytes starting at PTR.  Return the number of bytes actually
00093 .     transfered (a read past end-of-file returns less than NBYTES),
00094 .     or -1 (setting <<bfd_error>>) if an error occurs.  *}
00095 .  file_ptr (*bread) (struct bfd *abfd, void *ptr, file_ptr nbytes);
00096 .  file_ptr (*bwrite) (struct bfd *abfd, const void *ptr,
00097 .                      file_ptr nbytes);
00098 .  {* Return the current IOSTREAM file offset, or -1 (setting <<bfd_error>>
00099 .     if an error occurs.  *}
00100 .  file_ptr (*btell) (struct bfd *abfd);
00101 .  {* For the following, on successful completion a value of 0 is returned.
00102 .     Otherwise, a value of -1 is returned (and  <<bfd_error>> is set).  *}
00103 .  int (*bseek) (struct bfd *abfd, file_ptr offset, int whence);
00104 .  int (*bclose) (struct bfd *abfd);
00105 .  int (*bflush) (struct bfd *abfd);
00106 .  int (*bstat) (struct bfd *abfd, struct stat *sb);
00107 .};
00108 
00109 */
00110 
00111 
00112 /* Return value is amount read.  */
00113 
00114 bfd_size_type
00115 bfd_bread (void *ptr, bfd_size_type size, bfd *abfd)
00116 {
00117   size_t nread;
00118 
00119   /* If this is an archive element, don't read past the end of
00120      this element.  */
00121   if (abfd->arelt_data != NULL)
00122     {
00123       size_t maxbytes = ((struct areltdata *) abfd->arelt_data)->parsed_size;
00124       if (size > maxbytes)
00125        size = maxbytes;
00126     }
00127 
00128   if ((abfd->flags & BFD_IN_MEMORY) != 0)
00129     {
00130       struct bfd_in_memory *bim;
00131       bfd_size_type get;
00132 
00133       bim = abfd->iostream;
00134       get = size;
00135       if (abfd->where + get > bim->size)
00136        {
00137          if (bim->size < (bfd_size_type) abfd->where)
00138            get = 0;
00139          else
00140            get = bim->size - abfd->where;
00141          bfd_set_error (bfd_error_file_truncated);
00142        }
00143       memcpy (ptr, bim->buffer + abfd->where, (size_t) get);
00144       abfd->where += get;
00145       return get;
00146     }
00147 
00148   if (abfd->iovec)
00149     nread = abfd->iovec->bread (abfd, ptr, size);
00150   else
00151     nread = 0;
00152   if (nread != (size_t) -1)
00153     abfd->where += nread;
00154 
00155   return nread;
00156 }
00157 
00158 bfd_size_type
00159 bfd_bwrite (const void *ptr, bfd_size_type size, bfd *abfd)
00160 {
00161   size_t nwrote;
00162 
00163   if ((abfd->flags & BFD_IN_MEMORY) != 0)
00164     {
00165       struct bfd_in_memory *bim = abfd->iostream;
00166 
00167       size = (size_t) size;
00168       if (abfd->where + size > bim->size)
00169        {
00170          bfd_size_type newsize, oldsize;
00171 
00172          oldsize = (bim->size + 127) & ~(bfd_size_type) 127;
00173          bim->size = abfd->where + size;
00174          /* Round up to cut down on memory fragmentation */
00175          newsize = (bim->size + 127) & ~(bfd_size_type) 127;
00176          if (newsize > oldsize)
00177            {
00178              bim->buffer = bfd_realloc (bim->buffer, newsize);
00179              if (bim->buffer == 0)
00180               {
00181                 bim->size = 0;
00182                 return 0;
00183               }
00184            }
00185        }
00186       memcpy (bim->buffer + abfd->where, ptr, (size_t) size);
00187       abfd->where += size;
00188       return size;
00189     }
00190 
00191   if (abfd->iovec)
00192     nwrote = abfd->iovec->bwrite (abfd, ptr, size);
00193   else
00194     nwrote = 0;
00195 
00196   if (nwrote != (size_t) -1)
00197     abfd->where += nwrote;
00198   if (nwrote != size)
00199     {
00200 #ifdef ENOSPC
00201       errno = ENOSPC;
00202 #endif
00203       bfd_set_error (bfd_error_system_call);
00204     }
00205   return nwrote;
00206 }
00207 
00208 file_ptr
00209 bfd_tell (bfd *abfd)
00210 {
00211   file_ptr ptr;
00212 
00213   if ((abfd->flags & BFD_IN_MEMORY) != 0)
00214     return abfd->where;
00215 
00216   if (abfd->iovec)
00217     {
00218       ptr = abfd->iovec->btell (abfd);
00219 
00220       if (abfd->my_archive)
00221        ptr -= abfd->origin;
00222     }
00223   else
00224     ptr = 0;
00225 
00226   abfd->where = ptr;
00227   return ptr;
00228 }
00229 
00230 int
00231 bfd_flush (bfd *abfd)
00232 {
00233   if ((abfd->flags & BFD_IN_MEMORY) != 0)
00234     return 0;
00235 
00236   if (abfd->iovec)
00237     return abfd->iovec->bflush (abfd);
00238   return 0;
00239 }
00240 
00241 /* Returns 0 for success, negative value for failure (in which case
00242    bfd_get_error can retrieve the error code).  */
00243 int
00244 bfd_stat (bfd *abfd, struct stat *statbuf)
00245 {
00246   int result;
00247 
00248   if ((abfd->flags & BFD_IN_MEMORY) != 0)
00249     abort ();
00250 
00251   if (abfd->iovec)
00252     result = abfd->iovec->bstat (abfd, statbuf);
00253   else
00254     result = -1;
00255 
00256   if (result < 0)
00257     bfd_set_error (bfd_error_system_call);
00258   return result;
00259 }
00260 
00261 /* Returns 0 for success, nonzero for failure (in which case bfd_get_error
00262    can retrieve the error code).  */
00263 
00264 int
00265 bfd_seek (bfd *abfd, file_ptr position, int direction)
00266 {
00267   int result;
00268   file_ptr file_position;
00269   /* For the time being, a BFD may not seek to it's end.  The problem
00270      is that we don't easily have a way to recognize the end of an
00271      element in an archive.  */
00272 
00273   BFD_ASSERT (direction == SEEK_SET || direction == SEEK_CUR);
00274 
00275   if (direction == SEEK_CUR && position == 0)
00276     return 0;
00277 
00278   if ((abfd->flags & BFD_IN_MEMORY) != 0)
00279     {
00280       struct bfd_in_memory *bim;
00281 
00282       bim = abfd->iostream;
00283 
00284       if (direction == SEEK_SET)
00285        abfd->where = position;
00286       else
00287        abfd->where += position;
00288 
00289       if (abfd->where > bim->size)
00290        {
00291          if ((abfd->direction == write_direction) ||
00292              (abfd->direction == both_direction))
00293            {
00294              bfd_size_type newsize, oldsize;
00295 
00296              oldsize = (bim->size + 127) & ~(bfd_size_type) 127;
00297              bim->size = abfd->where;
00298              /* Round up to cut down on memory fragmentation */
00299              newsize = (bim->size + 127) & ~(bfd_size_type) 127;
00300              if (newsize > oldsize)
00301                {
00302                 bim->buffer = bfd_realloc (bim->buffer, newsize);
00303                 if (bim->buffer == 0)
00304                   {
00305                     bim->size = 0;
00306                     return -1;
00307                   }
00308                }
00309            }
00310          else
00311            {
00312              abfd->where = bim->size;
00313              bfd_set_error (bfd_error_file_truncated);
00314              return -1;
00315            }
00316        }
00317       return 0;
00318     }
00319 
00320   if (abfd->format != bfd_archive && abfd->my_archive == 0)
00321     {
00322       if (direction == SEEK_SET && (bfd_vma) position == abfd->where)
00323        return 0;
00324     }
00325   else
00326     {
00327       /* We need something smarter to optimize access to archives.
00328         Currently, anything inside an archive is read via the file
00329         handle for the archive.  Which means that a bfd_seek on one
00330         component affects the `current position' in the archive, as
00331         well as in any other component.
00332 
00333         It might be sufficient to put a spike through the cache
00334         abstraction, and look to the archive for the file position,
00335         but I think we should try for something cleaner.
00336 
00337         In the meantime, no optimization for archives.  */
00338     }
00339 
00340   file_position = position;
00341   if (direction == SEEK_SET && abfd->my_archive != NULL)
00342     file_position += abfd->origin;
00343 
00344   if (abfd->iovec)
00345     result = abfd->iovec->bseek (abfd, file_position, direction);
00346   else
00347     result = -1;
00348 
00349   if (result != 0)
00350     {
00351       int hold_errno = errno;
00352 
00353       /* Force redetermination of `where' field.  */
00354       bfd_tell (abfd);
00355 
00356       /* An EINVAL error probably means that the file offset was
00357          absurd.  */
00358       if (hold_errno == EINVAL)
00359        bfd_set_error (bfd_error_file_truncated);
00360       else
00361        {
00362          bfd_set_error (bfd_error_system_call);
00363          errno = hold_errno;
00364        }
00365     }
00366   else
00367     {
00368       /* Adjust `where' field.  */
00369       if (direction == SEEK_SET)
00370        abfd->where = position;
00371       else
00372        abfd->where += position;
00373     }
00374   return result;
00375 }
00376 
00377 /*
00378 FUNCTION
00379        bfd_get_mtime
00380 
00381 SYNOPSIS
00382        long bfd_get_mtime (bfd *abfd);
00383 
00384 DESCRIPTION
00385        Return the file modification time (as read from the file system, or
00386        from the archive header for archive members).
00387 
00388 */
00389 
00390 long
00391 bfd_get_mtime (bfd *abfd)
00392 {
00393   struct stat buf;
00394 
00395   if (abfd->mtime_set)
00396     return abfd->mtime;
00397 
00398   if (abfd->iovec == NULL)
00399     return 0;
00400 
00401   if (abfd->iovec->bstat (abfd, &buf) != 0)
00402     return 0;
00403 
00404   abfd->mtime = buf.st_mtime;             /* Save value in case anyone wants it */
00405   return buf.st_mtime;
00406 }
00407 
00408 /*
00409 FUNCTION
00410        bfd_get_size
00411 
00412 SYNOPSIS
00413        file_ptr bfd_get_size (bfd *abfd);
00414 
00415 DESCRIPTION
00416        Return the file size (as read from file system) for the file
00417        associated with BFD @var{abfd}.
00418 
00419        The initial motivation for, and use of, this routine is not
00420        so we can get the exact size of the object the BFD applies to, since
00421        that might not be generally possible (archive members for example).
00422        It would be ideal if someone could eventually modify
00423        it so that such results were guaranteed.
00424 
00425        Instead, we want to ask questions like "is this NNN byte sized
00426        object I'm about to try read from file offset YYY reasonable?"
00427        As as example of where we might do this, some object formats
00428        use string tables for which the first <<sizeof (long)>> bytes of the
00429        table contain the size of the table itself, including the size bytes.
00430        If an application tries to read what it thinks is one of these
00431        string tables, without some way to validate the size, and for
00432        some reason the size is wrong (byte swapping error, wrong location
00433        for the string table, etc.), the only clue is likely to be a read
00434        error when it tries to read the table, or a "virtual memory
00435        exhausted" error when it tries to allocate 15 bazillon bytes
00436        of space for the 15 bazillon byte table it is about to read.
00437        This function at least allows us to answer the question, "is the
00438        size reasonable?".
00439 */
00440 
00441 file_ptr
00442 bfd_get_size (bfd *abfd)
00443 {
00444   struct stat buf;
00445 
00446   if ((abfd->flags & BFD_IN_MEMORY) != 0)
00447     return ((struct bfd_in_memory *) abfd->iostream)->size;
00448 
00449   if (abfd->iovec == NULL)
00450     return 0;
00451 
00452   if (abfd->iovec->bstat (abfd, &buf) != 0)
00453     return 0;
00454 
00455   return buf.st_size;
00456 }