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