Coverage Report

Created: 2026-03-10 08:46

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