xref: /dflybsd-src/contrib/binutils-2.34/bfd/bfdio.c (revision b52ef7118d1621abed722c5bbbd542210290ecef)
1*fae548d3Szrj /* Low-level I/O routines for BFDs.
2*fae548d3Szrj 
3*fae548d3Szrj    Copyright (C) 1990-2020 Free Software Foundation, Inc.
4*fae548d3Szrj 
5*fae548d3Szrj    Written by Cygnus Support.
6*fae548d3Szrj 
7*fae548d3Szrj    This file is part of BFD, the Binary File Descriptor library.
8*fae548d3Szrj 
9*fae548d3Szrj    This program is free software; you can redistribute it and/or modify
10*fae548d3Szrj    it under the terms of the GNU General Public License as published by
11*fae548d3Szrj    the Free Software Foundation; either version 3 of the License, or
12*fae548d3Szrj    (at your option) any later version.
13*fae548d3Szrj 
14*fae548d3Szrj    This program is distributed in the hope that it will be useful,
15*fae548d3Szrj    but WITHOUT ANY WARRANTY; without even the implied warranty of
16*fae548d3Szrj    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17*fae548d3Szrj    GNU General Public License for more details.
18*fae548d3Szrj 
19*fae548d3Szrj    You should have received a copy of the GNU General Public License
20*fae548d3Szrj    along with this program; if not, write to the Free Software
21*fae548d3Szrj    Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston,
22*fae548d3Szrj    MA 02110-1301, USA.  */
23*fae548d3Szrj 
24*fae548d3Szrj #include "sysdep.h"
25*fae548d3Szrj #include <limits.h>
26*fae548d3Szrj #include "bfd.h"
27*fae548d3Szrj #include "libbfd.h"
28*fae548d3Szrj 
29*fae548d3Szrj #ifndef S_IXUSR
30*fae548d3Szrj #define S_IXUSR 0100    /* Execute by owner.  */
31*fae548d3Szrj #endif
32*fae548d3Szrj #ifndef S_IXGRP
33*fae548d3Szrj #define S_IXGRP 0010    /* Execute by group.  */
34*fae548d3Szrj #endif
35*fae548d3Szrj #ifndef S_IXOTH
36*fae548d3Szrj #define S_IXOTH 0001    /* Execute by others.  */
37*fae548d3Szrj #endif
38*fae548d3Szrj 
39*fae548d3Szrj #ifndef FD_CLOEXEC
40*fae548d3Szrj #define FD_CLOEXEC 1
41*fae548d3Szrj #endif
42*fae548d3Szrj 
43*fae548d3Szrj file_ptr
_bfd_real_ftell(FILE * file)44*fae548d3Szrj _bfd_real_ftell (FILE *file)
45*fae548d3Szrj {
46*fae548d3Szrj #if defined (HAVE_FTELLO64)
47*fae548d3Szrj   return ftello64 (file);
48*fae548d3Szrj #elif defined (HAVE_FTELLO)
49*fae548d3Szrj   return ftello (file);
50*fae548d3Szrj #else
51*fae548d3Szrj   return ftell (file);
52*fae548d3Szrj #endif
53*fae548d3Szrj }
54*fae548d3Szrj 
55*fae548d3Szrj int
_bfd_real_fseek(FILE * file,file_ptr offset,int whence)56*fae548d3Szrj _bfd_real_fseek (FILE *file, file_ptr offset, int whence)
57*fae548d3Szrj {
58*fae548d3Szrj #if defined (HAVE_FSEEKO64)
59*fae548d3Szrj   return fseeko64 (file, offset, whence);
60*fae548d3Szrj #elif defined (HAVE_FSEEKO)
61*fae548d3Szrj   return fseeko (file, offset, whence);
62*fae548d3Szrj #else
63*fae548d3Szrj   return fseek (file, offset, whence);
64*fae548d3Szrj #endif
65*fae548d3Szrj }
66*fae548d3Szrj 
67*fae548d3Szrj /* Mark FILE as close-on-exec.  Return FILE.  FILE may be NULL, in
68*fae548d3Szrj    which case nothing is done.  */
69*fae548d3Szrj static FILE *
close_on_exec(FILE * file)70*fae548d3Szrj close_on_exec (FILE *file)
71*fae548d3Szrj {
72*fae548d3Szrj #if defined (HAVE_FILENO) && defined (F_GETFD)
73*fae548d3Szrj   if (file)
74*fae548d3Szrj     {
75*fae548d3Szrj       int fd = fileno (file);
76*fae548d3Szrj       int old = fcntl (fd, F_GETFD, 0);
77*fae548d3Szrj       if (old >= 0)
78*fae548d3Szrj 	fcntl (fd, F_SETFD, old | FD_CLOEXEC);
79*fae548d3Szrj     }
80*fae548d3Szrj #endif
81*fae548d3Szrj   return file;
82*fae548d3Szrj }
83*fae548d3Szrj 
84*fae548d3Szrj FILE *
_bfd_real_fopen(const char * filename,const char * modes)85*fae548d3Szrj _bfd_real_fopen (const char *filename, const char *modes)
86*fae548d3Szrj {
87*fae548d3Szrj #ifdef VMS
88*fae548d3Szrj   char *vms_attr;
89*fae548d3Szrj 
90*fae548d3Szrj   /* On VMS, fopen allows file attributes as optional arguments.
91*fae548d3Szrj      We need to use them but we'd better to use the common prototype.
92*fae548d3Szrj      In fopen-vms.h, they are separated from the mode with a comma.
93*fae548d3Szrj      Split here.  */
94*fae548d3Szrj   vms_attr = strchr (modes, ',');
95*fae548d3Szrj   if (vms_attr == NULL)
96*fae548d3Szrj     {
97*fae548d3Szrj       /* No attributes.  */
98*fae548d3Szrj       return close_on_exec (fopen (filename, modes));
99*fae548d3Szrj     }
100*fae548d3Szrj   else
101*fae548d3Szrj     {
102*fae548d3Szrj       /* Attributes found.  Split.  */
103*fae548d3Szrj       size_t modes_len = strlen (modes) + 1;
104*fae548d3Szrj       char attrs[modes_len + 1];
105*fae548d3Szrj       char *at[3];
106*fae548d3Szrj       int i;
107*fae548d3Szrj 
108*fae548d3Szrj       memcpy (attrs, modes, modes_len);
109*fae548d3Szrj       at[0] = attrs;
110*fae548d3Szrj       for (i = 0; i < 2; i++)
111*fae548d3Szrj 	{
112*fae548d3Szrj 	  at[i + 1] = strchr (at[i], ',');
113*fae548d3Szrj 	  BFD_ASSERT (at[i + 1] != NULL);
114*fae548d3Szrj 	  *(at[i + 1]++) = 0; /* Replace ',' with a nul, and skip it.  */
115*fae548d3Szrj 	}
116*fae548d3Szrj       return close_on_exec (fopen (filename, at[0], at[1], at[2]));
117*fae548d3Szrj     }
118*fae548d3Szrj #else /* !VMS */
119*fae548d3Szrj #if defined (HAVE_FOPEN64)
120*fae548d3Szrj   return close_on_exec (fopen64 (filename, modes));
121*fae548d3Szrj #else
122*fae548d3Szrj   return close_on_exec (fopen (filename, modes));
123*fae548d3Szrj #endif
124*fae548d3Szrj #endif /* !VMS */
125*fae548d3Szrj }
126*fae548d3Szrj 
127*fae548d3Szrj /*
128*fae548d3Szrj INTERNAL_DEFINITION
129*fae548d3Szrj 	struct bfd_iovec
130*fae548d3Szrj 
131*fae548d3Szrj DESCRIPTION
132*fae548d3Szrj 
133*fae548d3Szrj 	The <<struct bfd_iovec>> contains the internal file I/O class.
134*fae548d3Szrj 	Each <<BFD>> has an instance of this class and all file I/O is
135*fae548d3Szrj 	routed through it (it is assumed that the instance implements
136*fae548d3Szrj 	all methods listed below).
137*fae548d3Szrj 
138*fae548d3Szrj .struct bfd_iovec
139*fae548d3Szrj .{
140*fae548d3Szrj .  {* To avoid problems with macros, a "b" rather than "f"
141*fae548d3Szrj .     prefix is prepended to each method name.  *}
142*fae548d3Szrj .  {* Attempt to read/write NBYTES on ABFD's IOSTREAM storing/fetching
143*fae548d3Szrj .     bytes starting at PTR.  Return the number of bytes actually
144*fae548d3Szrj .     transfered (a read past end-of-file returns less than NBYTES),
145*fae548d3Szrj .     or -1 (setting <<bfd_error>>) if an error occurs.  *}
146*fae548d3Szrj .  file_ptr (*bread) (struct bfd *abfd, void *ptr, file_ptr nbytes);
147*fae548d3Szrj .  file_ptr (*bwrite) (struct bfd *abfd, const void *ptr,
148*fae548d3Szrj .		       file_ptr nbytes);
149*fae548d3Szrj .  {* Return the current IOSTREAM file offset, or -1 (setting <<bfd_error>>
150*fae548d3Szrj .     if an error occurs.  *}
151*fae548d3Szrj .  file_ptr (*btell) (struct bfd *abfd);
152*fae548d3Szrj .  {* For the following, on successful completion a value of 0 is returned.
153*fae548d3Szrj .     Otherwise, a value of -1 is returned (and <<bfd_error>> is set).  *}
154*fae548d3Szrj .  int (*bseek) (struct bfd *abfd, file_ptr offset, int whence);
155*fae548d3Szrj .  int (*bclose) (struct bfd *abfd);
156*fae548d3Szrj .  int (*bflush) (struct bfd *abfd);
157*fae548d3Szrj .  int (*bstat) (struct bfd *abfd, struct stat *sb);
158*fae548d3Szrj .  {* Mmap a part of the files. ADDR, LEN, PROT, FLAGS and OFFSET are the usual
159*fae548d3Szrj .     mmap parameter, except that LEN and OFFSET do not need to be page
160*fae548d3Szrj .     aligned.  Returns (void *)-1 on failure, mmapped address on success.
161*fae548d3Szrj .     Also write in MAP_ADDR the address of the page aligned buffer and in
162*fae548d3Szrj .     MAP_LEN the size mapped (a page multiple).  Use unmap with MAP_ADDR and
163*fae548d3Szrj .     MAP_LEN to unmap.  *}
164*fae548d3Szrj .  void *(*bmmap) (struct bfd *abfd, void *addr, bfd_size_type len,
165*fae548d3Szrj .		   int prot, int flags, file_ptr offset,
166*fae548d3Szrj .		   void **map_addr, bfd_size_type *map_len);
167*fae548d3Szrj .};
168*fae548d3Szrj 
169*fae548d3Szrj .extern const struct bfd_iovec _bfd_memory_iovec;
170*fae548d3Szrj 
171*fae548d3Szrj */
172*fae548d3Szrj 
173*fae548d3Szrj 
174*fae548d3Szrj /* Return value is amount read.  */
175*fae548d3Szrj 
176*fae548d3Szrj bfd_size_type
bfd_bread(void * ptr,bfd_size_type size,bfd * abfd)177*fae548d3Szrj bfd_bread (void *ptr, bfd_size_type size, bfd *abfd)
178*fae548d3Szrj {
179*fae548d3Szrj   file_ptr nread;
180*fae548d3Szrj   bfd *element_bfd = abfd;
181*fae548d3Szrj   ufile_ptr offset = 0;
182*fae548d3Szrj 
183*fae548d3Szrj   while (abfd->my_archive != NULL
184*fae548d3Szrj 	 && !bfd_is_thin_archive (abfd->my_archive))
185*fae548d3Szrj     {
186*fae548d3Szrj       offset += abfd->origin;
187*fae548d3Szrj       abfd = abfd->my_archive;
188*fae548d3Szrj     }
189*fae548d3Szrj 
190*fae548d3Szrj   /* If this is an archive element, don't read past the end of
191*fae548d3Szrj      this element.  */
192*fae548d3Szrj   if (element_bfd->arelt_data != NULL)
193*fae548d3Szrj     {
194*fae548d3Szrj       bfd_size_type maxbytes = arelt_size (element_bfd);
195*fae548d3Szrj 
196*fae548d3Szrj       if (abfd->where < offset || abfd->where - offset >= maxbytes)
197*fae548d3Szrj 	{
198*fae548d3Szrj 	  bfd_set_error (bfd_error_invalid_operation);
199*fae548d3Szrj 	  return -1;
200*fae548d3Szrj 	}
201*fae548d3Szrj       if (abfd->where - offset + size > maxbytes)
202*fae548d3Szrj 	size = maxbytes - (abfd->where - offset);
203*fae548d3Szrj     }
204*fae548d3Szrj 
205*fae548d3Szrj   if (abfd->iovec == NULL)
206*fae548d3Szrj     {
207*fae548d3Szrj       bfd_set_error (bfd_error_invalid_operation);
208*fae548d3Szrj       return -1;
209*fae548d3Szrj     }
210*fae548d3Szrj 
211*fae548d3Szrj   nread = abfd->iovec->bread (abfd, ptr, size);
212*fae548d3Szrj   if (nread != -1)
213*fae548d3Szrj     abfd->where += nread;
214*fae548d3Szrj 
215*fae548d3Szrj   return nread;
216*fae548d3Szrj }
217*fae548d3Szrj 
218*fae548d3Szrj bfd_size_type
bfd_bwrite(const void * ptr,bfd_size_type size,bfd * abfd)219*fae548d3Szrj bfd_bwrite (const void *ptr, bfd_size_type size, bfd *abfd)
220*fae548d3Szrj {
221*fae548d3Szrj   file_ptr nwrote;
222*fae548d3Szrj 
223*fae548d3Szrj   while (abfd->my_archive != NULL
224*fae548d3Szrj 	 && !bfd_is_thin_archive (abfd->my_archive))
225*fae548d3Szrj     abfd = abfd->my_archive;
226*fae548d3Szrj 
227*fae548d3Szrj   if (abfd->iovec == NULL)
228*fae548d3Szrj     {
229*fae548d3Szrj       bfd_set_error (bfd_error_invalid_operation);
230*fae548d3Szrj       return -1;
231*fae548d3Szrj     }
232*fae548d3Szrj 
233*fae548d3Szrj   nwrote = abfd->iovec->bwrite (abfd, ptr, size);
234*fae548d3Szrj   if (nwrote != -1)
235*fae548d3Szrj     abfd->where += nwrote;
236*fae548d3Szrj   if ((bfd_size_type) nwrote != size)
237*fae548d3Szrj     {
238*fae548d3Szrj #ifdef ENOSPC
239*fae548d3Szrj       errno = ENOSPC;
240*fae548d3Szrj #endif
241*fae548d3Szrj       bfd_set_error (bfd_error_system_call);
242*fae548d3Szrj     }
243*fae548d3Szrj   return nwrote;
244*fae548d3Szrj }
245*fae548d3Szrj 
246*fae548d3Szrj file_ptr
bfd_tell(bfd * abfd)247*fae548d3Szrj bfd_tell (bfd *abfd)
248*fae548d3Szrj {
249*fae548d3Szrj   ufile_ptr offset = 0;
250*fae548d3Szrj   file_ptr ptr;
251*fae548d3Szrj 
252*fae548d3Szrj   while (abfd->my_archive != NULL
253*fae548d3Szrj 	 && !bfd_is_thin_archive (abfd->my_archive))
254*fae548d3Szrj     {
255*fae548d3Szrj       offset += abfd->origin;
256*fae548d3Szrj       abfd = abfd->my_archive;
257*fae548d3Szrj     }
258*fae548d3Szrj 
259*fae548d3Szrj   if (abfd->iovec == NULL)
260*fae548d3Szrj     return 0;
261*fae548d3Szrj 
262*fae548d3Szrj   ptr = abfd->iovec->btell (abfd);
263*fae548d3Szrj   abfd->where = ptr;
264*fae548d3Szrj   return ptr - offset;
265*fae548d3Szrj }
266*fae548d3Szrj 
267*fae548d3Szrj int
bfd_flush(bfd * abfd)268*fae548d3Szrj bfd_flush (bfd *abfd)
269*fae548d3Szrj {
270*fae548d3Szrj   while (abfd->my_archive != NULL
271*fae548d3Szrj 	 && !bfd_is_thin_archive (abfd->my_archive))
272*fae548d3Szrj     abfd = abfd->my_archive;
273*fae548d3Szrj 
274*fae548d3Szrj   if (abfd->iovec == NULL)
275*fae548d3Szrj     return 0;
276*fae548d3Szrj 
277*fae548d3Szrj   return abfd->iovec->bflush (abfd);
278*fae548d3Szrj }
279*fae548d3Szrj 
280*fae548d3Szrj /* Returns 0 for success, negative value for failure (in which case
281*fae548d3Szrj    bfd_get_error can retrieve the error code).  */
282*fae548d3Szrj int
bfd_stat(bfd * abfd,struct stat * statbuf)283*fae548d3Szrj bfd_stat (bfd *abfd, struct stat *statbuf)
284*fae548d3Szrj {
285*fae548d3Szrj   int result;
286*fae548d3Szrj 
287*fae548d3Szrj   while (abfd->my_archive != NULL
288*fae548d3Szrj 	 && !bfd_is_thin_archive (abfd->my_archive))
289*fae548d3Szrj     abfd = abfd->my_archive;
290*fae548d3Szrj 
291*fae548d3Szrj   if (abfd->iovec == NULL)
292*fae548d3Szrj     {
293*fae548d3Szrj       bfd_set_error (bfd_error_invalid_operation);
294*fae548d3Szrj       return -1;
295*fae548d3Szrj     }
296*fae548d3Szrj 
297*fae548d3Szrj   result = abfd->iovec->bstat (abfd, statbuf);
298*fae548d3Szrj   if (result < 0)
299*fae548d3Szrj     bfd_set_error (bfd_error_system_call);
300*fae548d3Szrj   return result;
301*fae548d3Szrj }
302*fae548d3Szrj 
303*fae548d3Szrj /* Returns 0 for success, nonzero for failure (in which case bfd_get_error
304*fae548d3Szrj    can retrieve the error code).  */
305*fae548d3Szrj 
306*fae548d3Szrj int
bfd_seek(bfd * abfd,file_ptr position,int direction)307*fae548d3Szrj bfd_seek (bfd *abfd, file_ptr position, int direction)
308*fae548d3Szrj {
309*fae548d3Szrj   int result;
310*fae548d3Szrj   ufile_ptr offset = 0;
311*fae548d3Szrj 
312*fae548d3Szrj   while (abfd->my_archive != NULL
313*fae548d3Szrj 	 && !bfd_is_thin_archive (abfd->my_archive))
314*fae548d3Szrj     {
315*fae548d3Szrj       offset += abfd->origin;
316*fae548d3Szrj       abfd = abfd->my_archive;
317*fae548d3Szrj     }
318*fae548d3Szrj 
319*fae548d3Szrj   if (abfd->iovec == NULL)
320*fae548d3Szrj     {
321*fae548d3Szrj       bfd_set_error (bfd_error_invalid_operation);
322*fae548d3Szrj       return -1;
323*fae548d3Szrj     }
324*fae548d3Szrj 
325*fae548d3Szrj   /* For the time being, a BFD may not seek to it's end.  The problem
326*fae548d3Szrj      is that we don't easily have a way to recognize the end of an
327*fae548d3Szrj      element in an archive.  */
328*fae548d3Szrj   BFD_ASSERT (direction == SEEK_SET || direction == SEEK_CUR);
329*fae548d3Szrj 
330*fae548d3Szrj   if (direction != SEEK_CUR)
331*fae548d3Szrj     position += offset;
332*fae548d3Szrj 
333*fae548d3Szrj   if ((direction == SEEK_CUR && position == 0)
334*fae548d3Szrj       || (direction == SEEK_SET && (ufile_ptr) position == abfd->where))
335*fae548d3Szrj     return 0;
336*fae548d3Szrj 
337*fae548d3Szrj   result = abfd->iovec->bseek (abfd, position, direction);
338*fae548d3Szrj   if (result != 0)
339*fae548d3Szrj     {
340*fae548d3Szrj       /* An EINVAL error probably means that the file offset was
341*fae548d3Szrj 	 absurd.  */
342*fae548d3Szrj       if (errno == EINVAL)
343*fae548d3Szrj 	bfd_set_error (bfd_error_file_truncated);
344*fae548d3Szrj       else
345*fae548d3Szrj 	bfd_set_error (bfd_error_system_call);
346*fae548d3Szrj     }
347*fae548d3Szrj   else
348*fae548d3Szrj     {
349*fae548d3Szrj       /* Adjust `where' field.  */
350*fae548d3Szrj       if (direction == SEEK_CUR)
351*fae548d3Szrj 	abfd->where += position;
352*fae548d3Szrj       else
353*fae548d3Szrj 	abfd->where = position;
354*fae548d3Szrj     }
355*fae548d3Szrj 
356*fae548d3Szrj   return result;
357*fae548d3Szrj }
358*fae548d3Szrj 
359*fae548d3Szrj /*
360*fae548d3Szrj FUNCTION
361*fae548d3Szrj 	bfd_get_mtime
362*fae548d3Szrj 
363*fae548d3Szrj SYNOPSIS
364*fae548d3Szrj 	long bfd_get_mtime (bfd *abfd);
365*fae548d3Szrj 
366*fae548d3Szrj DESCRIPTION
367*fae548d3Szrj 	Return the file modification time (as read from the file system, or
368*fae548d3Szrj 	from the archive header for archive members).
369*fae548d3Szrj 
370*fae548d3Szrj */
371*fae548d3Szrj 
372*fae548d3Szrj long
bfd_get_mtime(bfd * abfd)373*fae548d3Szrj bfd_get_mtime (bfd *abfd)
374*fae548d3Szrj {
375*fae548d3Szrj   struct stat buf;
376*fae548d3Szrj 
377*fae548d3Szrj   if (abfd->mtime_set)
378*fae548d3Szrj     return abfd->mtime;
379*fae548d3Szrj 
380*fae548d3Szrj   if (bfd_stat (abfd, &buf) != 0)
381*fae548d3Szrj     return 0;
382*fae548d3Szrj 
383*fae548d3Szrj   abfd->mtime = buf.st_mtime;		/* Save value in case anyone wants it */
384*fae548d3Szrj   return buf.st_mtime;
385*fae548d3Szrj }
386*fae548d3Szrj 
387*fae548d3Szrj /*
388*fae548d3Szrj FUNCTION
389*fae548d3Szrj 	bfd_get_size
390*fae548d3Szrj 
391*fae548d3Szrj SYNOPSIS
392*fae548d3Szrj 	ufile_ptr bfd_get_size (bfd *abfd);
393*fae548d3Szrj 
394*fae548d3Szrj DESCRIPTION
395*fae548d3Szrj 	Return the file size (as read from file system) for the file
396*fae548d3Szrj 	associated with BFD @var{abfd}.
397*fae548d3Szrj 
398*fae548d3Szrj 	The initial motivation for, and use of, this routine is not
399*fae548d3Szrj 	so we can get the exact size of the object the BFD applies to, since
400*fae548d3Szrj 	that might not be generally possible (archive members for example).
401*fae548d3Szrj 	It would be ideal if someone could eventually modify
402*fae548d3Szrj 	it so that such results were guaranteed.
403*fae548d3Szrj 
404*fae548d3Szrj 	Instead, we want to ask questions like "is this NNN byte sized
405*fae548d3Szrj 	object I'm about to try read from file offset YYY reasonable?"
406*fae548d3Szrj 	As as example of where we might do this, some object formats
407*fae548d3Szrj 	use string tables for which the first <<sizeof (long)>> bytes of the
408*fae548d3Szrj 	table contain the size of the table itself, including the size bytes.
409*fae548d3Szrj 	If an application tries to read what it thinks is one of these
410*fae548d3Szrj 	string tables, without some way to validate the size, and for
411*fae548d3Szrj 	some reason the size is wrong (byte swapping error, wrong location
412*fae548d3Szrj 	for the string table, etc.), the only clue is likely to be a read
413*fae548d3Szrj 	error when it tries to read the table, or a "virtual memory
414*fae548d3Szrj 	exhausted" error when it tries to allocate 15 bazillon bytes
415*fae548d3Szrj 	of space for the 15 bazillon byte table it is about to read.
416*fae548d3Szrj 	This function at least allows us to answer the question, "is the
417*fae548d3Szrj 	size reasonable?".
418*fae548d3Szrj */
419*fae548d3Szrj 
420*fae548d3Szrj ufile_ptr
bfd_get_size(bfd * abfd)421*fae548d3Szrj bfd_get_size (bfd *abfd)
422*fae548d3Szrj {
423*fae548d3Szrj   struct stat buf;
424*fae548d3Szrj 
425*fae548d3Szrj   if (bfd_stat (abfd, &buf) != 0)
426*fae548d3Szrj     return 0;
427*fae548d3Szrj 
428*fae548d3Szrj   return buf.st_size;
429*fae548d3Szrj }
430*fae548d3Szrj 
431*fae548d3Szrj /*
432*fae548d3Szrj FUNCTION
433*fae548d3Szrj 	bfd_get_file_size
434*fae548d3Szrj 
435*fae548d3Szrj SYNOPSIS
436*fae548d3Szrj 	ufile_ptr bfd_get_file_size (bfd *abfd);
437*fae548d3Szrj 
438*fae548d3Szrj DESCRIPTION
439*fae548d3Szrj 	Return the file size (as read from file system) for the file
440*fae548d3Szrj 	associated with BFD @var{abfd}.  It supports both normal files
441*fae548d3Szrj 	and archive elements.
442*fae548d3Szrj 
443*fae548d3Szrj */
444*fae548d3Szrj 
445*fae548d3Szrj ufile_ptr
bfd_get_file_size(bfd * abfd)446*fae548d3Szrj bfd_get_file_size (bfd *abfd)
447*fae548d3Szrj {
448*fae548d3Szrj   if (abfd->my_archive != NULL
449*fae548d3Szrj       && !bfd_is_thin_archive (abfd->my_archive))
450*fae548d3Szrj     return arelt_size (abfd);
451*fae548d3Szrj 
452*fae548d3Szrj   return bfd_get_size (abfd);
453*fae548d3Szrj }
454*fae548d3Szrj 
455*fae548d3Szrj /*
456*fae548d3Szrj FUNCTION
457*fae548d3Szrj 	bfd_mmap
458*fae548d3Szrj 
459*fae548d3Szrj SYNOPSIS
460*fae548d3Szrj 	void *bfd_mmap (bfd *abfd, void *addr, bfd_size_type len,
461*fae548d3Szrj 			int prot, int flags, file_ptr offset,
462*fae548d3Szrj 			void **map_addr, bfd_size_type *map_len);
463*fae548d3Szrj 
464*fae548d3Szrj DESCRIPTION
465*fae548d3Szrj 	Return mmap()ed region of the file, if possible and implemented.
466*fae548d3Szrj 	LEN and OFFSET do not need to be page aligned.  The page aligned
467*fae548d3Szrj 	address and length are written to MAP_ADDR and MAP_LEN.
468*fae548d3Szrj 
469*fae548d3Szrj */
470*fae548d3Szrj 
471*fae548d3Szrj void *
bfd_mmap(bfd * abfd,void * addr,bfd_size_type len,int prot,int flags,file_ptr offset,void ** map_addr,bfd_size_type * map_len)472*fae548d3Szrj bfd_mmap (bfd *abfd, void *addr, bfd_size_type len,
473*fae548d3Szrj 	  int prot, int flags, file_ptr offset,
474*fae548d3Szrj 	  void **map_addr, bfd_size_type *map_len)
475*fae548d3Szrj {
476*fae548d3Szrj   while (abfd->my_archive != NULL
477*fae548d3Szrj 	 && !bfd_is_thin_archive (abfd->my_archive))
478*fae548d3Szrj     {
479*fae548d3Szrj       offset += abfd->origin;
480*fae548d3Szrj       abfd = abfd->my_archive;
481*fae548d3Szrj     }
482*fae548d3Szrj 
483*fae548d3Szrj   if (abfd->iovec == NULL)
484*fae548d3Szrj     {
485*fae548d3Szrj       bfd_set_error (bfd_error_invalid_operation);
486*fae548d3Szrj       return (void *) -1;
487*fae548d3Szrj     }
488*fae548d3Szrj 
489*fae548d3Szrj   return abfd->iovec->bmmap (abfd, addr, len, prot, flags, offset,
490*fae548d3Szrj 			     map_addr, map_len);
491*fae548d3Szrj }
492*fae548d3Szrj 
493*fae548d3Szrj /* Memory file I/O operations.  */
494*fae548d3Szrj 
495*fae548d3Szrj static file_ptr
memory_bread(bfd * abfd,void * ptr,file_ptr size)496*fae548d3Szrj memory_bread (bfd *abfd, void *ptr, file_ptr size)
497*fae548d3Szrj {
498*fae548d3Szrj   struct bfd_in_memory *bim;
499*fae548d3Szrj   bfd_size_type get;
500*fae548d3Szrj 
501*fae548d3Szrj   bim = (struct bfd_in_memory *) abfd->iostream;
502*fae548d3Szrj   get = size;
503*fae548d3Szrj   if (abfd->where + get > bim->size)
504*fae548d3Szrj     {
505*fae548d3Szrj       if (bim->size < (bfd_size_type) abfd->where)
506*fae548d3Szrj 	get = 0;
507*fae548d3Szrj       else
508*fae548d3Szrj 	get = bim->size - abfd->where;
509*fae548d3Szrj       bfd_set_error (bfd_error_file_truncated);
510*fae548d3Szrj     }
511*fae548d3Szrj   memcpy (ptr, bim->buffer + abfd->where, (size_t) get);
512*fae548d3Szrj   return get;
513*fae548d3Szrj }
514*fae548d3Szrj 
515*fae548d3Szrj static file_ptr
memory_bwrite(bfd * abfd,const void * ptr,file_ptr size)516*fae548d3Szrj memory_bwrite (bfd *abfd, const void *ptr, file_ptr size)
517*fae548d3Szrj {
518*fae548d3Szrj   struct bfd_in_memory *bim = (struct bfd_in_memory *) abfd->iostream;
519*fae548d3Szrj 
520*fae548d3Szrj   if (abfd->where + size > bim->size)
521*fae548d3Szrj     {
522*fae548d3Szrj       bfd_size_type newsize, oldsize;
523*fae548d3Szrj 
524*fae548d3Szrj       oldsize = (bim->size + 127) & ~(bfd_size_type) 127;
525*fae548d3Szrj       bim->size = abfd->where + size;
526*fae548d3Szrj       /* Round up to cut down on memory fragmentation */
527*fae548d3Szrj       newsize = (bim->size + 127) & ~(bfd_size_type) 127;
528*fae548d3Szrj       if (newsize > oldsize)
529*fae548d3Szrj 	{
530*fae548d3Szrj 	  bim->buffer = (bfd_byte *) bfd_realloc_or_free (bim->buffer, newsize);
531*fae548d3Szrj 	  if (bim->buffer == NULL)
532*fae548d3Szrj 	    {
533*fae548d3Szrj 	      bim->size = 0;
534*fae548d3Szrj 	      return 0;
535*fae548d3Szrj 	    }
536*fae548d3Szrj 	  if (newsize > bim->size)
537*fae548d3Szrj 	    memset (bim->buffer + bim->size, 0, newsize - bim->size);
538*fae548d3Szrj 	}
539*fae548d3Szrj     }
540*fae548d3Szrj   memcpy (bim->buffer + abfd->where, ptr, (size_t) size);
541*fae548d3Szrj   return size;
542*fae548d3Szrj }
543*fae548d3Szrj 
544*fae548d3Szrj static file_ptr
memory_btell(bfd * abfd)545*fae548d3Szrj memory_btell (bfd *abfd)
546*fae548d3Szrj {
547*fae548d3Szrj   return abfd->where;
548*fae548d3Szrj }
549*fae548d3Szrj 
550*fae548d3Szrj static int
memory_bseek(bfd * abfd,file_ptr position,int direction)551*fae548d3Szrj memory_bseek (bfd *abfd, file_ptr position, int direction)
552*fae548d3Szrj {
553*fae548d3Szrj   file_ptr nwhere;
554*fae548d3Szrj   struct bfd_in_memory *bim;
555*fae548d3Szrj 
556*fae548d3Szrj   bim = (struct bfd_in_memory *) abfd->iostream;
557*fae548d3Szrj 
558*fae548d3Szrj   if (direction == SEEK_SET)
559*fae548d3Szrj     nwhere = position;
560*fae548d3Szrj   else
561*fae548d3Szrj     nwhere = abfd->where + position;
562*fae548d3Szrj 
563*fae548d3Szrj   if (nwhere < 0)
564*fae548d3Szrj     {
565*fae548d3Szrj       abfd->where = 0;
566*fae548d3Szrj       errno = EINVAL;
567*fae548d3Szrj       return -1;
568*fae548d3Szrj     }
569*fae548d3Szrj 
570*fae548d3Szrj   if ((bfd_size_type)nwhere > bim->size)
571*fae548d3Szrj     {
572*fae548d3Szrj       if (abfd->direction == write_direction
573*fae548d3Szrj 	  || abfd->direction == both_direction)
574*fae548d3Szrj 	{
575*fae548d3Szrj 	  bfd_size_type newsize, oldsize;
576*fae548d3Szrj 
577*fae548d3Szrj 	  oldsize = (bim->size + 127) & ~(bfd_size_type) 127;
578*fae548d3Szrj 	  bim->size = nwhere;
579*fae548d3Szrj 	  /* Round up to cut down on memory fragmentation */
580*fae548d3Szrj 	  newsize = (bim->size + 127) & ~(bfd_size_type) 127;
581*fae548d3Szrj 	  if (newsize > oldsize)
582*fae548d3Szrj 	    {
583*fae548d3Szrj 	      bim->buffer = (bfd_byte *) bfd_realloc_or_free (bim->buffer, newsize);
584*fae548d3Szrj 	      if (bim->buffer == NULL)
585*fae548d3Szrj 		{
586*fae548d3Szrj 		  errno = EINVAL;
587*fae548d3Szrj 		  bim->size = 0;
588*fae548d3Szrj 		  return -1;
589*fae548d3Szrj 		}
590*fae548d3Szrj 	      memset (bim->buffer + oldsize, 0, newsize - oldsize);
591*fae548d3Szrj 	    }
592*fae548d3Szrj 	}
593*fae548d3Szrj       else
594*fae548d3Szrj 	{
595*fae548d3Szrj 	  abfd->where = bim->size;
596*fae548d3Szrj 	  errno = EINVAL;
597*fae548d3Szrj 	  bfd_set_error (bfd_error_file_truncated);
598*fae548d3Szrj 	  return -1;
599*fae548d3Szrj 	}
600*fae548d3Szrj     }
601*fae548d3Szrj   return 0;
602*fae548d3Szrj }
603*fae548d3Szrj 
604*fae548d3Szrj static int
memory_bclose(struct bfd * abfd)605*fae548d3Szrj memory_bclose (struct bfd *abfd)
606*fae548d3Szrj {
607*fae548d3Szrj   struct bfd_in_memory *bim = (struct bfd_in_memory *) abfd->iostream;
608*fae548d3Szrj 
609*fae548d3Szrj   if (bim->buffer != NULL)
610*fae548d3Szrj     free (bim->buffer);
611*fae548d3Szrj   free (bim);
612*fae548d3Szrj   abfd->iostream = NULL;
613*fae548d3Szrj 
614*fae548d3Szrj   return 0;
615*fae548d3Szrj }
616*fae548d3Szrj 
617*fae548d3Szrj static int
memory_bflush(bfd * abfd ATTRIBUTE_UNUSED)618*fae548d3Szrj memory_bflush (bfd *abfd ATTRIBUTE_UNUSED)
619*fae548d3Szrj {
620*fae548d3Szrj   return 0;
621*fae548d3Szrj }
622*fae548d3Szrj 
623*fae548d3Szrj static int
memory_bstat(bfd * abfd,struct stat * statbuf)624*fae548d3Szrj memory_bstat (bfd *abfd, struct stat *statbuf)
625*fae548d3Szrj {
626*fae548d3Szrj   struct bfd_in_memory *bim = (struct bfd_in_memory *) abfd->iostream;
627*fae548d3Szrj 
628*fae548d3Szrj   memset (statbuf, 0, sizeof (*statbuf));
629*fae548d3Szrj   statbuf->st_size = bim->size;
630*fae548d3Szrj 
631*fae548d3Szrj   return 0;
632*fae548d3Szrj }
633*fae548d3Szrj 
634*fae548d3Szrj static void *
memory_bmmap(bfd * abfd ATTRIBUTE_UNUSED,void * addr ATTRIBUTE_UNUSED,bfd_size_type len ATTRIBUTE_UNUSED,int prot ATTRIBUTE_UNUSED,int flags ATTRIBUTE_UNUSED,file_ptr offset ATTRIBUTE_UNUSED,void ** map_addr ATTRIBUTE_UNUSED,bfd_size_type * map_len ATTRIBUTE_UNUSED)635*fae548d3Szrj memory_bmmap (bfd *abfd ATTRIBUTE_UNUSED, void *addr ATTRIBUTE_UNUSED,
636*fae548d3Szrj 	      bfd_size_type len ATTRIBUTE_UNUSED, int prot ATTRIBUTE_UNUSED,
637*fae548d3Szrj 	      int flags ATTRIBUTE_UNUSED, file_ptr offset ATTRIBUTE_UNUSED,
638*fae548d3Szrj 	      void **map_addr ATTRIBUTE_UNUSED,
639*fae548d3Szrj 	      bfd_size_type *map_len ATTRIBUTE_UNUSED)
640*fae548d3Szrj {
641*fae548d3Szrj   return (void *)-1;
642*fae548d3Szrj }
643*fae548d3Szrj 
644*fae548d3Szrj const struct bfd_iovec _bfd_memory_iovec =
645*fae548d3Szrj {
646*fae548d3Szrj   &memory_bread, &memory_bwrite, &memory_btell, &memory_bseek,
647*fae548d3Szrj   &memory_bclose, &memory_bflush, &memory_bstat, &memory_bmmap
648*fae548d3Szrj };
649