Coverage Report

Created: 2026-09-14 08:07

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