Coverage Report

Created: 2025-07-08 11:15

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