Coverage Report

Created: 2026-04-04 08:16

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