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
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 ((abfd->flags & BFD_IN_MEMORY) != 0)
120    {
121      struct bfd_in_memory *bim;
122      bfd_size_type get;
123
124      bim = abfd->iostream;
125      get = size;
126      if (abfd->where + get > bim->size)
127	{
128	  if (bim->size < (bfd_size_type) abfd->where)
129	    get = 0;
130	  else
131	    get = bim->size - abfd->where;
132	  bfd_set_error (bfd_error_file_truncated);
133	}
134      memcpy (ptr, bim->buffer + abfd->where, (size_t) get);
135      abfd->where += get;
136      return get;
137    }
138
139  if (abfd->iovec)
140    nread = abfd->iovec->bread (abfd, ptr, size);
141  else
142    nread = 0;
143  if (nread != (size_t) -1)
144    abfd->where += nread;
145
146  return nread;
147}
148
149bfd_size_type
150bfd_bwrite (const void *ptr, bfd_size_type size, bfd *abfd)
151{
152  size_t nwrote;
153
154  if ((abfd->flags & BFD_IN_MEMORY) != 0)
155    {
156      struct bfd_in_memory *bim = abfd->iostream;
157
158      size = (size_t) size;
159      if (abfd->where + size > bim->size)
160	{
161	  bfd_size_type newsize, oldsize;
162
163	  oldsize = (bim->size + 127) & ~(bfd_size_type) 127;
164	  bim->size = abfd->where + size;
165	  /* Round up to cut down on memory fragmentation */
166	  newsize = (bim->size + 127) & ~(bfd_size_type) 127;
167	  if (newsize > oldsize)
168	    {
169	      bim->buffer = bfd_realloc (bim->buffer, newsize);
170	      if (bim->buffer == 0)
171		{
172		  bim->size = 0;
173		  return 0;
174		}
175	    }
176	}
177      memcpy (bim->buffer + abfd->where, ptr, (size_t) size);
178      abfd->where += size;
179      return size;
180    }
181
182  if (abfd->iovec)
183    nwrote = abfd->iovec->bwrite (abfd, ptr, size);
184  else
185    nwrote = 0;
186
187  if (nwrote != (size_t) -1)
188    abfd->where += nwrote;
189  if (nwrote != size)
190    {
191#ifdef ENOSPC
192      errno = ENOSPC;
193#endif
194      bfd_set_error (bfd_error_system_call);
195    }
196  return nwrote;
197}
198
199file_ptr
200bfd_tell (bfd *abfd)
201{
202  file_ptr ptr;
203
204  if ((abfd->flags & BFD_IN_MEMORY) != 0)
205    return abfd->where;
206
207  if (abfd->iovec)
208    {
209      ptr = abfd->iovec->btell (abfd);
210
211      if (abfd->my_archive)
212	ptr -= abfd->origin;
213    }
214  else
215    ptr = 0;
216
217  abfd->where = ptr;
218  return ptr;
219}
220
221int
222bfd_flush (bfd *abfd)
223{
224  if ((abfd->flags & BFD_IN_MEMORY) != 0)
225    return 0;
226
227  if (abfd->iovec)
228    return abfd->iovec->bflush (abfd);
229  return 0;
230}
231
232/* Returns 0 for success, negative value for failure (in which case
233   bfd_get_error can retrieve the error code).  */
234int
235bfd_stat (bfd *abfd, struct stat *statbuf)
236{
237  int result;
238
239  if ((abfd->flags & BFD_IN_MEMORY) != 0)
240    abort ();
241
242  if (abfd->iovec)
243    result = abfd->iovec->bstat (abfd, statbuf);
244  else
245    result = -1;
246
247  if (result < 0)
248    bfd_set_error (bfd_error_system_call);
249  return result;
250}
251
252/* Returns 0 for success, nonzero for failure (in which case bfd_get_error
253   can retrieve the error code).  */
254
255int
256bfd_seek (bfd *abfd, file_ptr position, int direction)
257{
258  int result;
259  file_ptr file_position;
260  /* For the time being, a BFD may not seek to it's end.  The problem
261     is that we don't easily have a way to recognize the end of an
262     element in an archive.  */
263
264  BFD_ASSERT (direction == SEEK_SET || direction == SEEK_CUR);
265
266  if (direction == SEEK_CUR && position == 0)
267    return 0;
268
269  if ((abfd->flags & BFD_IN_MEMORY) != 0)
270    {
271      struct bfd_in_memory *bim;
272
273      bim = abfd->iostream;
274
275      if (direction == SEEK_SET)
276	abfd->where = position;
277      else
278	abfd->where += position;
279
280      if (abfd->where > bim->size)
281	{
282	  if ((abfd->direction == write_direction) ||
283	      (abfd->direction == both_direction))
284	    {
285	      bfd_size_type newsize, oldsize;
286
287	      oldsize = (bim->size + 127) & ~(bfd_size_type) 127;
288	      bim->size = abfd->where;
289	      /* Round up to cut down on memory fragmentation */
290	      newsize = (bim->size + 127) & ~(bfd_size_type) 127;
291	      if (newsize > oldsize)
292	        {
293		  bim->buffer = bfd_realloc (bim->buffer, newsize);
294		  if (bim->buffer == 0)
295		    {
296		      bim->size = 0;
297		      return -1;
298		    }
299	        }
300	    }
301	  else
302	    {
303	      abfd->where = bim->size;
304	      bfd_set_error (bfd_error_file_truncated);
305	      return -1;
306	    }
307	}
308      return 0;
309    }
310
311  if (abfd->format != bfd_archive && abfd->my_archive == 0)
312    {
313      if (direction == SEEK_SET && (bfd_vma) position == abfd->where)
314	return 0;
315    }
316  else
317    {
318      /* We need something smarter to optimize access to archives.
319	 Currently, anything inside an archive is read via the file
320	 handle for the archive.  Which means that a bfd_seek on one
321	 component affects the `current position' in the archive, as
322	 well as in any other component.
323
324	 It might be sufficient to put a spike through the cache
325	 abstraction, and look to the archive for the file position,
326	 but I think we should try for something cleaner.
327
328	 In the meantime, no optimization for archives.  */
329    }
330
331  file_position = position;
332  if (direction == SEEK_SET && abfd->my_archive != NULL)
333    file_position += abfd->origin;
334
335  if (abfd->iovec)
336    result = abfd->iovec->bseek (abfd, file_position, direction);
337  else
338    result = -1;
339
340  if (result != 0)
341    {
342      int hold_errno = errno;
343
344      /* Force redetermination of `where' field.  */
345      bfd_tell (abfd);
346
347      /* An EINVAL error probably means that the file offset was
348         absurd.  */
349      if (hold_errno == EINVAL)
350	bfd_set_error (bfd_error_file_truncated);
351      else
352	{
353	  bfd_set_error (bfd_error_system_call);
354	  errno = hold_errno;
355	}
356    }
357  else
358    {
359      /* Adjust `where' field.  */
360      if (direction == SEEK_SET)
361	abfd->where = position;
362      else
363	abfd->where += position;
364    }
365  return result;
366}
367
368/*
369FUNCTION
370	bfd_get_mtime
371
372SYNOPSIS
373	long bfd_get_mtime (bfd *abfd);
374
375DESCRIPTION
376	Return the file modification time (as read from the file system, or
377	from the archive header for archive members).
378
379*/
380
381long
382bfd_get_mtime (bfd *abfd)
383{
384  struct stat buf;
385
386  if (abfd->mtime_set)
387    return abfd->mtime;
388
389  if (abfd->iovec == NULL)
390    return 0;
391
392  if (abfd->iovec->bstat (abfd, &buf) != 0)
393    return 0;
394
395  abfd->mtime = buf.st_mtime;		/* Save value in case anyone wants it */
396  return buf.st_mtime;
397}
398
399/*
400FUNCTION
401	bfd_get_size
402
403SYNOPSIS
404	long bfd_get_size (bfd *abfd);
405
406DESCRIPTION
407	Return the file size (as read from file system) for the file
408	associated with BFD @var{abfd}.
409
410	The initial motivation for, and use of, this routine is not
411	so we can get the exact size of the object the BFD applies to, since
412	that might not be generally possible (archive members for example).
413	It would be ideal if someone could eventually modify
414	it so that such results were guaranteed.
415
416	Instead, we want to ask questions like "is this NNN byte sized
417	object I'm about to try read from file offset YYY reasonable?"
418	As as example of where we might do this, some object formats
419	use string tables for which the first <<sizeof (long)>> bytes of the
420	table contain the size of the table itself, including the size bytes.
421	If an application tries to read what it thinks is one of these
422	string tables, without some way to validate the size, and for
423	some reason the size is wrong (byte swapping error, wrong location
424	for the string table, etc.), the only clue is likely to be a read
425	error when it tries to read the table, or a "virtual memory
426	exhausted" error when it tries to allocate 15 bazillon bytes
427	of space for the 15 bazillon byte table it is about to read.
428	This function at least allows us to answer the question, "is the
429	size reasonable?".
430*/
431
432long
433bfd_get_size (bfd *abfd)
434{
435  struct stat buf;
436
437  if ((abfd->flags & BFD_IN_MEMORY) != 0)
438    return ((struct bfd_in_memory *) abfd->iostream)->size;
439
440  if (abfd->iovec == NULL)
441    return 0;
442
443  if (abfd->iovec->bstat (abfd, &buf) != 0)
444    return 0;
445
446  return buf.st_size;
447}
448