Coverage Report

Created: 2026-05-11 07:54

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