bfdio.c revision 218822
1/* Low-level I/O routines for BFDs.
2
3   Copyright 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1997, 1998,
4   1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007
5   Free Software Foundation, Inc.
6
7   Written by Cygnus Support.
8
9This file is part of BFD, the Binary File Descriptor library.
10
11This program is free software; you can redistribute it and/or modify
12it under the terms of the GNU General Public License as published by
13the Free Software Foundation; either version 2 of the License, or
14(at your option) any later version.
15
16This program is distributed in the hope that it will be useful,
17but WITHOUT ANY WARRANTY; without even the implied warranty of
18MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
19GNU General Public License for more details.
20
21You should have received a copy of the GNU General Public License
22along with this program; if not, write to the Free Software
23Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA.  */
24
25#include "sysdep.h"
26#include <limits.h>
27#include "bfd.h"
28#include "libbfd.h"
29
30#ifndef S_IXUSR
31#define S_IXUSR 0100    /* Execute by owner.  */
32#endif
33#ifndef S_IXGRP
34#define S_IXGRP 0010    /* Execute by group.  */
35#endif
36#ifndef S_IXOTH
37#define S_IXOTH 0001    /* Execute by others.  */
38#endif
39
40file_ptr
41real_ftell (FILE *file)
42{
43#if defined (HAVE_FTELLO64)
44  return ftello64 (file);
45#elif defined (HAVE_FTELLO)
46  return ftello (file);
47#else
48  return ftell (file);
49#endif
50}
51
52int
53real_fseek (FILE *file, file_ptr offset, int whence)
54{
55#if defined (HAVE_FSEEKO64)
56  return fseeko64 (file, offset, whence);
57#elif defined (HAVE_FSEEKO)
58  return fseeko (file, offset, whence);
59#else
60  return fseek (file, offset, whence);
61#endif
62}
63
64FILE *
65real_fopen (const char *filename, const char *modes)
66{
67#if defined (HAVE_FOPEN64)
68  return fopen64 (filename, modes);
69#else
70  return fopen (filename, modes);
71#endif
72}
73
74/*
75INTERNAL_DEFINITION
76	struct bfd_iovec
77
78DESCRIPTION
79
80	The <<struct bfd_iovec>> contains the internal file I/O class.
81	Each <<BFD>> has an instance of this class and all file I/O is
82	routed through it (it is assumed that the instance implements
83	all methods listed below).
84
85.struct bfd_iovec
86.{
87.  {* To avoid problems with macros, a "b" rather than "f"
88.     prefix is prepended to each method name.  *}
89.  {* Attempt to read/write NBYTES on ABFD's IOSTREAM storing/fetching
90.     bytes starting at PTR.  Return the number of bytes actually
91.     transfered (a read past end-of-file returns less than NBYTES),
92.     or -1 (setting <<bfd_error>>) if an error occurs.  *}
93.  file_ptr (*bread) (struct bfd *abfd, void *ptr, file_ptr nbytes);
94.  file_ptr (*bwrite) (struct bfd *abfd, const void *ptr,
95.                      file_ptr nbytes);
96.  {* Return the current IOSTREAM file offset, or -1 (setting <<bfd_error>>
97.     if an error occurs.  *}
98.  file_ptr (*btell) (struct bfd *abfd);
99.  {* For the following, on successful completion a value of 0 is returned.
100.     Otherwise, a value of -1 is returned (and  <<bfd_error>> is set).  *}
101.  int (*bseek) (struct bfd *abfd, file_ptr offset, int whence);
102.  int (*bclose) (struct bfd *abfd);
103.  int (*bflush) (struct bfd *abfd);
104.  int (*bstat) (struct bfd *abfd, struct stat *sb);
105.};
106
107*/
108
109
110/* Return value is amount read.  */
111
112bfd_size_type
113bfd_bread (void *ptr, bfd_size_type size, bfd *abfd)
114{
115  size_t nread;
116
117  /* If this is an archive element, don't read past the end of
118     this element.  */
119  if (abfd->arelt_data != NULL)
120    {
121      size_t maxbytes = ((struct areltdata *) abfd->arelt_data)->parsed_size;
122      if (size > maxbytes)
123	size = maxbytes;
124    }
125
126  if ((abfd->flags & BFD_IN_MEMORY) != 0)
127    {
128      struct bfd_in_memory *bim;
129      bfd_size_type get;
130
131      bim = abfd->iostream;
132      get = size;
133      if (abfd->where + get > bim->size)
134	{
135	  if (bim->size < (bfd_size_type) abfd->where)
136	    get = 0;
137	  else
138	    get = bim->size - abfd->where;
139	  bfd_set_error (bfd_error_file_truncated);
140	}
141      memcpy (ptr, bim->buffer + abfd->where, (size_t) get);
142      abfd->where += get;
143      return get;
144    }
145
146  if (abfd->iovec)
147    nread = abfd->iovec->bread (abfd, ptr, size);
148  else
149    nread = 0;
150  if (nread != (size_t) -1)
151    abfd->where += nread;
152
153  return nread;
154}
155
156bfd_size_type
157bfd_bwrite (const void *ptr, bfd_size_type size, bfd *abfd)
158{
159  size_t nwrote;
160
161  if ((abfd->flags & BFD_IN_MEMORY) != 0)
162    {
163      struct bfd_in_memory *bim = abfd->iostream;
164
165      size = (size_t) size;
166      if (abfd->where + size > bim->size)
167	{
168	  bfd_size_type newsize, oldsize;
169
170	  oldsize = (bim->size + 127) & ~(bfd_size_type) 127;
171	  bim->size = abfd->where + size;
172	  /* Round up to cut down on memory fragmentation */
173	  newsize = (bim->size + 127) & ~(bfd_size_type) 127;
174	  if (newsize > oldsize)
175	    {
176	      bim->buffer = bfd_realloc (bim->buffer, newsize);
177	      if (bim->buffer == 0)
178		{
179		  bim->size = 0;
180		  return 0;
181		}
182	    }
183	}
184      memcpy (bim->buffer + abfd->where, ptr, (size_t) size);
185      abfd->where += size;
186      return size;
187    }
188
189  if (abfd->iovec)
190    nwrote = abfd->iovec->bwrite (abfd, ptr, size);
191  else
192    nwrote = 0;
193
194  if (nwrote != (size_t) -1)
195    abfd->where += nwrote;
196  if (nwrote != size)
197    {
198#ifdef ENOSPC
199      errno = ENOSPC;
200#endif
201      bfd_set_error (bfd_error_system_call);
202    }
203  return nwrote;
204}
205
206file_ptr
207bfd_tell (bfd *abfd)
208{
209  file_ptr ptr;
210
211  if ((abfd->flags & BFD_IN_MEMORY) != 0)
212    return abfd->where;
213
214  if (abfd->iovec)
215    {
216      ptr = abfd->iovec->btell (abfd);
217
218      if (abfd->my_archive)
219	ptr -= abfd->origin;
220    }
221  else
222    ptr = 0;
223
224  abfd->where = ptr;
225  return ptr;
226}
227
228int
229bfd_flush (bfd *abfd)
230{
231  if ((abfd->flags & BFD_IN_MEMORY) != 0)
232    return 0;
233
234  if (abfd->iovec)
235    return abfd->iovec->bflush (abfd);
236  return 0;
237}
238
239/* Returns 0 for success, negative value for failure (in which case
240   bfd_get_error can retrieve the error code).  */
241int
242bfd_stat (bfd *abfd, struct stat *statbuf)
243{
244  int result;
245
246  if ((abfd->flags & BFD_IN_MEMORY) != 0)
247    abort ();
248
249  if (abfd->iovec)
250    result = abfd->iovec->bstat (abfd, statbuf);
251  else
252    result = -1;
253
254  if (result < 0)
255    bfd_set_error (bfd_error_system_call);
256  return result;
257}
258
259/* Returns 0 for success, nonzero for failure (in which case bfd_get_error
260   can retrieve the error code).  */
261
262int
263bfd_seek (bfd *abfd, file_ptr position, int direction)
264{
265  int result;
266  file_ptr file_position;
267  /* For the time being, a BFD may not seek to it's end.  The problem
268     is that we don't easily have a way to recognize the end of an
269     element in an archive.  */
270
271  BFD_ASSERT (direction == SEEK_SET || direction == SEEK_CUR);
272
273  if (direction == SEEK_CUR && position == 0)
274    return 0;
275
276  if ((abfd->flags & BFD_IN_MEMORY) != 0)
277    {
278      struct bfd_in_memory *bim;
279
280      bim = abfd->iostream;
281
282      if (direction == SEEK_SET)
283	abfd->where = position;
284      else
285	abfd->where += position;
286
287      if (abfd->where > bim->size)
288	{
289	  if ((abfd->direction == write_direction) ||
290	      (abfd->direction == both_direction))
291	    {
292	      bfd_size_type newsize, oldsize;
293
294	      oldsize = (bim->size + 127) & ~(bfd_size_type) 127;
295	      bim->size = abfd->where;
296	      /* Round up to cut down on memory fragmentation */
297	      newsize = (bim->size + 127) & ~(bfd_size_type) 127;
298	      if (newsize > oldsize)
299	        {
300		  bim->buffer = bfd_realloc (bim->buffer, newsize);
301		  if (bim->buffer == 0)
302		    {
303		      bim->size = 0;
304		      return -1;
305		    }
306	        }
307	    }
308	  else
309	    {
310	      abfd->where = bim->size;
311	      bfd_set_error (bfd_error_file_truncated);
312	      return -1;
313	    }
314	}
315      return 0;
316    }
317
318  if (abfd->format != bfd_archive && abfd->my_archive == 0)
319    {
320      if (direction == SEEK_SET && (bfd_vma) position == abfd->where)
321	return 0;
322    }
323  else
324    {
325      /* We need something smarter to optimize access to archives.
326	 Currently, anything inside an archive is read via the file
327	 handle for the archive.  Which means that a bfd_seek on one
328	 component affects the `current position' in the archive, as
329	 well as in any other component.
330
331	 It might be sufficient to put a spike through the cache
332	 abstraction, and look to the archive for the file position,
333	 but I think we should try for something cleaner.
334
335	 In the meantime, no optimization for archives.  */
336    }
337
338  file_position = position;
339  if (direction == SEEK_SET && abfd->my_archive != NULL)
340    file_position += abfd->origin;
341
342  if (abfd->iovec)
343    result = abfd->iovec->bseek (abfd, file_position, direction);
344  else
345    result = -1;
346
347  if (result != 0)
348    {
349      int hold_errno = errno;
350
351      /* Force redetermination of `where' field.  */
352      bfd_tell (abfd);
353
354      /* An EINVAL error probably means that the file offset was
355         absurd.  */
356      if (hold_errno == EINVAL)
357	bfd_set_error (bfd_error_file_truncated);
358      else
359	{
360	  bfd_set_error (bfd_error_system_call);
361	  errno = hold_errno;
362	}
363    }
364  else
365    {
366      /* Adjust `where' field.  */
367      if (direction == SEEK_SET)
368	abfd->where = position;
369      else
370	abfd->where += position;
371    }
372  return result;
373}
374
375/*
376FUNCTION
377	bfd_get_mtime
378
379SYNOPSIS
380	long bfd_get_mtime (bfd *abfd);
381
382DESCRIPTION
383	Return the file modification time (as read from the file system, or
384	from the archive header for archive members).
385
386*/
387
388long
389bfd_get_mtime (bfd *abfd)
390{
391  struct stat buf;
392
393  if (abfd->mtime_set)
394    return abfd->mtime;
395
396  if (abfd->iovec == NULL)
397    return 0;
398
399  if (abfd->iovec->bstat (abfd, &buf) != 0)
400    return 0;
401
402  abfd->mtime = buf.st_mtime;		/* Save value in case anyone wants it */
403  return buf.st_mtime;
404}
405
406/*
407FUNCTION
408	bfd_get_size
409
410SYNOPSIS
411	file_ptr bfd_get_size (bfd *abfd);
412
413DESCRIPTION
414	Return the file size (as read from file system) for the file
415	associated with BFD @var{abfd}.
416
417	The initial motivation for, and use of, this routine is not
418	so we can get the exact size of the object the BFD applies to, since
419	that might not be generally possible (archive members for example).
420	It would be ideal if someone could eventually modify
421	it so that such results were guaranteed.
422
423	Instead, we want to ask questions like "is this NNN byte sized
424	object I'm about to try read from file offset YYY reasonable?"
425	As as example of where we might do this, some object formats
426	use string tables for which the first <<sizeof (long)>> bytes of the
427	table contain the size of the table itself, including the size bytes.
428	If an application tries to read what it thinks is one of these
429	string tables, without some way to validate the size, and for
430	some reason the size is wrong (byte swapping error, wrong location
431	for the string table, etc.), the only clue is likely to be a read
432	error when it tries to read the table, or a "virtual memory
433	exhausted" error when it tries to allocate 15 bazillon bytes
434	of space for the 15 bazillon byte table it is about to read.
435	This function at least allows us to answer the question, "is the
436	size reasonable?".
437*/
438
439file_ptr
440bfd_get_size (bfd *abfd)
441{
442  struct stat buf;
443
444  if ((abfd->flags & BFD_IN_MEMORY) != 0)
445    return ((struct bfd_in_memory *) abfd->iostream)->size;
446
447  if (abfd->iovec == NULL)
448    return 0;
449
450  if (abfd->iovec->bstat (abfd, &buf) != 0)
451    return 0;
452
453  return buf.st_size;
454}
455