]> git.ipfire.org Git - thirdparty/binutils-gdb.git/blame - bfd/bfdio.c
Automatic date update in version.in
[thirdparty/binutils-gdb.git] / bfd / bfdio.c
CommitLineData
93509525 1/* Low-level I/O routines for BFDs.
7c192733 2
fd67aa11 3 Copyright (C) 1990-2024 Free Software Foundation, Inc.
7c192733 4
93509525
KD
5 Written by Cygnus Support.
6
cd123cb7 7 This file is part of BFD, the Binary File Descriptor library.
93509525 8
cd123cb7
NC
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.
93509525 13
cd123cb7
NC
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.
93509525 18
cd123cb7
NC
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. */
93509525
KD
23
24#include "sysdep.h"
3db64b00 25#include <limits.h>
93509525
KD
26#include "bfd.h"
27#include "libbfd.h"
b570b954 28#include "aout/ar.h"
0b8448af
NC
29#if defined (_WIN32)
30#include <windows.h>
68e80d96 31#include <locale.h>
0b8448af 32#endif
93509525 33
93509525
KD
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
428b207a
TT
44#ifndef FD_CLOEXEC
45#define FD_CLOEXEC 1
46#endif
47
7c192733 48file_ptr
c7c3d11b 49_bfd_real_ftell (FILE *file)
7c192733
AC
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
60int
c7c3d11b 61_bfd_real_fseek (FILE *file, file_ptr offset, int whence)
7c192733
AC
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
428b207a
TT
72/* Mark FILE as close-on-exec. Return FILE. FILE may be NULL, in
73 which case nothing is done. */
74static FILE *
75close_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
2e6f4fae 89FILE *
c7c3d11b 90_bfd_real_fopen (const char *filename, const char *modes)
2e6f4fae 91{
d387240a 92#ifdef VMS
d387240a
TG
93 char *vms_attr;
94
9aff4b7a 95 /* On VMS, fopen allows file attributes as optional arguments.
d387240a
TG
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, ',');
0b8448af 100 if (vms_attr != NULL)
d387240a 101 {
0c376465
TG
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]));
d387240a 117 }
0b8448af
NC
118
119#elif defined (_WIN32)
ba0eb22c 120 /* PR 25713: Handle extra long path names possibly containing '..' and '.'. */
eac88f32
ZX
121 wchar_t ** lpFilePart = {NULL};
122 const wchar_t prefixDOS[] = L"\\\\?\\";
123 const wchar_t prefixUNC[] = L"\\\\?\\UNC\\";
9dd91814 124 const wchar_t prefixNone[] = L"";
eac88f32
ZX
125 const size_t partPathLen = strlen (filename) + 1;
126 const wchar_t * prefix;
127 size_t sizeof_prefix;
9dd91814
NC
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
eac88f32 144 */
eac88f32 145
9dd91814
NC
146 if (startswith (filename, "\\\\?\\"))
147 {
148 prefix = prefixNone;
149 sizeof_prefix = sizeof (prefixNone);
150 }
151 else if (startswith (filename, "\\\\") || startswith (filename, "//"))
eac88f32
ZX
152 {
153 prefix = prefixUNC;
154 sizeof_prefix = sizeof (prefixUNC);
9dd91814 155 strip_network_prefix = true;
eac88f32 156 }
9dd91814 157 else if (strlen (filename) > 2 && filename[1] == ':')
eac88f32
ZX
158 {
159 prefix = prefixDOS;
160 sizeof_prefix = sizeof (prefixDOS);
161 }
9dd91814
NC
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 }
eac88f32 190
68e80d96 191#ifdef __MINGW32__
9d099144 192#if !HAVE_DECL____LC_CODEPAGE_FUNC
eac88f32
ZX
193 /* This prototype was added to locale.h in version 9.0 of MinGW-w64. */
194 _CRTIMP unsigned int __cdecl ___lc_codepage_func (void);
9d099144 195#endif
eac88f32 196 const unsigned int cp = ___lc_codepage_func ();
68e80d96 197#else
eac88f32 198 const unsigned int cp = CP_UTF8;
68e80d96 199#endif
17d60030 200
eac88f32
ZX
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;
17d60030 207
eac88f32 208 MultiByteToWideChar (cp, 0, filename, -1, partPath, partPathWSize);
17d60030 209
eac88f32
ZX
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] = '\\';
0b8448af 214
eac88f32
ZX
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));
cb7da2a6 220
eac88f32 221 wcscpy (fullPath, prefix);
ba0eb22c 222
eac88f32 223 int prefixLen = sizeof_prefix / sizeof(wchar_t);
a8cf07d3 224
eac88f32
ZX
225 /* Do not add a prefix to the null device. */
226 if (stricmp (filename, "nul") == 0)
a8cf07d3
H
227 prefixLen = 1;
228
eac88f32
ZX
229 wchar_t * fullPathOffset = fullPath + prefixLen - 1;
230
231 GetFullPathNameW (partPath, fullPathWSize, fullPathOffset, lpFilePart);
232
9dd91814 233 if (strip_network_prefix)
eac88f32
ZX
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 }
ba0eb22c 242
eac88f32 243 free (partPath);
cb7da2a6 244
eac88f32
ZX
245 /* It is non-standard for modes to exceed 16 characters. */
246 wchar_t modesW[16];
ba0eb22c 247
eac88f32 248 MultiByteToWideChar (cp, 0, modes, -1, modesW, sizeof(modesW));
cb7da2a6 249
eac88f32
ZX
250 FILE * file = _wfopen (fullPath, modesW);
251 free (fullPath);
cb7da2a6 252
eac88f32 253 return close_on_exec (file);
0b8448af
NC
254
255#elif defined (HAVE_FOPEN64)
428b207a 256 return close_on_exec (fopen64 (filename, modes));
0b8448af 257
cb7da2a6 258#else
0b8448af 259 return close_on_exec (fopen (filename, modes));
cb7da2a6 260#endif
2e6f4fae
DJ
261}
262
40838a72
AC
263/*
264INTERNAL_DEFINITION
265 struct bfd_iovec
93509525 266
40838a72 267DESCRIPTION
93509525 268
40838a72
AC
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,
07d6d2b8 284. file_ptr nbytes);
40838a72
AC
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.
07d6d2b8 289. Otherwise, a value of -1 is returned (and <<bfd_error>> is set). *}
40838a72 290. int (*bseek) (struct bfd *abfd, file_ptr offset, int whence);
405bf443 291. int (*bclose) (struct bfd *abfd);
40838a72
AC
292. int (*bflush) (struct bfd *abfd);
293. int (*bstat) (struct bfd *abfd, struct stat *sb);
4c95ab76
TG
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. *}
4810a2d9 300. void *(*bmmap) (struct bfd *abfd, void *addr, size_t len,
07d6d2b8 301. int prot, int flags, file_ptr offset,
4810a2d9 302. void **map_addr, size_t *map_len);
40838a72 303.};
93509525 304
65077aa8 305.extern const struct bfd_iovec _bfd_memory_iovec;
717d4bd6 306.
40838a72 307*/
93509525 308
93509525 309
717d4bd6
AM
310/*
311FUNCTION
226f9f4f 312 bfd_read
717d4bd6
AM
313
314SYNOPSIS
e416bd75
AM
315 bfd_size_type bfd_read (void *, bfd_size_type, bfd *)
316 ATTRIBUTE_WARN_UNUSED_RESULT;
717d4bd6
AM
317
318DESCRIPTION
319 Attempt to read SIZE bytes from ABFD's iostream to PTR.
320 Return the amount read.
321*/
93509525
KD
322
323bfd_size_type
226f9f4f 324bfd_read (void *ptr, bfd_size_type size, bfd *abfd)
93509525 325{
5c4ce239
AM
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 }
4d095f5b 336 offset += abfd->origin;
93509525 337
c17eb63b 338 /* If this is a non-thin archive element, don't read past the end of
1fb41da4 339 this element. */
c17eb63b
L
340 if (element_bfd->arelt_data != NULL
341 && element_bfd->my_archive != NULL
342 && !bfd_is_thin_archive (element_bfd->my_archive))
1fb41da4 343 {
5c4ce239 344 bfd_size_type maxbytes = arelt_size (element_bfd);
f1bb16f8 345
5c4ce239 346 if (abfd->where < offset || abfd->where - offset >= maxbytes)
07d6d2b8 347 {
5c4ce239
AM
348 bfd_set_error (bfd_error_invalid_operation);
349 return -1;
07d6d2b8 350 }
5c4ce239
AM
351 if (abfd->where - offset + size > maxbytes)
352 size = maxbytes - (abfd->where - offset);
1fb41da4
AM
353 }
354
5c4ce239
AM
355 if (abfd->iovec == NULL)
356 {
357 bfd_set_error (bfd_error_invalid_operation);
358 return -1;
359 }
360
f82ee0c8
AM
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
5c4ce239
AM
369 nread = abfd->iovec->bread (abfd, ptr, size);
370 if (nread != -1)
93509525
KD
371 abfd->where += nread;
372
93509525
KD
373 return nread;
374}
375
717d4bd6
AM
376/*
377FUNCTION
226f9f4f 378 bfd_write
717d4bd6
AM
379
380SYNOPSIS
e416bd75
AM
381 bfd_size_type bfd_write (const void *, bfd_size_type, bfd *)
382 ATTRIBUTE_WARN_UNUSED_RESULT;
717d4bd6
AM
383
384DESCRIPTION
385 Attempt to write SIZE bytes to ABFD's iostream from PTR.
386 Return the amount written.
387*/
388
93509525 389bfd_size_type
226f9f4f 390bfd_write (const void *ptr, bfd_size_type size, bfd *abfd)
93509525 391{
5c4ce239 392 file_ptr nwrote;
93509525 393
5c4ce239
AM
394 while (abfd->my_archive != NULL
395 && !bfd_is_thin_archive (abfd->my_archive))
396 abfd = abfd->my_archive;
69fd4758 397
5c4ce239
AM
398 if (abfd->iovec == NULL)
399 {
400 bfd_set_error (bfd_error_invalid_operation);
401 return -1;
402 }
403
f82ee0c8
AM
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
5c4ce239
AM
412 nwrote = abfd->iovec->bwrite (abfd, ptr, size);
413 if (nwrote != -1)
93509525 414 abfd->where += nwrote;
5c4ce239 415 if ((bfd_size_type) nwrote != size)
93509525
KD
416 {
417#ifdef ENOSPC
418 errno = ENOSPC;
419#endif
420 bfd_set_error (bfd_error_system_call);
421 }
422 return nwrote;
423}
424
717d4bd6
AM
425/*
426FUNCTION
427 bfd_tell
428
429SYNOPSIS
e416bd75 430 file_ptr bfd_tell (bfd *) ATTRIBUTE_WARN_UNUSED_RESULT;
717d4bd6
AM
431
432DESCRIPTION
433 Return ABFD's iostream file position.
434*/
435
7c192733 436file_ptr
c58b9523 437bfd_tell (bfd *abfd)
93509525 438{
5c4ce239 439 ufile_ptr offset = 0;
93509525
KD
440 file_ptr ptr;
441
5c4ce239
AM
442 while (abfd->my_archive != NULL
443 && !bfd_is_thin_archive (abfd->my_archive))
69fd4758 444 {
5c4ce239
AM
445 offset += abfd->origin;
446 abfd = abfd->my_archive;
69fd4758 447 }
4d095f5b 448 offset += abfd->origin;
93509525 449
5c4ce239
AM
450 if (abfd->iovec == NULL)
451 return 0;
452
453 ptr = abfd->iovec->btell (abfd);
93509525 454 abfd->where = ptr;
5c4ce239 455 return ptr - offset;
93509525
KD
456}
457
717d4bd6
AM
458/*
459FUNCTION
460 bfd_flush
461
462SYNOPSIS
463 int bfd_flush (bfd *);
464
465DESCRIPTION
466 Flush ABFD's iostream pending IO.
467*/
468
93509525 469int
c58b9523 470bfd_flush (bfd *abfd)
93509525 471{
5c4ce239
AM
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);
93509525
KD
480}
481
717d4bd6
AM
482/*
483FUNCTION
484 bfd_stat
485
486SYNOPSIS
e416bd75 487 int bfd_stat (bfd *, struct stat *) ATTRIBUTE_WARN_UNUSED_RESULT;
717d4bd6
AM
488
489DESCRIPTION
490 Call fstat on ABFD's iostream. Return 0 on success, and a
491 negative value on failure.
492*/
493
93509525 494int
c58b9523 495bfd_stat (bfd *abfd, struct stat *statbuf)
93509525 496{
93509525
KD
497 int result;
498
5c4ce239
AM
499 while (abfd->my_archive != NULL
500 && !bfd_is_thin_archive (abfd->my_archive))
501 abfd = abfd->my_archive;
69fd4758 502
5c4ce239
AM
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);
93509525
KD
510 if (result < 0)
511 bfd_set_error (bfd_error_system_call);
512 return result;
513}
514
717d4bd6
AM
515/*
516FUNCTION
517 bfd_seek
518
519SYNOPSIS
e416bd75 520 int bfd_seek (bfd *, file_ptr, int) ATTRIBUTE_WARN_UNUSED_RESULT;
717d4bd6
AM
521
522DESCRIPTION
523 Call fseek on ABFD's iostream. Return 0 on success, and a
524 negative value on failure.
525*/
93509525
KD
526
527int
c58b9523 528bfd_seek (bfd *abfd, file_ptr position, int direction)
93509525
KD
529{
530 int result;
5c4ce239 531 ufile_ptr offset = 0;
93509525 532
5c4ce239
AM
533 while (abfd->my_archive != NULL
534 && !bfd_is_thin_archive (abfd->my_archive))
93509525 535 {
5c4ce239
AM
536 offset += abfd->origin;
537 abfd = abfd->my_archive;
93509525 538 }
4d095f5b 539 offset += abfd->origin;
93509525 540
5c4ce239 541 if (abfd->iovec == NULL)
660722b0 542 {
5c4ce239
AM
543 bfd_set_error (bfd_error_invalid_operation);
544 return -1;
660722b0 545 }
93509525 546
5c4ce239
AM
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;
69fd4758 554
f82ee0c8
AM
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
5c4ce239 562 result = abfd->iovec->bseek (abfd, position, direction);
93509525
KD
563 if (result != 0)
564 {
93509525 565 /* An EINVAL error probably means that the file offset was
07d6d2b8 566 absurd. */
5c4ce239 567 if (errno == EINVAL)
93509525
KD
568 bfd_set_error (bfd_error_file_truncated);
569 else
5c4ce239 570 bfd_set_error (bfd_error_system_call);
93509525
KD
571 }
572 else
573 {
574 /* Adjust `where' field. */
5c4ce239 575 if (direction == SEEK_CUR)
93509525 576 abfd->where += position;
5c4ce239
AM
577 else
578 abfd->where = position;
93509525 579 }
5c4ce239 580
93509525
KD
581 return result;
582}
583
584/*
585FUNCTION
586 bfd_get_mtime
587
588SYNOPSIS
c58b9523 589 long bfd_get_mtime (bfd *abfd);
93509525
KD
590
591DESCRIPTION
592 Return the file modification time (as read from the file system, or
593 from the archive header for archive members).
594
595*/
596
597long
c58b9523 598bfd_get_mtime (bfd *abfd)
93509525 599{
93509525
KD
600 struct stat buf;
601
602 if (abfd->mtime_set)
603 return abfd->mtime;
604
5c4ce239 605 if (bfd_stat (abfd, &buf) != 0)
93509525
KD
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/*
613FUNCTION
614 bfd_get_size
615
616SYNOPSIS
47fdcf63 617 ufile_ptr bfd_get_size (bfd *abfd);
93509525
KD
618
619DESCRIPTION
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.
5c4491d3 641 This function at least allows us to answer the question, "is the
93509525 642 size reasonable?".
b03202e3
AM
643
644 A return value of zero indicates the file size is unknown.
93509525
KD
645*/
646
47fdcf63 647ufile_ptr
c58b9523 648bfd_get_size (bfd *abfd)
93509525 649{
b03202e3
AM
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;
93509525 655
b03202e3
AM
656 if (abfd->size == 1 && !bfd_write_p (abfd))
657 return 0;
93509525 658
b03202e3
AM
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;
93509525 669}
25b88f33 670
8e2f54bc
L
671/*
672FUNCTION
673 bfd_get_file_size
674
675SYNOPSIS
47fdcf63 676 ufile_ptr bfd_get_file_size (bfd *abfd);
8e2f54bc
L
677
678DESCRIPTION
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
47fdcf63 685ufile_ptr
8e2f54bc
L
686bfd_get_file_size (bfd *abfd)
687{
b570b954 688 ufile_ptr file_size, archive_size = (ufile_ptr) -1;
3b37f0f1 689 unsigned int compression_p2 = 0;
b570b954 690
8e2f54bc
L
691 if (abfd->my_archive != NULL
692 && !bfd_is_thin_archive (abfd->my_archive))
b570b954
AM
693 {
694 struct areltdata *adata = (struct areltdata *) abfd->arelt_data;
c01de193
AM
695 if (adata != NULL)
696 {
697 archive_size = adata->parsed_size;
3b37f0f1
AM
698 /* If the archive is compressed, assume an element won't
699 expand more than eight times file size. */
c01de193
AM
700 if (adata->arch_header != NULL
701 && memcmp (((struct ar_hdr *) adata->arch_header)->ar_fmag,
702 "Z\012", 2) == 0)
3b37f0f1 703 compression_p2 = 3;
c01de193
AM
704 abfd = abfd->my_archive;
705 }
b570b954 706 }
8e2f54bc 707
3b37f0f1 708 file_size = bfd_get_size (abfd) << compression_p2;
b570b954
AM
709 if (archive_size < file_size)
710 return archive_size;
711 return file_size;
8e2f54bc 712}
25b88f33
PP
713
714/*
715FUNCTION
716 bfd_mmap
717
718SYNOPSIS
4810a2d9 719 void *bfd_mmap (bfd *abfd, void *addr, size_t len,
07d6d2b8 720 int prot, int flags, file_ptr offset,
4810a2d9 721 void **map_addr, size_t *map_len)
e416bd75 722 ATTRIBUTE_WARN_UNUSED_RESULT;
25b88f33
PP
723
724DESCRIPTION
725 Return mmap()ed region of the file, if possible and implemented.
07d6d2b8
AM
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.
25b88f33
PP
728
729*/
730
731void *
4810a2d9 732bfd_mmap (bfd *abfd, void *addr, size_t len,
4c95ab76 733 int prot, int flags, file_ptr offset,
4810a2d9 734 void **map_addr, size_t *map_len)
25b88f33 735{
5c4ce239
AM
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 }
4d095f5b 742 offset += abfd->origin;
25b88f33
PP
743
744 if (abfd->iovec == NULL)
5c4ce239
AM
745 {
746 bfd_set_error (bfd_error_invalid_operation);
2e384d4f 747 return MAP_FAILED;
5c4ce239 748 }
25b88f33 749
4c95ab76 750 return abfd->iovec->bmmap (abfd, addr, len, prot, flags, offset,
07d6d2b8 751 map_addr, map_len);
25b88f33 752}
65077aa8
TG
753
754/* Memory file I/O operations. */
755
756static file_ptr
757memory_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)
07d6d2b8 767 get = 0;
65077aa8 768 else
07d6d2b8 769 get = bim->size - abfd->where;
65077aa8
TG
770 bfd_set_error (bfd_error_file_truncated);
771 }
772 memcpy (ptr, bim->buffer + abfd->where, (size_t) get);
773 return get;
774}
775
776static file_ptr
777memory_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)
07d6d2b8
AM
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 }
65077aa8
TG
800 }
801 memcpy (bim->buffer + abfd->where, ptr, (size_t) size);
802 return size;
803}
804
805static file_ptr
806memory_btell (bfd *abfd)
807{
808 return abfd->where;
809}
810
811static int
812memory_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
07d6d2b8
AM
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 }
65077aa8 854 else
07d6d2b8
AM
855 {
856 abfd->where = bim->size;
857 errno = EINVAL;
858 bfd_set_error (bfd_error_file_truncated);
859 return -1;
860 }
65077aa8
TG
861 }
862 return 0;
863}
864
405bf443 865static int
65077aa8
TG
866memory_bclose (struct bfd *abfd)
867{
868 struct bfd_in_memory *bim = (struct bfd_in_memory *) abfd->iostream;
869
c9594989 870 free (bim->buffer);
65077aa8
TG
871 free (bim);
872 abfd->iostream = NULL;
873
405bf443 874 return 0;
65077aa8
TG
875}
876
877static int
878memory_bflush (bfd *abfd ATTRIBUTE_UNUSED)
879{
880 return 0;
881}
882
883static int
884memory_bstat (bfd *abfd, struct stat *statbuf)
885{
886 struct bfd_in_memory *bim = (struct bfd_in_memory *) abfd->iostream;
887
b5dee4ea 888 memset (statbuf, 0, sizeof (*statbuf));
65077aa8
TG
889 statbuf->st_size = bim->size;
890
891 return 0;
892}
893
894static void *
895memory_bmmap (bfd *abfd ATTRIBUTE_UNUSED, void *addr ATTRIBUTE_UNUSED,
4810a2d9 896 size_t len ATTRIBUTE_UNUSED, int prot ATTRIBUTE_UNUSED,
07d6d2b8
AM
897 int flags ATTRIBUTE_UNUSED, file_ptr offset ATTRIBUTE_UNUSED,
898 void **map_addr ATTRIBUTE_UNUSED,
4810a2d9 899 size_t *map_len ATTRIBUTE_UNUSED)
65077aa8
TG
900{
901 return (void *)-1;
902}
903
904const 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};
6f567398
NC
909
910/*
911FUNCTION
912 bfd_get_current_time
913
914SYNOPSIS
915 time_t bfd_get_current_time (time_t now);
916
917DESCRIPTION
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
927time_t
928bfd_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}