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