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