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