]> git.ipfire.org Git - thirdparty/binutils-gdb.git/blame - bfd/bfdio.c
bfd: Use size_t in the BFD mmap interface
[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
NC
120 /* PR 25713: Handle extra long path names possibly containing '..' and '.'. */
121 wchar_t ** lpFilePart = {NULL};
122 const wchar_t prefix[] = L"\\\\?\\";
ba0eb22c 123 const size_t partPathLen = strlen (filename) + 1;
68e80d96 124#ifdef __MINGW32__
9d099144
AM
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 ();
68e80d96
CC
130#else
131 const unsigned int cp = CP_UTF8;
132#endif
17d60030 133
cb7da2a6 134 /* Converting the partial path from ascii to unicode.
ba0eb22c
NC
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. */
68e80d96 137 size_t partPathWSize = MultiByteToWideChar (cp, 0, filename, -1, NULL, 0);
ba0eb22c
NC
138 wchar_t * partPath = calloc (partPathWSize, sizeof(wchar_t));
139 size_t ix;
17d60030 140
68e80d96 141 MultiByteToWideChar (cp, 0, filename, -1, partPath, partPathWSize);
17d60030 142
cb7da2a6 143 /* Convert any UNIX style path separators into the DOS i.e. backslash separator. */
cb7da2a6
TS
144 for (ix = 0; ix < partPathLen; ix++)
145 if (IS_UNIX_DIR_SEPARATOR(filename[ix]))
146 partPath[ix] = '\\';
0b8448af 147
cb7da2a6 148 /* Getting the full path from the provided partial path.
ba0eb22c
NC
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));
cb7da2a6
TS
153
154 wcscpy (fullPath, prefix);
ba0eb22c
NC
155
156 int prefixLen = sizeof(prefix) / sizeof(wchar_t);
a8cf07d3
H
157
158 /* Do not add a prefix to the null device. */
159 if (stricmp (filename, "nul") == 0)
160 prefixLen = 1;
161
ba0eb22c
NC
162 wchar_t * fullPathOffset = fullPath + prefixLen - 1;
163
cb7da2a6
TS
164 GetFullPathNameW (partPath, fullPathWSize, fullPathOffset, lpFilePart);
165 free (partPath);
166
167 /* It is non-standard for modes to exceed 16 characters. */
5f3fc928 168 wchar_t modesW[16];
ba0eb22c 169
68e80d96 170 MultiByteToWideChar (cp, 0, modes, -1, modesW, sizeof(modesW));
cb7da2a6 171
ba0eb22c 172 FILE * file = _wfopen (fullPath, modesW);
cb7da2a6
TS
173 free (fullPath);
174
175 return close_on_exec (file);
0b8448af
NC
176
177#elif defined (HAVE_FOPEN64)
428b207a 178 return close_on_exec (fopen64 (filename, modes));
0b8448af 179
cb7da2a6 180#else
0b8448af 181 return close_on_exec (fopen (filename, modes));
cb7da2a6 182#endif
2e6f4fae
DJ
183}
184
40838a72
AC
185/*
186INTERNAL_DEFINITION
187 struct bfd_iovec
93509525 188
40838a72 189DESCRIPTION
93509525 190
40838a72
AC
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,
07d6d2b8 206. file_ptr nbytes);
40838a72
AC
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.
07d6d2b8 211. Otherwise, a value of -1 is returned (and <<bfd_error>> is set). *}
40838a72 212. int (*bseek) (struct bfd *abfd, file_ptr offset, int whence);
405bf443 213. int (*bclose) (struct bfd *abfd);
40838a72
AC
214. int (*bflush) (struct bfd *abfd);
215. int (*bstat) (struct bfd *abfd, struct stat *sb);
4c95ab76
TG
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. *}
4810a2d9 222. void *(*bmmap) (struct bfd *abfd, void *addr, size_t len,
07d6d2b8 223. int prot, int flags, file_ptr offset,
4810a2d9 224. void **map_addr, size_t *map_len);
40838a72 225.};
93509525 226
65077aa8 227.extern const struct bfd_iovec _bfd_memory_iovec;
717d4bd6 228.
40838a72 229*/
93509525 230
93509525 231
717d4bd6
AM
232/*
233FUNCTION
226f9f4f 234 bfd_read
717d4bd6
AM
235
236SYNOPSIS
e416bd75
AM
237 bfd_size_type bfd_read (void *, bfd_size_type, bfd *)
238 ATTRIBUTE_WARN_UNUSED_RESULT;
717d4bd6
AM
239
240DESCRIPTION
241 Attempt to read SIZE bytes from ABFD's iostream to PTR.
242 Return the amount read.
243*/
93509525
KD
244
245bfd_size_type
226f9f4f 246bfd_read (void *ptr, bfd_size_type size, bfd *abfd)
93509525 247{
5c4ce239
AM
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 }
4d095f5b 258 offset += abfd->origin;
93509525 259
c17eb63b 260 /* If this is a non-thin archive element, don't read past the end of
1fb41da4 261 this element. */
c17eb63b
L
262 if (element_bfd->arelt_data != NULL
263 && element_bfd->my_archive != NULL
264 && !bfd_is_thin_archive (element_bfd->my_archive))
1fb41da4 265 {
5c4ce239 266 bfd_size_type maxbytes = arelt_size (element_bfd);
f1bb16f8 267
5c4ce239 268 if (abfd->where < offset || abfd->where - offset >= maxbytes)
07d6d2b8 269 {
5c4ce239
AM
270 bfd_set_error (bfd_error_invalid_operation);
271 return -1;
07d6d2b8 272 }
5c4ce239
AM
273 if (abfd->where - offset + size > maxbytes)
274 size = maxbytes - (abfd->where - offset);
1fb41da4
AM
275 }
276
5c4ce239
AM
277 if (abfd->iovec == NULL)
278 {
279 bfd_set_error (bfd_error_invalid_operation);
280 return -1;
281 }
282
f82ee0c8
AM
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
5c4ce239
AM
291 nread = abfd->iovec->bread (abfd, ptr, size);
292 if (nread != -1)
93509525
KD
293 abfd->where += nread;
294
93509525
KD
295 return nread;
296}
297
717d4bd6
AM
298/*
299FUNCTION
226f9f4f 300 bfd_write
717d4bd6
AM
301
302SYNOPSIS
e416bd75
AM
303 bfd_size_type bfd_write (const void *, bfd_size_type, bfd *)
304 ATTRIBUTE_WARN_UNUSED_RESULT;
717d4bd6
AM
305
306DESCRIPTION
307 Attempt to write SIZE bytes to ABFD's iostream from PTR.
308 Return the amount written.
309*/
310
93509525 311bfd_size_type
226f9f4f 312bfd_write (const void *ptr, bfd_size_type size, bfd *abfd)
93509525 313{
5c4ce239 314 file_ptr nwrote;
93509525 315
5c4ce239
AM
316 while (abfd->my_archive != NULL
317 && !bfd_is_thin_archive (abfd->my_archive))
318 abfd = abfd->my_archive;
69fd4758 319
5c4ce239
AM
320 if (abfd->iovec == NULL)
321 {
322 bfd_set_error (bfd_error_invalid_operation);
323 return -1;
324 }
325
f82ee0c8
AM
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
5c4ce239
AM
334 nwrote = abfd->iovec->bwrite (abfd, ptr, size);
335 if (nwrote != -1)
93509525 336 abfd->where += nwrote;
5c4ce239 337 if ((bfd_size_type) nwrote != size)
93509525
KD
338 {
339#ifdef ENOSPC
340 errno = ENOSPC;
341#endif
342 bfd_set_error (bfd_error_system_call);
343 }
344 return nwrote;
345}
346
717d4bd6
AM
347/*
348FUNCTION
349 bfd_tell
350
351SYNOPSIS
e416bd75 352 file_ptr bfd_tell (bfd *) ATTRIBUTE_WARN_UNUSED_RESULT;
717d4bd6
AM
353
354DESCRIPTION
355 Return ABFD's iostream file position.
356*/
357
7c192733 358file_ptr
c58b9523 359bfd_tell (bfd *abfd)
93509525 360{
5c4ce239 361 ufile_ptr offset = 0;
93509525
KD
362 file_ptr ptr;
363
5c4ce239
AM
364 while (abfd->my_archive != NULL
365 && !bfd_is_thin_archive (abfd->my_archive))
69fd4758 366 {
5c4ce239
AM
367 offset += abfd->origin;
368 abfd = abfd->my_archive;
69fd4758 369 }
4d095f5b 370 offset += abfd->origin;
93509525 371
5c4ce239
AM
372 if (abfd->iovec == NULL)
373 return 0;
374
375 ptr = abfd->iovec->btell (abfd);
93509525 376 abfd->where = ptr;
5c4ce239 377 return ptr - offset;
93509525
KD
378}
379
717d4bd6
AM
380/*
381FUNCTION
382 bfd_flush
383
384SYNOPSIS
385 int bfd_flush (bfd *);
386
387DESCRIPTION
388 Flush ABFD's iostream pending IO.
389*/
390
93509525 391int
c58b9523 392bfd_flush (bfd *abfd)
93509525 393{
5c4ce239
AM
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);
93509525
KD
402}
403
717d4bd6
AM
404/*
405FUNCTION
406 bfd_stat
407
408SYNOPSIS
e416bd75 409 int bfd_stat (bfd *, struct stat *) ATTRIBUTE_WARN_UNUSED_RESULT;
717d4bd6
AM
410
411DESCRIPTION
412 Call fstat on ABFD's iostream. Return 0 on success, and a
413 negative value on failure.
414*/
415
93509525 416int
c58b9523 417bfd_stat (bfd *abfd, struct stat *statbuf)
93509525 418{
93509525
KD
419 int result;
420
5c4ce239
AM
421 while (abfd->my_archive != NULL
422 && !bfd_is_thin_archive (abfd->my_archive))
423 abfd = abfd->my_archive;
69fd4758 424
5c4ce239
AM
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);
93509525
KD
432 if (result < 0)
433 bfd_set_error (bfd_error_system_call);
434 return result;
435}
436
717d4bd6
AM
437/*
438FUNCTION
439 bfd_seek
440
441SYNOPSIS
e416bd75 442 int bfd_seek (bfd *, file_ptr, int) ATTRIBUTE_WARN_UNUSED_RESULT;
717d4bd6
AM
443
444DESCRIPTION
445 Call fseek on ABFD's iostream. Return 0 on success, and a
446 negative value on failure.
447*/
93509525
KD
448
449int
c58b9523 450bfd_seek (bfd *abfd, file_ptr position, int direction)
93509525
KD
451{
452 int result;
5c4ce239 453 ufile_ptr offset = 0;
93509525 454
5c4ce239
AM
455 while (abfd->my_archive != NULL
456 && !bfd_is_thin_archive (abfd->my_archive))
93509525 457 {
5c4ce239
AM
458 offset += abfd->origin;
459 abfd = abfd->my_archive;
93509525 460 }
4d095f5b 461 offset += abfd->origin;
93509525 462
5c4ce239 463 if (abfd->iovec == NULL)
660722b0 464 {
5c4ce239
AM
465 bfd_set_error (bfd_error_invalid_operation);
466 return -1;
660722b0 467 }
93509525 468
5c4ce239
AM
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;
69fd4758 476
f82ee0c8
AM
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
5c4ce239 484 result = abfd->iovec->bseek (abfd, position, direction);
93509525
KD
485 if (result != 0)
486 {
93509525 487 /* An EINVAL error probably means that the file offset was
07d6d2b8 488 absurd. */
5c4ce239 489 if (errno == EINVAL)
93509525
KD
490 bfd_set_error (bfd_error_file_truncated);
491 else
5c4ce239 492 bfd_set_error (bfd_error_system_call);
93509525
KD
493 }
494 else
495 {
496 /* Adjust `where' field. */
5c4ce239 497 if (direction == SEEK_CUR)
93509525 498 abfd->where += position;
5c4ce239
AM
499 else
500 abfd->where = position;
93509525 501 }
5c4ce239 502
93509525
KD
503 return result;
504}
505
506/*
507FUNCTION
508 bfd_get_mtime
509
510SYNOPSIS
c58b9523 511 long bfd_get_mtime (bfd *abfd);
93509525
KD
512
513DESCRIPTION
514 Return the file modification time (as read from the file system, or
515 from the archive header for archive members).
516
517*/
518
519long
c58b9523 520bfd_get_mtime (bfd *abfd)
93509525 521{
93509525
KD
522 struct stat buf;
523
524 if (abfd->mtime_set)
525 return abfd->mtime;
526
5c4ce239 527 if (bfd_stat (abfd, &buf) != 0)
93509525
KD
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/*
535FUNCTION
536 bfd_get_size
537
538SYNOPSIS
47fdcf63 539 ufile_ptr bfd_get_size (bfd *abfd);
93509525
KD
540
541DESCRIPTION
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.
5c4491d3 563 This function at least allows us to answer the question, "is the
93509525 564 size reasonable?".
b03202e3
AM
565
566 A return value of zero indicates the file size is unknown.
93509525
KD
567*/
568
47fdcf63 569ufile_ptr
c58b9523 570bfd_get_size (bfd *abfd)
93509525 571{
b03202e3
AM
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;
93509525 577
b03202e3
AM
578 if (abfd->size == 1 && !bfd_write_p (abfd))
579 return 0;
93509525 580
b03202e3
AM
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;
93509525 591}
25b88f33 592
8e2f54bc
L
593/*
594FUNCTION
595 bfd_get_file_size
596
597SYNOPSIS
47fdcf63 598 ufile_ptr bfd_get_file_size (bfd *abfd);
8e2f54bc
L
599
600DESCRIPTION
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
47fdcf63 607ufile_ptr
8e2f54bc
L
608bfd_get_file_size (bfd *abfd)
609{
b570b954 610 ufile_ptr file_size, archive_size = (ufile_ptr) -1;
3b37f0f1 611 unsigned int compression_p2 = 0;
b570b954 612
8e2f54bc
L
613 if (abfd->my_archive != NULL
614 && !bfd_is_thin_archive (abfd->my_archive))
b570b954
AM
615 {
616 struct areltdata *adata = (struct areltdata *) abfd->arelt_data;
c01de193
AM
617 if (adata != NULL)
618 {
619 archive_size = adata->parsed_size;
3b37f0f1
AM
620 /* If the archive is compressed, assume an element won't
621 expand more than eight times file size. */
c01de193
AM
622 if (adata->arch_header != NULL
623 && memcmp (((struct ar_hdr *) adata->arch_header)->ar_fmag,
624 "Z\012", 2) == 0)
3b37f0f1 625 compression_p2 = 3;
c01de193
AM
626 abfd = abfd->my_archive;
627 }
b570b954 628 }
8e2f54bc 629
3b37f0f1 630 file_size = bfd_get_size (abfd) << compression_p2;
b570b954
AM
631 if (archive_size < file_size)
632 return archive_size;
633 return file_size;
8e2f54bc 634}
25b88f33
PP
635
636/*
637FUNCTION
638 bfd_mmap
639
640SYNOPSIS
4810a2d9 641 void *bfd_mmap (bfd *abfd, void *addr, size_t len,
07d6d2b8 642 int prot, int flags, file_ptr offset,
4810a2d9 643 void **map_addr, size_t *map_len)
e416bd75 644 ATTRIBUTE_WARN_UNUSED_RESULT;
25b88f33
PP
645
646DESCRIPTION
647 Return mmap()ed region of the file, if possible and implemented.
07d6d2b8
AM
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.
25b88f33
PP
650
651*/
652
653void *
4810a2d9 654bfd_mmap (bfd *abfd, void *addr, size_t len,
4c95ab76 655 int prot, int flags, file_ptr offset,
4810a2d9 656 void **map_addr, size_t *map_len)
25b88f33 657{
5c4ce239
AM
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 }
4d095f5b 664 offset += abfd->origin;
25b88f33
PP
665
666 if (abfd->iovec == NULL)
5c4ce239
AM
667 {
668 bfd_set_error (bfd_error_invalid_operation);
2e384d4f 669 return MAP_FAILED;
5c4ce239 670 }
25b88f33 671
4c95ab76 672 return abfd->iovec->bmmap (abfd, addr, len, prot, flags, offset,
07d6d2b8 673 map_addr, map_len);
25b88f33 674}
65077aa8
TG
675
676/* Memory file I/O operations. */
677
678static file_ptr
679memory_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)
07d6d2b8 689 get = 0;
65077aa8 690 else
07d6d2b8 691 get = bim->size - abfd->where;
65077aa8
TG
692 bfd_set_error (bfd_error_file_truncated);
693 }
694 memcpy (ptr, bim->buffer + abfd->where, (size_t) get);
695 return get;
696}
697
698static file_ptr
699memory_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)
07d6d2b8
AM
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 }
65077aa8
TG
722 }
723 memcpy (bim->buffer + abfd->where, ptr, (size_t) size);
724 return size;
725}
726
727static file_ptr
728memory_btell (bfd *abfd)
729{
730 return abfd->where;
731}
732
733static int
734memory_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
07d6d2b8
AM
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 }
65077aa8 776 else
07d6d2b8
AM
777 {
778 abfd->where = bim->size;
779 errno = EINVAL;
780 bfd_set_error (bfd_error_file_truncated);
781 return -1;
782 }
65077aa8
TG
783 }
784 return 0;
785}
786
405bf443 787static int
65077aa8
TG
788memory_bclose (struct bfd *abfd)
789{
790 struct bfd_in_memory *bim = (struct bfd_in_memory *) abfd->iostream;
791
c9594989 792 free (bim->buffer);
65077aa8
TG
793 free (bim);
794 abfd->iostream = NULL;
795
405bf443 796 return 0;
65077aa8
TG
797}
798
799static int
800memory_bflush (bfd *abfd ATTRIBUTE_UNUSED)
801{
802 return 0;
803}
804
805static int
806memory_bstat (bfd *abfd, struct stat *statbuf)
807{
808 struct bfd_in_memory *bim = (struct bfd_in_memory *) abfd->iostream;
809
b5dee4ea 810 memset (statbuf, 0, sizeof (*statbuf));
65077aa8
TG
811 statbuf->st_size = bim->size;
812
813 return 0;
814}
815
816static void *
817memory_bmmap (bfd *abfd ATTRIBUTE_UNUSED, void *addr ATTRIBUTE_UNUSED,
4810a2d9 818 size_t len ATTRIBUTE_UNUSED, int prot ATTRIBUTE_UNUSED,
07d6d2b8
AM
819 int flags ATTRIBUTE_UNUSED, file_ptr offset ATTRIBUTE_UNUSED,
820 void **map_addr ATTRIBUTE_UNUSED,
4810a2d9 821 size_t *map_len ATTRIBUTE_UNUSED)
65077aa8
TG
822{
823 return (void *)-1;
824}
825
826const 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};
6f567398
NC
831
832/*
833FUNCTION
834 bfd_get_current_time
835
836SYNOPSIS
837 time_t bfd_get_current_time (time_t now);
838
839DESCRIPTION
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
849time_t
850bfd_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}