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