xref: /netbsd-src/external/gpl3/gdb/dist/bfd/bfdio.c (revision 8e33eff89e26cf71871ead62f0d5063e1313c33a)
1 /* Low-level I/O routines for BFDs.
2 
3    Copyright (C) 1990-2024 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
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
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 *
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 *
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   prefixDOS[] = L"\\\\?\\";
123   const wchar_t   prefixUNC[] = L"\\\\?\\UNC\\";
124   const wchar_t   prefixNone[] = L"";
125   const size_t    partPathLen = strlen (filename) + 1;
126   const wchar_t * prefix;
127   size_t          sizeof_prefix;
128   bool            strip_network_prefix = false;
129 
130   /* PR 31527: In order to not hit limits in the maximum file path, all paths
131      need converting to Universal Naming Convention (UNC) syntax. The following
132      forms may be provided to this function and are converted accordingly.
133 
134      1. UNC paths (start with \\?\), these are unconverted;
135      2. Network paths (start with \\ or // but not \\?\), these are given the
136 	\\?UNC\ prefix, and have the incoming \\ or // removed;
137      3. DOS drive paths (a letter followed by a colon), these are given the
138 	\\?\ prefix;
139      4. Paths relative to CWD, the current working directory is tested for the
140 	above conditions, and otherwise are assumed to be DOS paths.
141 
142      For more information see:
143      https://learn.microsoft.com/en-us/windows/win32/fileio/maximum-file-path-limitation?tabs=registry
144   */
145 
146   if (startswith (filename, "\\\\?\\"))
147     {
148       prefix = prefixNone;
149       sizeof_prefix = sizeof (prefixNone);
150     }
151   else if (startswith (filename, "\\\\") || startswith (filename, "//"))
152     {
153       prefix = prefixUNC;
154       sizeof_prefix = sizeof (prefixUNC);
155       strip_network_prefix = true;
156     }
157   else if (strlen (filename) > 2 && filename[1] == ':')
158     {
159       prefix = prefixDOS;
160       sizeof_prefix = sizeof (prefixDOS);
161     }
162   else
163     {
164       /* The partial path is relative to the current working directory, use this
165 	 to determine the prefix.
166 	 1) Get the length: Calling with lpBuffer set to null returns the length.
167 	 2) Resolve the path.  */
168       size_t    pwdWSize = GetCurrentDirectoryW (0, NULL);
169       wchar_t * pwdPath = calloc (pwdWSize, sizeof(wchar_t));
170       GetCurrentDirectoryW (pwdWSize, pwdPath);
171       if (wcsncmp (pwdPath, L"\\\\?\\", 6) == 0)
172 	{
173 	  prefix = prefixNone;
174 	  sizeof_prefix = sizeof (prefixNone);
175 	}
176       else if (wcsncmp (pwdPath, L"\\\\", 2) == 0
177 	       || wcsncmp (pwdPath, L"//", 2) == 0)
178 	{
179 	  prefix = prefixUNC;
180 	  sizeof_prefix = sizeof (prefixUNC);
181 	  strip_network_prefix = true;
182 	}
183       else
184 	{
185 	  prefix = prefixDOS;
186 	  sizeof_prefix = sizeof (prefixDOS);
187 	}
188       free (pwdPath);
189     }
190 
191 #ifdef __MINGW32__
192 #if !HAVE_DECL____LC_CODEPAGE_FUNC
193   /* This prototype was added to locale.h in version 9.0 of MinGW-w64.  */
194   _CRTIMP unsigned int __cdecl ___lc_codepage_func (void);
195 #endif
196   const unsigned int cp = ___lc_codepage_func ();
197 #else
198   const unsigned int cp = CP_UTF8;
199 #endif
200 
201   /* Converting the partial path from ascii to unicode.
202      1) Get the length: Calling with lpWideCharStr set to null returns the length.
203      2) Convert the string: Calling with cbMultiByte set to -1 includes the terminating null.  */
204   size_t     partPathWSize = MultiByteToWideChar (cp, 0, filename, -1, NULL, 0);
205   wchar_t *  partPath = calloc (partPathWSize, sizeof(wchar_t));
206   size_t     ix;
207 
208   MultiByteToWideChar (cp, 0, filename, -1, partPath, partPathWSize);
209 
210   /* Convert any UNIX style path separators into the DOS i.e. backslash separator.  */
211   for (ix = 0; ix < partPathLen; ix++)
212     if (IS_UNIX_DIR_SEPARATOR(filename[ix]))
213       partPath[ix] = '\\';
214 
215   /* Getting the full path from the provided partial path.
216      1) Get the length.
217      2) Resolve the path.  */
218   long       fullPathWSize = GetFullPathNameW (partPath, 0, NULL, lpFilePart);
219   wchar_t *  fullPath = calloc (fullPathWSize + sizeof_prefix + 1, sizeof(wchar_t));
220 
221   wcscpy (fullPath, prefix);
222 
223   int  prefixLen = sizeof_prefix / sizeof(wchar_t);
224 
225   /* Do not add a prefix to the null device.  */
226   if (stricmp (filename, "nul") == 0)
227     prefixLen = 1;
228 
229   wchar_t *  fullPathOffset = fullPath + prefixLen - 1;
230 
231   GetFullPathNameW (partPath, fullPathWSize, fullPathOffset, lpFilePart);
232 
233   if (strip_network_prefix)
234     {
235       /* Remove begining of the beginning two backslash characters (\\).  */
236       wchar_t *_fullPath = calloc (fullPathWSize + sizeof_prefix + 1, sizeof(wchar_t));
237 
238       GetFullPathNameW (fullPath, fullPathWSize + sizeof_prefix + 1, _fullPath, lpFilePart);
239       free (fullPath);
240       fullPath = _fullPath;
241     }
242 
243   free (partPath);
244 
245   /* It is non-standard for modes to exceed 16 characters.  */
246   wchar_t  modesW[16];
247 
248   MultiByteToWideChar (cp, 0, modes, -1, modesW, sizeof(modesW));
249 
250   FILE *  file = _wfopen (fullPath, modesW);
251   free (fullPath);
252 
253   return close_on_exec (file);
254 
255 #elif defined (HAVE_FOPEN64)
256   return close_on_exec (fopen64 (filename, modes));
257 
258 #else
259   return close_on_exec (fopen (filename, modes));
260 #endif
261 }
262 
263 /*
264 INTERNAL_DEFINITION
265 	struct bfd_iovec
266 
267 DESCRIPTION
268 
269 	The <<struct bfd_iovec>> contains the internal file I/O class.
270 	Each <<BFD>> has an instance of this class and all file I/O is
271 	routed through it (it is assumed that the instance implements
272 	all methods listed below).
273 
274 .struct bfd_iovec
275 .{
276 .  {* To avoid problems with macros, a "b" rather than "f"
277 .     prefix is prepended to each method name.  *}
278 .  {* Attempt to read/write NBYTES on ABFD's IOSTREAM storing/fetching
279 .     bytes starting at PTR.  Return the number of bytes actually
280 .     transfered (a read past end-of-file returns less than NBYTES),
281 .     or -1 (setting <<bfd_error>>) if an error occurs.  *}
282 .  file_ptr (*bread) (struct bfd *abfd, void *ptr, file_ptr nbytes);
283 .  file_ptr (*bwrite) (struct bfd *abfd, const void *ptr,
284 .		       file_ptr nbytes);
285 .  {* Return the current IOSTREAM file offset, or -1 (setting <<bfd_error>>
286 .     if an error occurs.  *}
287 .  file_ptr (*btell) (struct bfd *abfd);
288 .  {* For the following, on successful completion a value of 0 is returned.
289 .     Otherwise, a value of -1 is returned (and <<bfd_error>> is set).  *}
290 .  int (*bseek) (struct bfd *abfd, file_ptr offset, int whence);
291 .  int (*bclose) (struct bfd *abfd);
292 .  int (*bflush) (struct bfd *abfd);
293 .  int (*bstat) (struct bfd *abfd, struct stat *sb);
294 .  {* Mmap a part of the files. ADDR, LEN, PROT, FLAGS and OFFSET are the usual
295 .     mmap parameter, except that LEN and OFFSET do not need to be page
296 .     aligned.  Returns (void *)-1 on failure, mmapped address on success.
297 .     Also write in MAP_ADDR the address of the page aligned buffer and in
298 .     MAP_LEN the size mapped (a page multiple).  Use unmap with MAP_ADDR and
299 .     MAP_LEN to unmap.  *}
300 .  void *(*bmmap) (struct bfd *abfd, void *addr, size_t len,
301 .		   int prot, int flags, file_ptr offset,
302 .		   void **map_addr, size_t *map_len);
303 .};
304 
305 .extern const struct bfd_iovec _bfd_memory_iovec;
306 .
307 */
308 
309 
310 /*
311 FUNCTION
312 	bfd_read
313 
314 SYNOPSIS
315 	bfd_size_type bfd_read (void *, bfd_size_type, bfd *)
316 				ATTRIBUTE_WARN_UNUSED_RESULT;
317 
318 DESCRIPTION
319 	Attempt to read SIZE bytes from ABFD's iostream to PTR.
320 	Return the amount read.
321 */
322 
323 bfd_size_type
324 bfd_read (void *ptr, bfd_size_type size, bfd *abfd)
325 {
326   file_ptr nread;
327   bfd *element_bfd = abfd;
328   ufile_ptr offset = 0;
329 
330   while (abfd->my_archive != NULL
331 	 && !bfd_is_thin_archive (abfd->my_archive))
332     {
333       offset += abfd->origin;
334       abfd = abfd->my_archive;
335     }
336   offset += abfd->origin;
337 
338   /* If this is a non-thin archive element, don't read past the end of
339      this element.  */
340   if (element_bfd->arelt_data != NULL
341       && element_bfd->my_archive != NULL
342       && !bfd_is_thin_archive (element_bfd->my_archive))
343     {
344       bfd_size_type maxbytes = arelt_size (element_bfd);
345 
346       if (abfd->where < offset || abfd->where - offset >= maxbytes)
347 	{
348 	  bfd_set_error (bfd_error_invalid_operation);
349 	  return -1;
350 	}
351       if (abfd->where - offset + size > maxbytes)
352 	size = maxbytes - (abfd->where - offset);
353     }
354 
355   if (abfd->iovec == NULL)
356     {
357       bfd_set_error (bfd_error_invalid_operation);
358       return -1;
359     }
360 
361   if (abfd->last_io == bfd_io_write)
362     {
363       abfd->last_io = bfd_io_force;
364       if (bfd_seek (abfd, 0, SEEK_CUR) != 0)
365 	return -1;
366     }
367   abfd->last_io = bfd_io_read;
368 
369   nread = abfd->iovec->bread (abfd, ptr, size);
370   if (nread != -1)
371     abfd->where += nread;
372 
373   return nread;
374 }
375 
376 /*
377 FUNCTION
378 	bfd_write
379 
380 SYNOPSIS
381 	bfd_size_type bfd_write (const void *, bfd_size_type, bfd *)
382 				ATTRIBUTE_WARN_UNUSED_RESULT;
383 
384 DESCRIPTION
385 	Attempt to write SIZE bytes to ABFD's iostream from PTR.
386 	Return the amount written.
387 */
388 
389 bfd_size_type
390 bfd_write (const void *ptr, bfd_size_type size, bfd *abfd)
391 {
392   file_ptr nwrote;
393 
394   while (abfd->my_archive != NULL
395 	 && !bfd_is_thin_archive (abfd->my_archive))
396     abfd = abfd->my_archive;
397 
398   if (abfd->iovec == NULL)
399     {
400       bfd_set_error (bfd_error_invalid_operation);
401       return -1;
402     }
403 
404   if (abfd->last_io == bfd_io_read)
405     {
406       abfd->last_io = bfd_io_force;
407       if (bfd_seek (abfd, 0, SEEK_CUR) != 0)
408 	return -1;
409     }
410   abfd->last_io = bfd_io_write;
411 
412   nwrote = abfd->iovec->bwrite (abfd, ptr, size);
413   if (nwrote != -1)
414     abfd->where += nwrote;
415   if ((bfd_size_type) nwrote != size)
416     {
417 #ifdef ENOSPC
418       errno = ENOSPC;
419 #endif
420       bfd_set_error (bfd_error_system_call);
421     }
422   return nwrote;
423 }
424 
425 /*
426 FUNCTION
427 	bfd_tell
428 
429 SYNOPSIS
430 	file_ptr bfd_tell (bfd *) ATTRIBUTE_WARN_UNUSED_RESULT;
431 
432 DESCRIPTION
433 	Return ABFD's iostream file position.
434 */
435 
436 file_ptr
437 bfd_tell (bfd *abfd)
438 {
439   ufile_ptr offset = 0;
440   file_ptr ptr;
441 
442   while (abfd->my_archive != NULL
443 	 && !bfd_is_thin_archive (abfd->my_archive))
444     {
445       offset += abfd->origin;
446       abfd = abfd->my_archive;
447     }
448   offset += abfd->origin;
449 
450   if (abfd->iovec == NULL)
451     return 0;
452 
453   ptr = abfd->iovec->btell (abfd);
454   abfd->where = ptr;
455   return ptr - offset;
456 }
457 
458 /*
459 FUNCTION
460 	bfd_flush
461 
462 SYNOPSIS
463 	int bfd_flush (bfd *);
464 
465 DESCRIPTION
466 	Flush ABFD's iostream pending IO.
467 */
468 
469 int
470 bfd_flush (bfd *abfd)
471 {
472   while (abfd->my_archive != NULL
473 	 && !bfd_is_thin_archive (abfd->my_archive))
474     abfd = abfd->my_archive;
475 
476   if (abfd->iovec == NULL)
477     return 0;
478 
479   return abfd->iovec->bflush (abfd);
480 }
481 
482 /*
483 FUNCTION
484 	bfd_stat
485 
486 SYNOPSIS
487 	int bfd_stat (bfd *, struct stat *) ATTRIBUTE_WARN_UNUSED_RESULT;
488 
489 DESCRIPTION
490 	Call fstat on ABFD's iostream.  Return 0 on success, and a
491 	negative value on failure.
492 */
493 
494 int
495 bfd_stat (bfd *abfd, struct stat *statbuf)
496 {
497   int result;
498 
499   while (abfd->my_archive != NULL
500 	 && !bfd_is_thin_archive (abfd->my_archive))
501     abfd = abfd->my_archive;
502 
503   if (abfd->iovec == NULL)
504     {
505       bfd_set_error (bfd_error_invalid_operation);
506       return -1;
507     }
508 
509   result = abfd->iovec->bstat (abfd, statbuf);
510   if (result < 0)
511     bfd_set_error (bfd_error_system_call);
512   return result;
513 }
514 
515 /*
516 FUNCTION
517 	bfd_seek
518 
519 SYNOPSIS
520 	int bfd_seek (bfd *, file_ptr, int) ATTRIBUTE_WARN_UNUSED_RESULT;
521 
522 DESCRIPTION
523 	Call fseek on ABFD's iostream.  Return 0 on success, and a
524 	negative value on failure.
525 */
526 
527 int
528 bfd_seek (bfd *abfd, file_ptr position, int direction)
529 {
530   int result;
531   ufile_ptr offset = 0;
532 
533   while (abfd->my_archive != NULL
534 	 && !bfd_is_thin_archive (abfd->my_archive))
535     {
536       offset += abfd->origin;
537       abfd = abfd->my_archive;
538     }
539   offset += abfd->origin;
540 
541   if (abfd->iovec == NULL)
542     {
543       bfd_set_error (bfd_error_invalid_operation);
544       return -1;
545     }
546 
547   /* For the time being, a BFD may not seek to it's end.  The problem
548      is that we don't easily have a way to recognize the end of an
549      element in an archive.  */
550   BFD_ASSERT (direction == SEEK_SET || direction == SEEK_CUR);
551 
552   if (direction != SEEK_CUR)
553     position += offset;
554 
555   if (((direction == SEEK_CUR && position == 0)
556        || (direction == SEEK_SET && (ufile_ptr) position == abfd->where))
557       && abfd->last_io != bfd_io_force)
558     return 0;
559 
560   abfd->last_io = bfd_io_seek;
561 
562   result = abfd->iovec->bseek (abfd, position, direction);
563   if (result != 0)
564     {
565       /* An EINVAL error probably means that the file offset was
566 	 absurd.  */
567       if (errno == EINVAL)
568 	bfd_set_error (bfd_error_file_truncated);
569       else
570 	bfd_set_error (bfd_error_system_call);
571     }
572   else
573     {
574       /* Adjust `where' field.  */
575       if (direction == SEEK_CUR)
576 	abfd->where += position;
577       else
578 	abfd->where = position;
579     }
580 
581   return result;
582 }
583 
584 /*
585 FUNCTION
586 	bfd_get_mtime
587 
588 SYNOPSIS
589 	long bfd_get_mtime (bfd *abfd);
590 
591 DESCRIPTION
592 	Return the file modification time (as read from the file system, or
593 	from the archive header for archive members).
594 
595 */
596 
597 long
598 bfd_get_mtime (bfd *abfd)
599 {
600   struct stat buf;
601 
602   if (abfd->mtime_set)
603     return abfd->mtime;
604 
605   if (bfd_stat (abfd, &buf) != 0)
606     return 0;
607 
608   abfd->mtime = buf.st_mtime;		/* Save value in case anyone wants it */
609   return buf.st_mtime;
610 }
611 
612 /*
613 FUNCTION
614 	bfd_get_size
615 
616 SYNOPSIS
617 	ufile_ptr bfd_get_size (bfd *abfd);
618 
619 DESCRIPTION
620 	Return the file size (as read from file system) for the file
621 	associated with BFD @var{abfd}.
622 
623 	The initial motivation for, and use of, this routine is not
624 	so we can get the exact size of the object the BFD applies to, since
625 	that might not be generally possible (archive members for example).
626 	It would be ideal if someone could eventually modify
627 	it so that such results were guaranteed.
628 
629 	Instead, we want to ask questions like "is this NNN byte sized
630 	object I'm about to try read from file offset YYY reasonable?"
631 	As as example of where we might do this, some object formats
632 	use string tables for which the first <<sizeof (long)>> bytes of the
633 	table contain the size of the table itself, including the size bytes.
634 	If an application tries to read what it thinks is one of these
635 	string tables, without some way to validate the size, and for
636 	some reason the size is wrong (byte swapping error, wrong location
637 	for the string table, etc.), the only clue is likely to be a read
638 	error when it tries to read the table, or a "virtual memory
639 	exhausted" error when it tries to allocate 15 bazillon bytes
640 	of space for the 15 bazillon byte table it is about to read.
641 	This function at least allows us to answer the question, "is the
642 	size reasonable?".
643 
644 	A return value of zero indicates the file size is unknown.
645 */
646 
647 ufile_ptr
648 bfd_get_size (bfd *abfd)
649 {
650   /* A size of 0 means we haven't yet called bfd_stat.  A size of 1
651      means we have a cached value of 0, ie. unknown.  */
652   if (abfd->size <= 1 || bfd_write_p (abfd))
653     {
654       struct stat buf;
655 
656       if (abfd->size == 1 && !bfd_write_p (abfd))
657 	return 0;
658 
659       if (bfd_stat (abfd, &buf) != 0
660 	  || buf.st_size == 0
661 	  || buf.st_size - (ufile_ptr) buf.st_size != 0)
662 	{
663 	  abfd->size = 1;
664 	  return 0;
665 	}
666       abfd->size = buf.st_size;
667     }
668   return abfd->size;
669 }
670 
671 /*
672 FUNCTION
673 	bfd_get_file_size
674 
675 SYNOPSIS
676 	ufile_ptr bfd_get_file_size (bfd *abfd);
677 
678 DESCRIPTION
679 	Return the file size (as read from file system) for the file
680 	associated with BFD @var{abfd}.  It supports both normal files
681 	and archive elements.
682 
683 */
684 
685 ufile_ptr
686 bfd_get_file_size (bfd *abfd)
687 {
688   ufile_ptr file_size, archive_size = (ufile_ptr) -1;
689   unsigned int compression_p2 = 0;
690 
691   if (abfd->my_archive != NULL
692       && !bfd_is_thin_archive (abfd->my_archive))
693     {
694       struct areltdata *adata = (struct areltdata *) abfd->arelt_data;
695       if (adata != NULL)
696 	{
697 	  archive_size = adata->parsed_size;
698 	  /* If the archive is compressed, assume an element won't
699 	     expand more than eight times file size.  */
700 	  if (adata->arch_header != NULL
701 	      && memcmp (((struct ar_hdr *) adata->arch_header)->ar_fmag,
702 			 "Z\012", 2) == 0)
703 	    compression_p2 = 3;
704 	  abfd = abfd->my_archive;
705 	}
706     }
707 
708   file_size = bfd_get_size (abfd) << compression_p2;
709   if (archive_size < file_size)
710     return archive_size;
711   return file_size;
712 }
713 
714 /*
715 FUNCTION
716 	bfd_mmap
717 
718 SYNOPSIS
719 	void *bfd_mmap (bfd *abfd, void *addr, size_t len,
720 			int prot, int flags, file_ptr offset,
721 			void **map_addr, size_t *map_len)
722 			ATTRIBUTE_WARN_UNUSED_RESULT;
723 
724 DESCRIPTION
725 	Return mmap()ed region of the file, if possible and implemented.
726 	LEN and OFFSET do not need to be page aligned.  The page aligned
727 	address and length are written to MAP_ADDR and MAP_LEN.
728 
729 */
730 
731 void *
732 bfd_mmap (bfd *abfd, void *addr, size_t len,
733 	  int prot, int flags, file_ptr offset,
734 	  void **map_addr, size_t *map_len)
735 {
736   while (abfd->my_archive != NULL
737 	 && !bfd_is_thin_archive (abfd->my_archive))
738     {
739       offset += abfd->origin;
740       abfd = abfd->my_archive;
741     }
742   offset += abfd->origin;
743 
744   if (abfd->iovec == NULL)
745     {
746       bfd_set_error (bfd_error_invalid_operation);
747       return MAP_FAILED;
748     }
749 
750   return abfd->iovec->bmmap (abfd, addr, len, prot, flags, offset,
751 			     map_addr, map_len);
752 }
753 
754 /* Memory file I/O operations.  */
755 
756 static file_ptr
757 memory_bread (bfd *abfd, void *ptr, file_ptr size)
758 {
759   struct bfd_in_memory *bim;
760   bfd_size_type get;
761 
762   bim = (struct bfd_in_memory *) abfd->iostream;
763   get = size;
764   if (abfd->where + get > bim->size)
765     {
766       if (bim->size < (bfd_size_type) abfd->where)
767 	get = 0;
768       else
769 	get = bim->size - abfd->where;
770       bfd_set_error (bfd_error_file_truncated);
771     }
772   memcpy (ptr, bim->buffer + abfd->where, (size_t) get);
773   return get;
774 }
775 
776 static file_ptr
777 memory_bwrite (bfd *abfd, const void *ptr, file_ptr size)
778 {
779   struct bfd_in_memory *bim = (struct bfd_in_memory *) abfd->iostream;
780 
781   if (abfd->where + size > bim->size)
782     {
783       bfd_size_type newsize, oldsize;
784 
785       oldsize = (bim->size + 127) & ~(bfd_size_type) 127;
786       bim->size = abfd->where + size;
787       /* Round up to cut down on memory fragmentation */
788       newsize = (bim->size + 127) & ~(bfd_size_type) 127;
789       if (newsize > oldsize)
790 	{
791 	  bim->buffer = (bfd_byte *) bfd_realloc_or_free (bim->buffer, newsize);
792 	  if (bim->buffer == NULL)
793 	    {
794 	      bim->size = 0;
795 	      return 0;
796 	    }
797 	  if (newsize > bim->size)
798 	    memset (bim->buffer + bim->size, 0, newsize - bim->size);
799 	}
800     }
801   memcpy (bim->buffer + abfd->where, ptr, (size_t) size);
802   return size;
803 }
804 
805 static file_ptr
806 memory_btell (bfd *abfd)
807 {
808   return abfd->where;
809 }
810 
811 static int
812 memory_bseek (bfd *abfd, file_ptr position, int direction)
813 {
814   file_ptr nwhere;
815   struct bfd_in_memory *bim;
816 
817   bim = (struct bfd_in_memory *) abfd->iostream;
818 
819   if (direction == SEEK_SET)
820     nwhere = position;
821   else
822     nwhere = abfd->where + position;
823 
824   if (nwhere < 0)
825     {
826       abfd->where = 0;
827       errno = EINVAL;
828       return -1;
829     }
830 
831   if ((bfd_size_type)nwhere > bim->size)
832     {
833       if (abfd->direction == write_direction
834 	  || abfd->direction == both_direction)
835 	{
836 	  bfd_size_type newsize, oldsize;
837 
838 	  oldsize = (bim->size + 127) & ~(bfd_size_type) 127;
839 	  bim->size = nwhere;
840 	  /* Round up to cut down on memory fragmentation */
841 	  newsize = (bim->size + 127) & ~(bfd_size_type) 127;
842 	  if (newsize > oldsize)
843 	    {
844 	      bim->buffer = (bfd_byte *) bfd_realloc_or_free (bim->buffer, newsize);
845 	      if (bim->buffer == NULL)
846 		{
847 		  errno = EINVAL;
848 		  bim->size = 0;
849 		  return -1;
850 		}
851 	      memset (bim->buffer + oldsize, 0, newsize - oldsize);
852 	    }
853 	}
854       else
855 	{
856 	  abfd->where = bim->size;
857 	  errno = EINVAL;
858 	  bfd_set_error (bfd_error_file_truncated);
859 	  return -1;
860 	}
861     }
862   return 0;
863 }
864 
865 static int
866 memory_bclose (struct bfd *abfd)
867 {
868   struct bfd_in_memory *bim = (struct bfd_in_memory *) abfd->iostream;
869 
870   free (bim->buffer);
871   free (bim);
872   abfd->iostream = NULL;
873 
874   return 0;
875 }
876 
877 static int
878 memory_bflush (bfd *abfd ATTRIBUTE_UNUSED)
879 {
880   return 0;
881 }
882 
883 static int
884 memory_bstat (bfd *abfd, struct stat *statbuf)
885 {
886   struct bfd_in_memory *bim = (struct bfd_in_memory *) abfd->iostream;
887 
888   memset (statbuf, 0, sizeof (*statbuf));
889   statbuf->st_size = bim->size;
890 
891   return 0;
892 }
893 
894 static void *
895 memory_bmmap (bfd *abfd ATTRIBUTE_UNUSED, void *addr ATTRIBUTE_UNUSED,
896 	      size_t len ATTRIBUTE_UNUSED, int prot ATTRIBUTE_UNUSED,
897 	      int flags ATTRIBUTE_UNUSED, file_ptr offset ATTRIBUTE_UNUSED,
898 	      void **map_addr ATTRIBUTE_UNUSED,
899 	      size_t *map_len ATTRIBUTE_UNUSED)
900 {
901   return (void *)-1;
902 }
903 
904 const struct bfd_iovec _bfd_memory_iovec =
905 {
906   &memory_bread, &memory_bwrite, &memory_btell, &memory_bseek,
907   &memory_bclose, &memory_bflush, &memory_bstat, &memory_bmmap
908 };
909 
910 /*
911 FUNCTION
912 	bfd_get_current_time
913 
914 SYNOPSIS
915 	time_t bfd_get_current_time (time_t now);
916 
917 DESCRIPTION
918 	Returns the current time.
919 
920 	If the environment variable SOURCE_DATE_EPOCH is defined
921 	then this is parsed and its value is returned.  Otherwise
922 	if the paramter NOW is non-zero, then that is returned.
923 	Otherwise the result of the system call "time(NULL)" is
924 	returned.
925 */
926 
927 time_t
928 bfd_get_current_time (time_t now)
929 {
930   char *source_date_epoch;
931   unsigned long long epoch;
932 
933   /* FIXME: We could probably cache this lookup,
934      and the parsing of its value below.  */
935   source_date_epoch = getenv ("SOURCE_DATE_EPOCH");
936 
937   if (source_date_epoch == NULL)
938     {
939       if (now)
940 	return now;
941       return time (NULL);
942     }
943 
944   epoch = strtoull (source_date_epoch, NULL, 0);
945 
946   /* If epoch == 0 then something is wrong with SOURCE_DATE_EPOCH,
947      but we do not have an easy way to report it.  Since the presence
948      of the environment variable implies that the user wants
949      deterministic behaviour we just accept the 0 value.  */
950 
951   return (time_t) epoch;
952 }
953