Coverage Report

Created: 2026-07-25 10:20

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
15.2M
{
52
15.2M
#if defined (HAVE_FTELLO64)
53
15.2M
  return ftello64 (file);
54
#elif defined (HAVE_FTELLO)
55
  return ftello (file);
56
#else
57
  return ftell (file);
58
#endif
59
15.2M
}
60
61
int
62
_bfd_real_fseek (FILE *file, file_ptr offset, int whence)
63
118M
{
64
118M
#if defined (HAVE_FSEEKO64)
65
118M
  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
118M
}
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
240k
{
78
240k
#if defined (HAVE_FILENO) && defined (F_GETFD)
79
240k
  if (file)
80
236k
    {
81
236k
      int fd = fileno (file);
82
236k
      int old = fcntl (fd, F_GETFD, 0);
83
236k
      if (old >= 0)
84
236k
  fcntl (fd, F_SETFD, old | FD_CLOEXEC);
85
236k
    }
86
240k
#endif
87
240k
  return file;
88
240k
}
89
90
FILE *
91
_bfd_real_fopen (const char *filename, const char *modes)
92
240k
{
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
240k
}
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
160M
{
328
160M
  file_ptr nread;
329
160M
  bfd *element_bfd = abfd;
330
160M
  ufile_ptr offset = 0;
331
332
180M
  while (abfd->my_archive != NULL
333
20.0M
   && abfd->my_archive->iovec == abfd->iovec
334
20.0M
   && !bfd_is_thin_archive (abfd->my_archive))
335
19.9M
    {
336
19.9M
      offset += abfd->origin;
337
19.9M
      abfd = abfd->my_archive;
338
19.9M
    }
339
160M
  offset += abfd->origin;
340
341
  /* If this is a non-thin archive element, don't read past the end of
342
     this element.  */
343
160M
  if (element_bfd->arelt_data != NULL
344
18.6M
      && element_bfd->my_archive != NULL
345
18.4M
      && element_bfd->my_archive->iovec == element_bfd->iovec
346
18.4M
      && !bfd_is_thin_archive (element_bfd->my_archive))
347
18.4M
    {
348
18.4M
      bfd_size_type maxbytes = arelt_size (element_bfd);
349
350
18.4M
      if (abfd->where < offset || abfd->where - offset >= maxbytes)
351
89.6k
  {
352
89.6k
    bfd_set_error (bfd_error_invalid_operation);
353
89.6k
    return -1;
354
89.6k
  }
355
18.3M
      if (abfd->where - offset + size > maxbytes)
356
904k
  size = maxbytes - (abfd->where - offset);
357
18.3M
    }
358
359
160M
  if (abfd->iovec == NULL)
360
0
    {
361
0
      bfd_set_error (bfd_error_invalid_operation);
362
0
      return -1;
363
0
    }
364
365
160M
  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
160M
  abfd->last_io = bfd_io_read;
372
373
160M
  nread = abfd->iovec->bread (abfd, ptr, size);
374
160M
  if (nread != -1)
375
160M
    abfd->where += nread;
376
377
160M
  return nread;
378
160M
}
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
55.5M
{
396
55.5M
  file_ptr nwrote;
397
398
55.5M
  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
55.5M
  if (abfd->iovec == NULL)
404
0
    {
405
0
      bfd_set_error (bfd_error_invalid_operation);
406
0
      return -1;
407
0
    }
408
409
55.5M
  if (abfd->last_io == bfd_io_read)
410
17
    {
411
17
      abfd->last_io = bfd_io_force;
412
17
      if (bfd_seek (abfd, 0, SEEK_CUR) != 0)
413
0
  return -1;
414
17
    }
415
55.5M
  abfd->last_io = bfd_io_write;
416
417
55.5M
  nwrote = abfd->iovec->bwrite (abfd, ptr, size);
418
55.5M
  if (nwrote != -1)
419
55.5M
    abfd->where += nwrote;
420
55.5M
  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
55.5M
  return nwrote;
428
55.5M
}
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
15.2M
{
444
15.2M
  ufile_ptr offset = 0;
445
15.2M
  file_ptr ptr;
446
447
15.6M
  while (abfd->my_archive != NULL
448
373k
   && abfd->my_archive->iovec == abfd->iovec
449
373k
   && !bfd_is_thin_archive (abfd->my_archive))
450
373k
    {
451
373k
      offset += abfd->origin;
452
373k
      abfd = abfd->my_archive;
453
373k
    }
454
15.2M
  offset += abfd->origin;
455
456
15.2M
  if (abfd->iovec == NULL)
457
0
    return 0;
458
459
15.2M
  ptr = abfd->iovec->btell (abfd);
460
15.2M
  abfd->where = ptr;
461
15.2M
  return ptr - offset;
462
15.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
212
{
478
212
  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
212
  if (abfd->iovec == NULL)
484
0
    return 0;
485
486
212
  return abfd->iovec->bflush (abfd);
487
212
}
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
3.00M
{
504
3.00M
  int result;
505
506
3.01M
  while (abfd->my_archive != NULL
507
13.8k
   && abfd->my_archive->iovec == abfd->iovec
508
13.8k
   && !bfd_is_thin_archive (abfd->my_archive))
509
13.7k
    abfd = abfd->my_archive;
510
511
3.00M
  if (abfd->iovec == NULL)
512
0
    {
513
0
      bfd_set_error (bfd_error_invalid_operation);
514
0
      return -1;
515
0
    }
516
517
3.00M
  result = abfd->iovec->bstat (abfd, statbuf);
518
3.00M
  if (result < 0)
519
0
    bfd_set_error (bfd_error_system_call);
520
3.00M
  return result;
521
3.00M
}
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
164M
{
538
164M
  int result;
539
164M
  ufile_ptr offset = 0;
540
541
185M
  while (abfd->my_archive != NULL
542
21.1M
   && abfd->my_archive->iovec == abfd->iovec
543
21.1M
   && !bfd_is_thin_archive (abfd->my_archive))
544
21.0M
    {
545
21.0M
      offset += abfd->origin;
546
21.0M
      abfd = abfd->my_archive;
547
21.0M
    }
548
164M
  offset += abfd->origin;
549
550
164M
  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
164M
  BFD_ASSERT (direction == SEEK_SET || direction == SEEK_CUR);
560
561
164M
  if (direction != SEEK_CUR)
562
139M
    position += offset;
563
564
164M
  if (((direction == SEEK_CUR && position == 0)
565
164M
       || (direction == SEEK_SET && (ufile_ptr) position == abfd->where))
566
45.8M
      && abfd->last_io != bfd_io_force)
567
45.8M
    return 0;
568
569
118M
  abfd->last_io = bfd_io_seek;
570
571
118M
  result = abfd->iovec->bseek (abfd, position, direction);
572
118M
  if (result != 0)
573
105k
    {
574
      /* An EINVAL error probably means that the file offset was
575
   absurd.  */
576
105k
      if (errno == EINVAL)
577
105k
  bfd_set_error (bfd_error_file_truncated);
578
0
      else
579
0
  bfd_set_error (bfd_error_system_call);
580
105k
    }
581
118M
  else
582
118M
    {
583
      /* Adjust `where' field.  */
584
118M
      if (direction == SEEK_CUR)
585
24.4M
  abfd->where += position;
586
93.8M
      else
587
93.8M
  abfd->where = position;
588
118M
    }
589
590
118M
  return result;
591
164M
}
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
17.1M
{
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
17.1M
  if (abfd->size <= 1 || bfd_write_p (abfd))
662
2.81M
    {
663
2.81M
      struct stat buf;
664
665
2.81M
      if (abfd->size == 1 && !bfd_write_p (abfd))
666
5.88k
  return 0;
667
668
2.80M
      if (bfd_stat (abfd, &buf) != 0
669
2.80M
    || buf.st_size == 0
670
2.80M
    || buf.st_size - (ufile_ptr) buf.st_size != 0)
671
2.15k
  {
672
2.15k
    abfd->size = 1;
673
2.15k
    return 0;
674
2.15k
  }
675
2.80M
      abfd->size = buf.st_size;
676
2.80M
    }
677
17.0M
  return abfd->size;
678
17.1M
}
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
17.0M
{
697
17.0M
  ufile_ptr file_size, archive_size = (ufile_ptr) -1;
698
17.0M
  unsigned int compression_p2 = 0;
699
700
17.0M
  if (abfd->my_archive != NULL
701
2.89M
      && !bfd_is_thin_archive (abfd->my_archive))
702
2.89M
    {
703
2.89M
      struct areltdata *adata = (struct areltdata *) abfd->arelt_data;
704
2.89M
      if (adata != NULL)
705
2.89M
  {
706
2.89M
    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.89M
    if (adata->arch_header != NULL
710
2.89M
        && memcmp (((struct ar_hdr *) adata->arch_header)->ar_fmag,
711
2.89M
       "Z\012", 2) == 0)
712
478
      compression_p2 = 3;
713
2.89M
  }
714
2.89M
      abfd = abfd->my_archive;
715
2.89M
    }
716
717
17.0M
  file_size = bfd_get_size (abfd) << compression_p2;
718
17.0M
  if (archive_size < file_size)
719
801k
    return archive_size;
720
16.2M
  return file_size;
721
17.0M
}
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
3.64k
{
770
3.64k
  struct bfd_in_memory *bim;
771
3.64k
  bfd_size_type get;
772
773
3.64k
  bim = (struct bfd_in_memory *) abfd->iostream;
774
3.64k
  get = size;
775
3.64k
  if (abfd->where + get > bim->size)
776
281
    {
777
281
      if (bim->size < (bfd_size_type) abfd->where)
778
0
  get = 0;
779
281
      else
780
281
  get = bim->size - abfd->where;
781
281
      bfd_set_error (bfd_error_file_truncated);
782
281
    }
783
3.64k
  memcpy (ptr, bim->buffer + abfd->where, (size_t) get);
784
3.64k
  return get;
785
3.64k
}
786
787
static file_ptr
788
memory_bwrite (bfd *abfd, const void *ptr, file_ptr size)
789
434
{
790
434
  struct bfd_in_memory *bim = (struct bfd_in_memory *) abfd->iostream;
791
792
434
  if (abfd->where + size > bim->size)
793
434
    {
794
434
      bfd_size_type newsize, oldsize;
795
796
434
      oldsize = (bim->size + 127) & ~(bfd_size_type) 127;
797
434
      bim->size = abfd->where + size;
798
      /* Round up to cut down on memory fragmentation */
799
434
      newsize = (bim->size + 127) & ~(bfd_size_type) 127;
800
434
      if (newsize > oldsize)
801
434
  {
802
434
    bim->buffer = (bfd_byte *) bfd_realloc_or_free (bim->buffer, newsize);
803
434
    if (bim->buffer == NULL)
804
0
      {
805
0
        bim->size = 0;
806
0
        return 0;
807
0
      }
808
434
    if (newsize > bim->size)
809
101
      memset (bim->buffer + bim->size, 0, newsize - bim->size);
810
434
  }
811
434
    }
812
434
  memcpy (bim->buffer + abfd->where, ptr, (size_t) size);
813
434
  return size;
814
434
}
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
3.59k
{
825
3.59k
  file_ptr nwhere;
826
3.59k
  struct bfd_in_memory *bim;
827
828
3.59k
  bim = (struct bfd_in_memory *) abfd->iostream;
829
830
3.59k
  if (direction == SEEK_SET)
831
3.59k
    nwhere = position;
832
0
  else
833
0
    nwhere = abfd->where + position;
834
835
3.59k
  if (nwhere < 0)
836
0
    {
837
0
      abfd->where = 0;
838
0
      errno = EINVAL;
839
0
      return -1;
840
0
    }
841
842
3.59k
  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
3.59k
  return 0;
874
3.59k
}
875
876
static int
877
memory_bclose (struct bfd *abfd)
878
4.96k
{
879
4.96k
  struct bfd_in_memory *bim = (struct bfd_in_memory *) abfd->iostream;
880
881
4.96k
  free (bim->buffer);
882
4.96k
  free (bim);
883
4.96k
  abfd->iostream = NULL;
884
885
4.96k
  return 0;
886
4.96k
}
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
25
{
897
25
  struct bfd_in_memory *bim = (struct bfd_in_memory *) abfd->iostream;
898
899
25
  memset (statbuf, 0, sizeof (*statbuf));
900
25
  statbuf->st_size = bim->size;
901
902
25
  return 0;
903
25
}
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.69k
{
941
1.69k
  char *source_date_epoch;
942
1.69k
  unsigned long long epoch;
943
944
  /* FIXME: We could probably cache this lookup,
945
     and the parsing of its value below.  */
946
1.69k
  source_date_epoch = getenv ("SOURCE_DATE_EPOCH");
947
948
1.69k
  if (source_date_epoch == NULL)
949
1.69k
    {
950
1.69k
      if (now)
951
600
  return now;
952
1.09k
      return time (NULL);
953
1.69k
    }
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.69k
}