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