]> git.ipfire.org Git - thirdparty/binutils-gdb.git/blame - bfd/bfdio.c
Remove dependency upon shlwapi library when building BFD for Windows/MinGW environments.
[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 250 FILE * file = _wfopen (fullPath, modesW);
9dd91814
NC
251 if (!file)
252 perror("Error opening file");
eac88f32 253 free (fullPath);
cb7da2a6 254
eac88f32 255 return close_on_exec (file);
0b8448af
NC
256
257#elif defined (HAVE_FOPEN64)
428b207a 258 return close_on_exec (fopen64 (filename, modes));
0b8448af 259
cb7da2a6 260#else
0b8448af 261 return close_on_exec (fopen (filename, modes));
cb7da2a6 262#endif
2e6f4fae
DJ
263}
264
40838a72
AC
265/*
266INTERNAL_DEFINITION
267 struct bfd_iovec
93509525 268
40838a72 269DESCRIPTION
93509525 270
40838a72
AC
271 The <<struct bfd_iovec>> contains the internal file I/O class.
272 Each <<BFD>> has an instance of this class and all file I/O is
273 routed through it (it is assumed that the instance implements
274 all methods listed below).
275
276.struct bfd_iovec
277.{
278. {* To avoid problems with macros, a "b" rather than "f"
279. prefix is prepended to each method name. *}
280. {* Attempt to read/write NBYTES on ABFD's IOSTREAM storing/fetching
281. bytes starting at PTR. Return the number of bytes actually
282. transfered (a read past end-of-file returns less than NBYTES),
283. or -1 (setting <<bfd_error>>) if an error occurs. *}
284. file_ptr (*bread) (struct bfd *abfd, void *ptr, file_ptr nbytes);
285. file_ptr (*bwrite) (struct bfd *abfd, const void *ptr,
07d6d2b8 286. file_ptr nbytes);
40838a72
AC
287. {* Return the current IOSTREAM file offset, or -1 (setting <<bfd_error>>
288. if an error occurs. *}
289. file_ptr (*btell) (struct bfd *abfd);
290. {* For the following, on successful completion a value of 0 is returned.
07d6d2b8 291. Otherwise, a value of -1 is returned (and <<bfd_error>> is set). *}
40838a72 292. int (*bseek) (struct bfd *abfd, file_ptr offset, int whence);
405bf443 293. int (*bclose) (struct bfd *abfd);
40838a72
AC
294. int (*bflush) (struct bfd *abfd);
295. int (*bstat) (struct bfd *abfd, struct stat *sb);
4c95ab76
TG
296. {* Mmap a part of the files. ADDR, LEN, PROT, FLAGS and OFFSET are the usual
297. mmap parameter, except that LEN and OFFSET do not need to be page
298. aligned. Returns (void *)-1 on failure, mmapped address on success.
299. Also write in MAP_ADDR the address of the page aligned buffer and in
300. MAP_LEN the size mapped (a page multiple). Use unmap with MAP_ADDR and
301. MAP_LEN to unmap. *}
4810a2d9 302. void *(*bmmap) (struct bfd *abfd, void *addr, size_t len,
07d6d2b8 303. int prot, int flags, file_ptr offset,
4810a2d9 304. void **map_addr, size_t *map_len);
40838a72 305.};
93509525 306
65077aa8 307.extern const struct bfd_iovec _bfd_memory_iovec;
717d4bd6 308.
40838a72 309*/
93509525 310
93509525 311
717d4bd6
AM
312/*
313FUNCTION
226f9f4f 314 bfd_read
717d4bd6
AM
315
316SYNOPSIS
e416bd75
AM
317 bfd_size_type bfd_read (void *, bfd_size_type, bfd *)
318 ATTRIBUTE_WARN_UNUSED_RESULT;
717d4bd6
AM
319
320DESCRIPTION
321 Attempt to read SIZE bytes from ABFD's iostream to PTR.
322 Return the amount read.
323*/
93509525
KD
324
325bfd_size_type
226f9f4f 326bfd_read (void *ptr, bfd_size_type size, bfd *abfd)
93509525 327{
5c4ce239
AM
328 file_ptr nread;
329 bfd *element_bfd = abfd;
330 ufile_ptr offset = 0;
331
332 while (abfd->my_archive != NULL
333 && !bfd_is_thin_archive (abfd->my_archive))
334 {
335 offset += abfd->origin;
336 abfd = abfd->my_archive;
337 }
4d095f5b 338 offset += abfd->origin;
93509525 339
c17eb63b 340 /* If this is a non-thin archive element, don't read past the end of
1fb41da4 341 this element. */
c17eb63b
L
342 if (element_bfd->arelt_data != NULL
343 && element_bfd->my_archive != NULL
344 && !bfd_is_thin_archive (element_bfd->my_archive))
1fb41da4 345 {
5c4ce239 346 bfd_size_type maxbytes = arelt_size (element_bfd);
f1bb16f8 347
5c4ce239 348 if (abfd->where < offset || abfd->where - offset >= maxbytes)
07d6d2b8 349 {
5c4ce239
AM
350 bfd_set_error (bfd_error_invalid_operation);
351 return -1;
07d6d2b8 352 }
5c4ce239
AM
353 if (abfd->where - offset + size > maxbytes)
354 size = maxbytes - (abfd->where - offset);
1fb41da4
AM
355 }
356
5c4ce239
AM
357 if (abfd->iovec == NULL)
358 {
359 bfd_set_error (bfd_error_invalid_operation);
360 return -1;
361 }
362
f82ee0c8
AM
363 if (abfd->last_io == bfd_io_write)
364 {
365 abfd->last_io = bfd_io_force;
366 if (bfd_seek (abfd, 0, SEEK_CUR) != 0)
367 return -1;
368 }
369 abfd->last_io = bfd_io_read;
370
5c4ce239
AM
371 nread = abfd->iovec->bread (abfd, ptr, size);
372 if (nread != -1)
93509525
KD
373 abfd->where += nread;
374
93509525
KD
375 return nread;
376}
377
717d4bd6
AM
378/*
379FUNCTION
226f9f4f 380 bfd_write
717d4bd6
AM
381
382SYNOPSIS
e416bd75
AM
383 bfd_size_type bfd_write (const void *, bfd_size_type, bfd *)
384 ATTRIBUTE_WARN_UNUSED_RESULT;
717d4bd6
AM
385
386DESCRIPTION
387 Attempt to write SIZE bytes to ABFD's iostream from PTR.
388 Return the amount written.
389*/
390
93509525 391bfd_size_type
226f9f4f 392bfd_write (const void *ptr, bfd_size_type size, bfd *abfd)
93509525 393{
5c4ce239 394 file_ptr nwrote;
93509525 395
5c4ce239
AM
396 while (abfd->my_archive != NULL
397 && !bfd_is_thin_archive (abfd->my_archive))
398 abfd = abfd->my_archive;
69fd4758 399
5c4ce239
AM
400 if (abfd->iovec == NULL)
401 {
402 bfd_set_error (bfd_error_invalid_operation);
403 return -1;
404 }
405
f82ee0c8
AM
406 if (abfd->last_io == bfd_io_read)
407 {
408 abfd->last_io = bfd_io_force;
409 if (bfd_seek (abfd, 0, SEEK_CUR) != 0)
410 return -1;
411 }
412 abfd->last_io = bfd_io_write;
413
5c4ce239
AM
414 nwrote = abfd->iovec->bwrite (abfd, ptr, size);
415 if (nwrote != -1)
93509525 416 abfd->where += nwrote;
5c4ce239 417 if ((bfd_size_type) nwrote != size)
93509525
KD
418 {
419#ifdef ENOSPC
420 errno = ENOSPC;
421#endif
422 bfd_set_error (bfd_error_system_call);
423 }
424 return nwrote;
425}
426
717d4bd6
AM
427/*
428FUNCTION
429 bfd_tell
430
431SYNOPSIS
e416bd75 432 file_ptr bfd_tell (bfd *) ATTRIBUTE_WARN_UNUSED_RESULT;
717d4bd6
AM
433
434DESCRIPTION
435 Return ABFD's iostream file position.
436*/
437
7c192733 438file_ptr
c58b9523 439bfd_tell (bfd *abfd)
93509525 440{
5c4ce239 441 ufile_ptr offset = 0;
93509525
KD
442 file_ptr ptr;
443
5c4ce239
AM
444 while (abfd->my_archive != NULL
445 && !bfd_is_thin_archive (abfd->my_archive))
69fd4758 446 {
5c4ce239
AM
447 offset += abfd->origin;
448 abfd = abfd->my_archive;
69fd4758 449 }
4d095f5b 450 offset += abfd->origin;
93509525 451
5c4ce239
AM
452 if (abfd->iovec == NULL)
453 return 0;
454
455 ptr = abfd->iovec->btell (abfd);
93509525 456 abfd->where = ptr;
5c4ce239 457 return ptr - offset;
93509525
KD
458}
459
717d4bd6
AM
460/*
461FUNCTION
462 bfd_flush
463
464SYNOPSIS
465 int bfd_flush (bfd *);
466
467DESCRIPTION
468 Flush ABFD's iostream pending IO.
469*/
470
93509525 471int
c58b9523 472bfd_flush (bfd *abfd)
93509525 473{
5c4ce239
AM
474 while (abfd->my_archive != NULL
475 && !bfd_is_thin_archive (abfd->my_archive))
476 abfd = abfd->my_archive;
477
478 if (abfd->iovec == NULL)
479 return 0;
480
481 return abfd->iovec->bflush (abfd);
93509525
KD
482}
483
717d4bd6
AM
484/*
485FUNCTION
486 bfd_stat
487
488SYNOPSIS
e416bd75 489 int bfd_stat (bfd *, struct stat *) ATTRIBUTE_WARN_UNUSED_RESULT;
717d4bd6
AM
490
491DESCRIPTION
492 Call fstat on ABFD's iostream. Return 0 on success, and a
493 negative value on failure.
494*/
495
93509525 496int
c58b9523 497bfd_stat (bfd *abfd, struct stat *statbuf)
93509525 498{
93509525
KD
499 int result;
500
5c4ce239
AM
501 while (abfd->my_archive != NULL
502 && !bfd_is_thin_archive (abfd->my_archive))
503 abfd = abfd->my_archive;
69fd4758 504
5c4ce239
AM
505 if (abfd->iovec == NULL)
506 {
507 bfd_set_error (bfd_error_invalid_operation);
508 return -1;
509 }
510
511 result = abfd->iovec->bstat (abfd, statbuf);
93509525
KD
512 if (result < 0)
513 bfd_set_error (bfd_error_system_call);
514 return result;
515}
516
717d4bd6
AM
517/*
518FUNCTION
519 bfd_seek
520
521SYNOPSIS
e416bd75 522 int bfd_seek (bfd *, file_ptr, int) ATTRIBUTE_WARN_UNUSED_RESULT;
717d4bd6
AM
523
524DESCRIPTION
525 Call fseek on ABFD's iostream. Return 0 on success, and a
526 negative value on failure.
527*/
93509525
KD
528
529int
c58b9523 530bfd_seek (bfd *abfd, file_ptr position, int direction)
93509525
KD
531{
532 int result;
5c4ce239 533 ufile_ptr offset = 0;
93509525 534
5c4ce239
AM
535 while (abfd->my_archive != NULL
536 && !bfd_is_thin_archive (abfd->my_archive))
93509525 537 {
5c4ce239
AM
538 offset += abfd->origin;
539 abfd = abfd->my_archive;
93509525 540 }
4d095f5b 541 offset += abfd->origin;
93509525 542
5c4ce239 543 if (abfd->iovec == NULL)
660722b0 544 {
5c4ce239
AM
545 bfd_set_error (bfd_error_invalid_operation);
546 return -1;
660722b0 547 }
93509525 548
5c4ce239
AM
549 /* For the time being, a BFD may not seek to it's end. The problem
550 is that we don't easily have a way to recognize the end of an
551 element in an archive. */
552 BFD_ASSERT (direction == SEEK_SET || direction == SEEK_CUR);
553
554 if (direction != SEEK_CUR)
555 position += offset;
69fd4758 556
f82ee0c8
AM
557 if (((direction == SEEK_CUR && position == 0)
558 || (direction == SEEK_SET && (ufile_ptr) position == abfd->where))
559 && abfd->last_io != bfd_io_force)
560 return 0;
561
562 abfd->last_io = bfd_io_seek;
563
5c4ce239 564 result = abfd->iovec->bseek (abfd, position, direction);
93509525
KD
565 if (result != 0)
566 {
93509525 567 /* An EINVAL error probably means that the file offset was
07d6d2b8 568 absurd. */
5c4ce239 569 if (errno == EINVAL)
93509525
KD
570 bfd_set_error (bfd_error_file_truncated);
571 else
5c4ce239 572 bfd_set_error (bfd_error_system_call);
93509525
KD
573 }
574 else
575 {
576 /* Adjust `where' field. */
5c4ce239 577 if (direction == SEEK_CUR)
93509525 578 abfd->where += position;
5c4ce239
AM
579 else
580 abfd->where = position;
93509525 581 }
5c4ce239 582
93509525
KD
583 return result;
584}
585
586/*
587FUNCTION
588 bfd_get_mtime
589
590SYNOPSIS
c58b9523 591 long bfd_get_mtime (bfd *abfd);
93509525
KD
592
593DESCRIPTION
594 Return the file modification time (as read from the file system, or
595 from the archive header for archive members).
596
597*/
598
599long
c58b9523 600bfd_get_mtime (bfd *abfd)
93509525 601{
93509525
KD
602 struct stat buf;
603
604 if (abfd->mtime_set)
605 return abfd->mtime;
606
5c4ce239 607 if (bfd_stat (abfd, &buf) != 0)
93509525
KD
608 return 0;
609
610 abfd->mtime = buf.st_mtime; /* Save value in case anyone wants it */
611 return buf.st_mtime;
612}
613
614/*
615FUNCTION
616 bfd_get_size
617
618SYNOPSIS
47fdcf63 619 ufile_ptr bfd_get_size (bfd *abfd);
93509525
KD
620
621DESCRIPTION
622 Return the file size (as read from file system) for the file
623 associated with BFD @var{abfd}.
624
625 The initial motivation for, and use of, this routine is not
626 so we can get the exact size of the object the BFD applies to, since
627 that might not be generally possible (archive members for example).
628 It would be ideal if someone could eventually modify
629 it so that such results were guaranteed.
630
631 Instead, we want to ask questions like "is this NNN byte sized
632 object I'm about to try read from file offset YYY reasonable?"
633 As as example of where we might do this, some object formats
634 use string tables for which the first <<sizeof (long)>> bytes of the
635 table contain the size of the table itself, including the size bytes.
636 If an application tries to read what it thinks is one of these
637 string tables, without some way to validate the size, and for
638 some reason the size is wrong (byte swapping error, wrong location
639 for the string table, etc.), the only clue is likely to be a read
640 error when it tries to read the table, or a "virtual memory
641 exhausted" error when it tries to allocate 15 bazillon bytes
642 of space for the 15 bazillon byte table it is about to read.
5c4491d3 643 This function at least allows us to answer the question, "is the
93509525 644 size reasonable?".
b03202e3
AM
645
646 A return value of zero indicates the file size is unknown.
93509525
KD
647*/
648
47fdcf63 649ufile_ptr
c58b9523 650bfd_get_size (bfd *abfd)
93509525 651{
b03202e3
AM
652 /* A size of 0 means we haven't yet called bfd_stat. A size of 1
653 means we have a cached value of 0, ie. unknown. */
654 if (abfd->size <= 1 || bfd_write_p (abfd))
655 {
656 struct stat buf;
93509525 657
b03202e3
AM
658 if (abfd->size == 1 && !bfd_write_p (abfd))
659 return 0;
93509525 660
b03202e3
AM
661 if (bfd_stat (abfd, &buf) != 0
662 || buf.st_size == 0
663 || buf.st_size - (ufile_ptr) buf.st_size != 0)
664 {
665 abfd->size = 1;
666 return 0;
667 }
668 abfd->size = buf.st_size;
669 }
670 return abfd->size;
93509525 671}
25b88f33 672
8e2f54bc
L
673/*
674FUNCTION
675 bfd_get_file_size
676
677SYNOPSIS
47fdcf63 678 ufile_ptr bfd_get_file_size (bfd *abfd);
8e2f54bc
L
679
680DESCRIPTION
681 Return the file size (as read from file system) for the file
682 associated with BFD @var{abfd}. It supports both normal files
683 and archive elements.
684
685*/
686
47fdcf63 687ufile_ptr
8e2f54bc
L
688bfd_get_file_size (bfd *abfd)
689{
b570b954 690 ufile_ptr file_size, archive_size = (ufile_ptr) -1;
3b37f0f1 691 unsigned int compression_p2 = 0;
b570b954 692
8e2f54bc
L
693 if (abfd->my_archive != NULL
694 && !bfd_is_thin_archive (abfd->my_archive))
b570b954
AM
695 {
696 struct areltdata *adata = (struct areltdata *) abfd->arelt_data;
c01de193
AM
697 if (adata != NULL)
698 {
699 archive_size = adata->parsed_size;
3b37f0f1
AM
700 /* If the archive is compressed, assume an element won't
701 expand more than eight times file size. */
c01de193
AM
702 if (adata->arch_header != NULL
703 && memcmp (((struct ar_hdr *) adata->arch_header)->ar_fmag,
704 "Z\012", 2) == 0)
3b37f0f1 705 compression_p2 = 3;
c01de193
AM
706 abfd = abfd->my_archive;
707 }
b570b954 708 }
8e2f54bc 709
3b37f0f1 710 file_size = bfd_get_size (abfd) << compression_p2;
b570b954
AM
711 if (archive_size < file_size)
712 return archive_size;
713 return file_size;
8e2f54bc 714}
25b88f33
PP
715
716/*
717FUNCTION
718 bfd_mmap
719
720SYNOPSIS
4810a2d9 721 void *bfd_mmap (bfd *abfd, void *addr, size_t len,
07d6d2b8 722 int prot, int flags, file_ptr offset,
4810a2d9 723 void **map_addr, size_t *map_len)
e416bd75 724 ATTRIBUTE_WARN_UNUSED_RESULT;
25b88f33
PP
725
726DESCRIPTION
727 Return mmap()ed region of the file, if possible and implemented.
07d6d2b8
AM
728 LEN and OFFSET do not need to be page aligned. The page aligned
729 address and length are written to MAP_ADDR and MAP_LEN.
25b88f33
PP
730
731*/
732
733void *
4810a2d9 734bfd_mmap (bfd *abfd, void *addr, size_t len,
4c95ab76 735 int prot, int flags, file_ptr offset,
4810a2d9 736 void **map_addr, size_t *map_len)
25b88f33 737{
5c4ce239
AM
738 while (abfd->my_archive != NULL
739 && !bfd_is_thin_archive (abfd->my_archive))
740 {
741 offset += abfd->origin;
742 abfd = abfd->my_archive;
743 }
4d095f5b 744 offset += abfd->origin;
25b88f33
PP
745
746 if (abfd->iovec == NULL)
5c4ce239
AM
747 {
748 bfd_set_error (bfd_error_invalid_operation);
2e384d4f 749 return MAP_FAILED;
5c4ce239 750 }
25b88f33 751
4c95ab76 752 return abfd->iovec->bmmap (abfd, addr, len, prot, flags, offset,
07d6d2b8 753 map_addr, map_len);
25b88f33 754}
65077aa8
TG
755
756/* Memory file I/O operations. */
757
758static file_ptr
759memory_bread (bfd *abfd, void *ptr, file_ptr size)
760{
761 struct bfd_in_memory *bim;
762 bfd_size_type get;
763
764 bim = (struct bfd_in_memory *) abfd->iostream;
765 get = size;
766 if (abfd->where + get > bim->size)
767 {
768 if (bim->size < (bfd_size_type) abfd->where)
07d6d2b8 769 get = 0;
65077aa8 770 else
07d6d2b8 771 get = bim->size - abfd->where;
65077aa8
TG
772 bfd_set_error (bfd_error_file_truncated);
773 }
774 memcpy (ptr, bim->buffer + abfd->where, (size_t) get);
775 return get;
776}
777
778static file_ptr
779memory_bwrite (bfd *abfd, const void *ptr, file_ptr size)
780{
781 struct bfd_in_memory *bim = (struct bfd_in_memory *) abfd->iostream;
782
783 if (abfd->where + size > bim->size)
784 {
785 bfd_size_type newsize, oldsize;
786
787 oldsize = (bim->size + 127) & ~(bfd_size_type) 127;
788 bim->size = abfd->where + size;
789 /* Round up to cut down on memory fragmentation */
790 newsize = (bim->size + 127) & ~(bfd_size_type) 127;
791 if (newsize > oldsize)
07d6d2b8
AM
792 {
793 bim->buffer = (bfd_byte *) bfd_realloc_or_free (bim->buffer, newsize);
794 if (bim->buffer == NULL)
795 {
796 bim->size = 0;
797 return 0;
798 }
799 if (newsize > bim->size)
800 memset (bim->buffer + bim->size, 0, newsize - bim->size);
801 }
65077aa8
TG
802 }
803 memcpy (bim->buffer + abfd->where, ptr, (size_t) size);
804 return size;
805}
806
807static file_ptr
808memory_btell (bfd *abfd)
809{
810 return abfd->where;
811}
812
813static int
814memory_bseek (bfd *abfd, file_ptr position, int direction)
815{
816 file_ptr nwhere;
817 struct bfd_in_memory *bim;
818
819 bim = (struct bfd_in_memory *) abfd->iostream;
820
821 if (direction == SEEK_SET)
822 nwhere = position;
823 else
824 nwhere = abfd->where + position;
825
826 if (nwhere < 0)
827 {
828 abfd->where = 0;
829 errno = EINVAL;
830 return -1;
831 }
832
833 if ((bfd_size_type)nwhere > bim->size)
834 {
835 if (abfd->direction == write_direction
07d6d2b8
AM
836 || abfd->direction == both_direction)
837 {
838 bfd_size_type newsize, oldsize;
839
840 oldsize = (bim->size + 127) & ~(bfd_size_type) 127;
841 bim->size = nwhere;
842 /* Round up to cut down on memory fragmentation */
843 newsize = (bim->size + 127) & ~(bfd_size_type) 127;
844 if (newsize > oldsize)
845 {
846 bim->buffer = (bfd_byte *) bfd_realloc_or_free (bim->buffer, newsize);
847 if (bim->buffer == NULL)
848 {
849 errno = EINVAL;
850 bim->size = 0;
851 return -1;
852 }
853 memset (bim->buffer + oldsize, 0, newsize - oldsize);
854 }
855 }
65077aa8 856 else
07d6d2b8
AM
857 {
858 abfd->where = bim->size;
859 errno = EINVAL;
860 bfd_set_error (bfd_error_file_truncated);
861 return -1;
862 }
65077aa8
TG
863 }
864 return 0;
865}
866
405bf443 867static int
65077aa8
TG
868memory_bclose (struct bfd *abfd)
869{
870 struct bfd_in_memory *bim = (struct bfd_in_memory *) abfd->iostream;
871
c9594989 872 free (bim->buffer);
65077aa8
TG
873 free (bim);
874 abfd->iostream = NULL;
875
405bf443 876 return 0;
65077aa8
TG
877}
878
879static int
880memory_bflush (bfd *abfd ATTRIBUTE_UNUSED)
881{
882 return 0;
883}
884
885static int
886memory_bstat (bfd *abfd, struct stat *statbuf)
887{
888 struct bfd_in_memory *bim = (struct bfd_in_memory *) abfd->iostream;
889
b5dee4ea 890 memset (statbuf, 0, sizeof (*statbuf));
65077aa8
TG
891 statbuf->st_size = bim->size;
892
893 return 0;
894}
895
896static void *
897memory_bmmap (bfd *abfd ATTRIBUTE_UNUSED, void *addr ATTRIBUTE_UNUSED,
4810a2d9 898 size_t len ATTRIBUTE_UNUSED, int prot ATTRIBUTE_UNUSED,
07d6d2b8
AM
899 int flags ATTRIBUTE_UNUSED, file_ptr offset ATTRIBUTE_UNUSED,
900 void **map_addr ATTRIBUTE_UNUSED,
4810a2d9 901 size_t *map_len ATTRIBUTE_UNUSED)
65077aa8
TG
902{
903 return (void *)-1;
904}
905
906const struct bfd_iovec _bfd_memory_iovec =
907{
908 &memory_bread, &memory_bwrite, &memory_btell, &memory_bseek,
909 &memory_bclose, &memory_bflush, &memory_bstat, &memory_bmmap
910};
6f567398
NC
911
912/*
913FUNCTION
914 bfd_get_current_time
915
916SYNOPSIS
917 time_t bfd_get_current_time (time_t now);
918
919DESCRIPTION
920 Returns the current time.
921
922 If the environment variable SOURCE_DATE_EPOCH is defined
923 then this is parsed and its value is returned. Otherwise
924 if the paramter NOW is non-zero, then that is returned.
925 Otherwise the result of the system call "time(NULL)" is
926 returned.
927*/
928
929time_t
930bfd_get_current_time (time_t now)
931{
932 char *source_date_epoch;
933 unsigned long long epoch;
934
935 /* FIXME: We could probably cache this lookup,
936 and the parsing of its value below. */
937 source_date_epoch = getenv ("SOURCE_DATE_EPOCH");
938
939 if (source_date_epoch == NULL)
940 {
941 if (now)
942 return now;
943 return time (NULL);
944 }
945
946 epoch = strtoull (source_date_epoch, NULL, 0);
947
948 /* If epoch == 0 then something is wrong with SOURCE_DATE_EPOCH,
949 but we do not have an easy way to report it. Since the presence
950 of the environment variable implies that the user wants
951 deterministic behaviour we just accept the 0 value. */
952
953 return (time_t) epoch;
954}