1130561Sobrien/* Low-level I/O routines for BFDs. 2130561Sobrien 3130561Sobrien Copyright 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1997, 1998, 4218822Sdim 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007 5218822Sdim Free Software Foundation, Inc. 6130561Sobrien 7130561Sobrien Written by Cygnus Support. 8130561Sobrien 9130561SobrienThis file is part of BFD, the Binary File Descriptor library. 10130561Sobrien 11130561SobrienThis program is free software; you can redistribute it and/or modify 12130561Sobrienit under the terms of the GNU General Public License as published by 13130561Sobrienthe Free Software Foundation; either version 2 of the License, or 14130561Sobrien(at your option) any later version. 15130561Sobrien 16130561SobrienThis program is distributed in the hope that it will be useful, 17130561Sobrienbut WITHOUT ANY WARRANTY; without even the implied warranty of 18130561SobrienMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 19130561SobrienGNU General Public License for more details. 20130561Sobrien 21130561SobrienYou should have received a copy of the GNU General Public License 22130561Sobrienalong with this program; if not, write to the Free Software 23218822SdimFoundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA. */ 24130561Sobrien 25130561Sobrien#include "sysdep.h" 26218822Sdim#include <limits.h> 27130561Sobrien#include "bfd.h" 28130561Sobrien#include "libbfd.h" 29130561Sobrien 30130561Sobrien#ifndef S_IXUSR 31130561Sobrien#define S_IXUSR 0100 /* Execute by owner. */ 32130561Sobrien#endif 33130561Sobrien#ifndef S_IXGRP 34130561Sobrien#define S_IXGRP 0010 /* Execute by group. */ 35130561Sobrien#endif 36130561Sobrien#ifndef S_IXOTH 37130561Sobrien#define S_IXOTH 0001 /* Execute by others. */ 38130561Sobrien#endif 39130561Sobrien 40130561Sobrienfile_ptr 41130561Sobrienreal_ftell (FILE *file) 42130561Sobrien{ 43130561Sobrien#if defined (HAVE_FTELLO64) 44130561Sobrien return ftello64 (file); 45130561Sobrien#elif defined (HAVE_FTELLO) 46130561Sobrien return ftello (file); 47130561Sobrien#else 48130561Sobrien return ftell (file); 49130561Sobrien#endif 50130561Sobrien} 51130561Sobrien 52130561Sobrienint 53130561Sobrienreal_fseek (FILE *file, file_ptr offset, int whence) 54130561Sobrien{ 55130561Sobrien#if defined (HAVE_FSEEKO64) 56130561Sobrien return fseeko64 (file, offset, whence); 57130561Sobrien#elif defined (HAVE_FSEEKO) 58130561Sobrien return fseeko (file, offset, whence); 59130561Sobrien#else 60130561Sobrien return fseek (file, offset, whence); 61130561Sobrien#endif 62130561Sobrien} 63130561Sobrien 64218822SdimFILE * 65218822Sdimreal_fopen (const char *filename, const char *modes) 66130561Sobrien{ 67218822Sdim#if defined (HAVE_FOPEN64) 68218822Sdim return fopen64 (filename, modes); 69130561Sobrien#else 70218822Sdim return fopen (filename, modes); 71130561Sobrien#endif 72130561Sobrien} 73130561Sobrien 74218822Sdim/* 75218822SdimINTERNAL_DEFINITION 76218822Sdim struct bfd_iovec 77218822Sdim 78218822SdimDESCRIPTION 79218822Sdim 80218822Sdim The <<struct bfd_iovec>> contains the internal file I/O class. 81218822Sdim Each <<BFD>> has an instance of this class and all file I/O is 82218822Sdim routed through it (it is assumed that the instance implements 83218822Sdim all methods listed below). 84218822Sdim 85218822Sdim.struct bfd_iovec 86218822Sdim.{ 87218822Sdim. {* To avoid problems with macros, a "b" rather than "f" 88218822Sdim. prefix is prepended to each method name. *} 89218822Sdim. {* Attempt to read/write NBYTES on ABFD's IOSTREAM storing/fetching 90218822Sdim. bytes starting at PTR. Return the number of bytes actually 91218822Sdim. transfered (a read past end-of-file returns less than NBYTES), 92218822Sdim. or -1 (setting <<bfd_error>>) if an error occurs. *} 93218822Sdim. file_ptr (*bread) (struct bfd *abfd, void *ptr, file_ptr nbytes); 94218822Sdim. file_ptr (*bwrite) (struct bfd *abfd, const void *ptr, 95218822Sdim. file_ptr nbytes); 96218822Sdim. {* Return the current IOSTREAM file offset, or -1 (setting <<bfd_error>> 97218822Sdim. if an error occurs. *} 98218822Sdim. file_ptr (*btell) (struct bfd *abfd); 99218822Sdim. {* For the following, on successful completion a value of 0 is returned. 100218822Sdim. Otherwise, a value of -1 is returned (and <<bfd_error>> is set). *} 101218822Sdim. int (*bseek) (struct bfd *abfd, file_ptr offset, int whence); 102218822Sdim. int (*bclose) (struct bfd *abfd); 103218822Sdim. int (*bflush) (struct bfd *abfd); 104218822Sdim. int (*bstat) (struct bfd *abfd, struct stat *sb); 105218822Sdim.}; 106218822Sdim 107218822Sdim*/ 108218822Sdim 109218822Sdim 110130561Sobrien/* Return value is amount read. */ 111130561Sobrien 112130561Sobrienbfd_size_type 113130561Sobrienbfd_bread (void *ptr, bfd_size_type size, bfd *abfd) 114130561Sobrien{ 115130561Sobrien size_t nread; 116130561Sobrien 117218822Sdim /* If this is an archive element, don't read past the end of 118218822Sdim this element. */ 119218822Sdim if (abfd->arelt_data != NULL) 120218822Sdim { 121218822Sdim size_t maxbytes = ((struct areltdata *) abfd->arelt_data)->parsed_size; 122218822Sdim if (size > maxbytes) 123218822Sdim size = maxbytes; 124218822Sdim } 125218822Sdim 126130561Sobrien if ((abfd->flags & BFD_IN_MEMORY) != 0) 127130561Sobrien { 128130561Sobrien struct bfd_in_memory *bim; 129130561Sobrien bfd_size_type get; 130130561Sobrien 131130561Sobrien bim = abfd->iostream; 132130561Sobrien get = size; 133130561Sobrien if (abfd->where + get > bim->size) 134130561Sobrien { 135130561Sobrien if (bim->size < (bfd_size_type) abfd->where) 136130561Sobrien get = 0; 137130561Sobrien else 138130561Sobrien get = bim->size - abfd->where; 139130561Sobrien bfd_set_error (bfd_error_file_truncated); 140130561Sobrien } 141130561Sobrien memcpy (ptr, bim->buffer + abfd->where, (size_t) get); 142130561Sobrien abfd->where += get; 143130561Sobrien return get; 144130561Sobrien } 145130561Sobrien 146218822Sdim if (abfd->iovec) 147218822Sdim nread = abfd->iovec->bread (abfd, ptr, size); 148218822Sdim else 149218822Sdim nread = 0; 150130561Sobrien if (nread != (size_t) -1) 151130561Sobrien abfd->where += nread; 152130561Sobrien 153130561Sobrien return nread; 154130561Sobrien} 155130561Sobrien 156130561Sobrienbfd_size_type 157130561Sobrienbfd_bwrite (const void *ptr, bfd_size_type size, bfd *abfd) 158130561Sobrien{ 159130561Sobrien size_t nwrote; 160130561Sobrien 161130561Sobrien if ((abfd->flags & BFD_IN_MEMORY) != 0) 162130561Sobrien { 163130561Sobrien struct bfd_in_memory *bim = abfd->iostream; 164218822Sdim 165130561Sobrien size = (size_t) size; 166130561Sobrien if (abfd->where + size > bim->size) 167130561Sobrien { 168130561Sobrien bfd_size_type newsize, oldsize; 169130561Sobrien 170130561Sobrien oldsize = (bim->size + 127) & ~(bfd_size_type) 127; 171130561Sobrien bim->size = abfd->where + size; 172130561Sobrien /* Round up to cut down on memory fragmentation */ 173130561Sobrien newsize = (bim->size + 127) & ~(bfd_size_type) 127; 174130561Sobrien if (newsize > oldsize) 175130561Sobrien { 176130561Sobrien bim->buffer = bfd_realloc (bim->buffer, newsize); 177130561Sobrien if (bim->buffer == 0) 178130561Sobrien { 179130561Sobrien bim->size = 0; 180130561Sobrien return 0; 181130561Sobrien } 182130561Sobrien } 183130561Sobrien } 184130561Sobrien memcpy (bim->buffer + abfd->where, ptr, (size_t) size); 185130561Sobrien abfd->where += size; 186130561Sobrien return size; 187130561Sobrien } 188130561Sobrien 189218822Sdim if (abfd->iovec) 190218822Sdim nwrote = abfd->iovec->bwrite (abfd, ptr, size); 191218822Sdim else 192218822Sdim nwrote = 0; 193218822Sdim 194130561Sobrien if (nwrote != (size_t) -1) 195130561Sobrien abfd->where += nwrote; 196130561Sobrien if (nwrote != size) 197130561Sobrien { 198130561Sobrien#ifdef ENOSPC 199130561Sobrien errno = ENOSPC; 200130561Sobrien#endif 201130561Sobrien bfd_set_error (bfd_error_system_call); 202130561Sobrien } 203130561Sobrien return nwrote; 204130561Sobrien} 205130561Sobrien 206130561Sobrienfile_ptr 207130561Sobrienbfd_tell (bfd *abfd) 208130561Sobrien{ 209130561Sobrien file_ptr ptr; 210130561Sobrien 211130561Sobrien if ((abfd->flags & BFD_IN_MEMORY) != 0) 212130561Sobrien return abfd->where; 213130561Sobrien 214218822Sdim if (abfd->iovec) 215218822Sdim { 216218822Sdim ptr = abfd->iovec->btell (abfd); 217130561Sobrien 218218822Sdim if (abfd->my_archive) 219218822Sdim ptr -= abfd->origin; 220218822Sdim } 221218822Sdim else 222218822Sdim ptr = 0; 223218822Sdim 224130561Sobrien abfd->where = ptr; 225130561Sobrien return ptr; 226130561Sobrien} 227130561Sobrien 228130561Sobrienint 229130561Sobrienbfd_flush (bfd *abfd) 230130561Sobrien{ 231130561Sobrien if ((abfd->flags & BFD_IN_MEMORY) != 0) 232130561Sobrien return 0; 233218822Sdim 234218822Sdim if (abfd->iovec) 235218822Sdim return abfd->iovec->bflush (abfd); 236218822Sdim return 0; 237130561Sobrien} 238130561Sobrien 239130561Sobrien/* Returns 0 for success, negative value for failure (in which case 240130561Sobrien bfd_get_error can retrieve the error code). */ 241130561Sobrienint 242130561Sobrienbfd_stat (bfd *abfd, struct stat *statbuf) 243130561Sobrien{ 244130561Sobrien int result; 245130561Sobrien 246130561Sobrien if ((abfd->flags & BFD_IN_MEMORY) != 0) 247130561Sobrien abort (); 248130561Sobrien 249218822Sdim if (abfd->iovec) 250218822Sdim result = abfd->iovec->bstat (abfd, statbuf); 251218822Sdim else 252218822Sdim result = -1; 253218822Sdim 254130561Sobrien if (result < 0) 255130561Sobrien bfd_set_error (bfd_error_system_call); 256130561Sobrien return result; 257130561Sobrien} 258130561Sobrien 259130561Sobrien/* Returns 0 for success, nonzero for failure (in which case bfd_get_error 260130561Sobrien can retrieve the error code). */ 261130561Sobrien 262130561Sobrienint 263130561Sobrienbfd_seek (bfd *abfd, file_ptr position, int direction) 264130561Sobrien{ 265130561Sobrien int result; 266130561Sobrien file_ptr file_position; 267130561Sobrien /* For the time being, a BFD may not seek to it's end. The problem 268130561Sobrien is that we don't easily have a way to recognize the end of an 269130561Sobrien element in an archive. */ 270130561Sobrien 271130561Sobrien BFD_ASSERT (direction == SEEK_SET || direction == SEEK_CUR); 272130561Sobrien 273130561Sobrien if (direction == SEEK_CUR && position == 0) 274130561Sobrien return 0; 275130561Sobrien 276130561Sobrien if ((abfd->flags & BFD_IN_MEMORY) != 0) 277130561Sobrien { 278130561Sobrien struct bfd_in_memory *bim; 279130561Sobrien 280130561Sobrien bim = abfd->iostream; 281130561Sobrien 282130561Sobrien if (direction == SEEK_SET) 283130561Sobrien abfd->where = position; 284130561Sobrien else 285130561Sobrien abfd->where += position; 286130561Sobrien 287130561Sobrien if (abfd->where > bim->size) 288130561Sobrien { 289130561Sobrien if ((abfd->direction == write_direction) || 290130561Sobrien (abfd->direction == both_direction)) 291130561Sobrien { 292130561Sobrien bfd_size_type newsize, oldsize; 293218822Sdim 294130561Sobrien oldsize = (bim->size + 127) & ~(bfd_size_type) 127; 295130561Sobrien bim->size = abfd->where; 296130561Sobrien /* Round up to cut down on memory fragmentation */ 297130561Sobrien newsize = (bim->size + 127) & ~(bfd_size_type) 127; 298130561Sobrien if (newsize > oldsize) 299130561Sobrien { 300130561Sobrien bim->buffer = bfd_realloc (bim->buffer, newsize); 301130561Sobrien if (bim->buffer == 0) 302130561Sobrien { 303130561Sobrien bim->size = 0; 304130561Sobrien return -1; 305130561Sobrien } 306130561Sobrien } 307130561Sobrien } 308130561Sobrien else 309130561Sobrien { 310130561Sobrien abfd->where = bim->size; 311130561Sobrien bfd_set_error (bfd_error_file_truncated); 312130561Sobrien return -1; 313130561Sobrien } 314130561Sobrien } 315130561Sobrien return 0; 316130561Sobrien } 317130561Sobrien 318130561Sobrien if (abfd->format != bfd_archive && abfd->my_archive == 0) 319130561Sobrien { 320130561Sobrien if (direction == SEEK_SET && (bfd_vma) position == abfd->where) 321130561Sobrien return 0; 322130561Sobrien } 323130561Sobrien else 324130561Sobrien { 325130561Sobrien /* We need something smarter to optimize access to archives. 326130561Sobrien Currently, anything inside an archive is read via the file 327130561Sobrien handle for the archive. Which means that a bfd_seek on one 328130561Sobrien component affects the `current position' in the archive, as 329130561Sobrien well as in any other component. 330130561Sobrien 331130561Sobrien It might be sufficient to put a spike through the cache 332130561Sobrien abstraction, and look to the archive for the file position, 333130561Sobrien but I think we should try for something cleaner. 334130561Sobrien 335130561Sobrien In the meantime, no optimization for archives. */ 336130561Sobrien } 337130561Sobrien 338130561Sobrien file_position = position; 339130561Sobrien if (direction == SEEK_SET && abfd->my_archive != NULL) 340130561Sobrien file_position += abfd->origin; 341130561Sobrien 342218822Sdim if (abfd->iovec) 343218822Sdim result = abfd->iovec->bseek (abfd, file_position, direction); 344218822Sdim else 345218822Sdim result = -1; 346218822Sdim 347130561Sobrien if (result != 0) 348130561Sobrien { 349130561Sobrien int hold_errno = errno; 350130561Sobrien 351130561Sobrien /* Force redetermination of `where' field. */ 352130561Sobrien bfd_tell (abfd); 353130561Sobrien 354130561Sobrien /* An EINVAL error probably means that the file offset was 355130561Sobrien absurd. */ 356130561Sobrien if (hold_errno == EINVAL) 357130561Sobrien bfd_set_error (bfd_error_file_truncated); 358130561Sobrien else 359130561Sobrien { 360130561Sobrien bfd_set_error (bfd_error_system_call); 361130561Sobrien errno = hold_errno; 362130561Sobrien } 363130561Sobrien } 364130561Sobrien else 365130561Sobrien { 366130561Sobrien /* Adjust `where' field. */ 367130561Sobrien if (direction == SEEK_SET) 368130561Sobrien abfd->where = position; 369130561Sobrien else 370130561Sobrien abfd->where += position; 371130561Sobrien } 372130561Sobrien return result; 373130561Sobrien} 374130561Sobrien 375130561Sobrien/* 376130561SobrienFUNCTION 377130561Sobrien bfd_get_mtime 378130561Sobrien 379130561SobrienSYNOPSIS 380130561Sobrien long bfd_get_mtime (bfd *abfd); 381130561Sobrien 382130561SobrienDESCRIPTION 383130561Sobrien Return the file modification time (as read from the file system, or 384130561Sobrien from the archive header for archive members). 385130561Sobrien 386130561Sobrien*/ 387130561Sobrien 388130561Sobrienlong 389130561Sobrienbfd_get_mtime (bfd *abfd) 390130561Sobrien{ 391130561Sobrien struct stat buf; 392130561Sobrien 393130561Sobrien if (abfd->mtime_set) 394130561Sobrien return abfd->mtime; 395130561Sobrien 396218822Sdim if (abfd->iovec == NULL) 397130561Sobrien return 0; 398130561Sobrien 399218822Sdim if (abfd->iovec->bstat (abfd, &buf) != 0) 400218822Sdim return 0; 401218822Sdim 402130561Sobrien abfd->mtime = buf.st_mtime; /* Save value in case anyone wants it */ 403130561Sobrien return buf.st_mtime; 404130561Sobrien} 405130561Sobrien 406130561Sobrien/* 407130561SobrienFUNCTION 408130561Sobrien bfd_get_size 409130561Sobrien 410130561SobrienSYNOPSIS 411218822Sdim file_ptr bfd_get_size (bfd *abfd); 412130561Sobrien 413130561SobrienDESCRIPTION 414130561Sobrien Return the file size (as read from file system) for the file 415130561Sobrien associated with BFD @var{abfd}. 416130561Sobrien 417130561Sobrien The initial motivation for, and use of, this routine is not 418130561Sobrien so we can get the exact size of the object the BFD applies to, since 419130561Sobrien that might not be generally possible (archive members for example). 420130561Sobrien It would be ideal if someone could eventually modify 421130561Sobrien it so that such results were guaranteed. 422130561Sobrien 423130561Sobrien Instead, we want to ask questions like "is this NNN byte sized 424130561Sobrien object I'm about to try read from file offset YYY reasonable?" 425130561Sobrien As as example of where we might do this, some object formats 426130561Sobrien use string tables for which the first <<sizeof (long)>> bytes of the 427130561Sobrien table contain the size of the table itself, including the size bytes. 428130561Sobrien If an application tries to read what it thinks is one of these 429130561Sobrien string tables, without some way to validate the size, and for 430130561Sobrien some reason the size is wrong (byte swapping error, wrong location 431130561Sobrien for the string table, etc.), the only clue is likely to be a read 432130561Sobrien error when it tries to read the table, or a "virtual memory 433130561Sobrien exhausted" error when it tries to allocate 15 bazillon bytes 434130561Sobrien of space for the 15 bazillon byte table it is about to read. 435130561Sobrien This function at least allows us to answer the question, "is the 436130561Sobrien size reasonable?". 437130561Sobrien*/ 438130561Sobrien 439218822Sdimfile_ptr 440130561Sobrienbfd_get_size (bfd *abfd) 441130561Sobrien{ 442130561Sobrien struct stat buf; 443130561Sobrien 444130561Sobrien if ((abfd->flags & BFD_IN_MEMORY) != 0) 445130561Sobrien return ((struct bfd_in_memory *) abfd->iostream)->size; 446130561Sobrien 447218822Sdim if (abfd->iovec == NULL) 448130561Sobrien return 0; 449130561Sobrien 450218822Sdim if (abfd->iovec->bstat (abfd, &buf) != 0) 451218822Sdim return 0; 452218822Sdim 453130561Sobrien return buf.st_size; 454130561Sobrien} 455