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