Coverage Report

Created: 2025-06-24 06:45

/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
9.86M
{
51
9.86M
#if defined (HAVE_FTELLO64)
52
9.86M
  return ftello64 (file);
53
#elif defined (HAVE_FTELLO)
54
  return ftello (file);
55
#else
56
  return ftell (file);
57
#endif
58
9.86M
}
59
60
int
61
_bfd_real_fseek (FILE *file, file_ptr offset, int whence)
62
992M
{
63
992M
#if defined (HAVE_FSEEKO64)
64
992M
  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
992M
}
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
171k
{
77
171k
#if defined (HAVE_FILENO) && defined (F_GETFD)
78
171k
  if (file)
79
170k
    {
80
170k
      int fd = fileno (file);
81
170k
      int old = fcntl (fd, F_GETFD, 0);
82
170k
      if (old >= 0)
83
170k
  fcntl (fd, F_SETFD, old | FD_CLOEXEC);
84
170k
    }
85
171k
#endif
86
171k
  return file;
87
171k
}
88
89
FILE *
90
_bfd_real_fopen (const char *filename, const char *modes)
91
171k
{
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
171k
}
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
1.10G
{
326
1.10G
  file_ptr nread;
327
1.10G
  bfd *element_bfd = abfd;
328
1.10G
  ufile_ptr offset = 0;
329
330
2.07G
  while (abfd->my_archive != NULL
331
2.07G
   && !bfd_is_thin_archive (abfd->my_archive))
332
970M
    {
333
970M
      offset += abfd->origin;
334
970M
      abfd = abfd->my_archive;
335
970M
    }
336
1.10G
  offset += abfd->origin;
337
338
  /* If this is a non-thin archive element, don't read past the end of
339
     this element.  */
340
1.10G
  if (element_bfd->arelt_data != NULL
341
1.10G
      && element_bfd->my_archive != NULL
342
1.10G
      && !bfd_is_thin_archive (element_bfd->my_archive))
343
970M
    {
344
970M
      bfd_size_type maxbytes = arelt_size (element_bfd);
345
346
970M
      if (abfd->where < offset || abfd->where - offset >= maxbytes)
347
1.63M
  {
348
1.63M
    bfd_set_error (bfd_error_invalid_operation);
349
1.63M
    return -1;
350
1.63M
  }
351
968M
      if (abfd->where - offset + size > maxbytes)
352
8.02M
  size = maxbytes - (abfd->where - offset);
353
968M
    }
354
355
1.10G
  if (abfd->iovec == NULL)
356
0
    {
357
0
      bfd_set_error (bfd_error_invalid_operation);
358
0
      return -1;
359
0
    }
360
361
1.10G
  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
1.10G
  abfd->last_io = bfd_io_read;
368
369
1.10G
  nread = abfd->iovec->bread (abfd, ptr, size);
370
1.10G
  if (nread != -1)
371
1.10G
    abfd->where += nread;
372
373
1.10G
  return nread;
374
1.10G
}
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
87.9k
{
392
87.9k
  file_ptr nwrote;
393
394
87.9k
  while (abfd->my_archive != NULL
395
87.9k
   && !bfd_is_thin_archive (abfd->my_archive))
396
0
    abfd = abfd->my_archive;
397
398
87.9k
  if (abfd->iovec == NULL)
399
0
    {
400
0
      bfd_set_error (bfd_error_invalid_operation);
401
0
      return -1;
402
0
    }
403
404
87.9k
  if (abfd->last_io == bfd_io_read)
405
1
    {
406
1
      abfd->last_io = bfd_io_force;
407
1
      if (bfd_seek (abfd, 0, SEEK_CUR) != 0)
408
0
  return -1;
409
1
    }
410
87.9k
  abfd->last_io = bfd_io_write;
411
412
87.9k
  nwrote = abfd->iovec->bwrite (abfd, ptr, size);
413
87.9k
  if (nwrote != -1)
414
87.9k
    abfd->where += nwrote;
415
87.9k
  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
87.9k
  return nwrote;
423
87.9k
}
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
9.86M
{
439
9.86M
  ufile_ptr offset = 0;
440
9.86M
  file_ptr ptr;
441
442
12.2M
  while (abfd->my_archive != NULL
443
12.2M
   && !bfd_is_thin_archive (abfd->my_archive))
444
2.36M
    {
445
2.36M
      offset += abfd->origin;
446
2.36M
      abfd = abfd->my_archive;
447
2.36M
    }
448
9.86M
  offset += abfd->origin;
449
450
9.86M
  if (abfd->iovec == NULL)
451
0
    return 0;
452
453
9.86M
  ptr = abfd->iovec->btell (abfd);
454
9.86M
  abfd->where = ptr;
455
9.86M
  return ptr - offset;
456
9.86M
}
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
3.09k
{
472
3.09k
  while (abfd->my_archive != NULL
473
3.09k
   && !bfd_is_thin_archive (abfd->my_archive))
474
0
    abfd = abfd->my_archive;
475
476
3.09k
  if (abfd->iovec == NULL)
477
0
    return 0;
478
479
3.09k
  return abfd->iovec->bflush (abfd);
480
3.09k
}
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
59.1M
{
497
59.1M
  int result;
498
499
65.7M
  while (abfd->my_archive != NULL
500
65.7M
   && !bfd_is_thin_archive (abfd->my_archive))
501
6.57M
    abfd = abfd->my_archive;
502
503
59.1M
  if (abfd->iovec == NULL)
504
0
    {
505
0
      bfd_set_error (bfd_error_invalid_operation);
506
0
      return -1;
507
0
    }
508
509
59.1M
  result = abfd->iovec->bstat (abfd, statbuf);
510
59.1M
  if (result < 0)
511
0
    bfd_set_error (bfd_error_system_call);
512
59.1M
  return result;
513
59.1M
}
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
1.13G
{
530
1.13G
  int result;
531
1.13G
  ufile_ptr offset = 0;
532
533
2.15G
  while (abfd->my_archive != NULL
534
2.15G
   && !bfd_is_thin_archive (abfd->my_archive))
535
1.02G
    {
536
1.02G
      offset += abfd->origin;
537
1.02G
      abfd = abfd->my_archive;
538
1.02G
    }
539
1.13G
  offset += abfd->origin;
540
541
1.13G
  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
1.13G
  BFD_ASSERT (direction == SEEK_SET || direction == SEEK_CUR);
551
552
1.13G
  if (direction != SEEK_CUR)
553
1.11G
    position += offset;
554
555
1.13G
  if (((direction == SEEK_CUR && position == 0)
556
1.13G
       || (direction == SEEK_SET && (ufile_ptr) position == abfd->where))
557
1.13G
      && abfd->last_io != bfd_io_force)
558
142M
    return 0;
559
560
992M
  abfd->last_io = bfd_io_seek;
561
562
992M
  result = abfd->iovec->bseek (abfd, position, direction);
563
992M
  if (result != 0)
564
406k
    {
565
      /* An EINVAL error probably means that the file offset was
566
   absurd.  */
567
406k
      if (errno == EINVAL)
568
406k
  bfd_set_error (bfd_error_file_truncated);
569
0
      else
570
0
  bfd_set_error (bfd_error_system_call);
571
406k
    }
572
991M
  else
573
991M
    {
574
      /* Adjust `where' field.  */
575
991M
      if (direction == SEEK_CUR)
576
17.2M
  abfd->where += position;
577
974M
      else
578
974M
  abfd->where = position;
579
991M
    }
580
581
992M
  return result;
582
1.13G
}
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
159M
{
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
159M
  if (abfd->size <= 1 || bfd_write_p (abfd))
653
52.4M
    {
654
52.4M
      struct stat buf;
655
656
52.4M
      if (abfd->size == 1 && !bfd_write_p (abfd))
657
1.68k
  return 0;
658
659
52.4M
      if (bfd_stat (abfd, &buf) != 0
660
52.4M
    || buf.st_size == 0
661
52.4M
    || buf.st_size - (ufile_ptr) buf.st_size != 0)
662
191
  {
663
191
    abfd->size = 1;
664
191
    return 0;
665
191
  }
666
52.4M
      abfd->size = buf.st_size;
667
52.4M
    }
668
159M
  return abfd->size;
669
159M
}
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
159M
{
688
159M
  ufile_ptr file_size, archive_size = (ufile_ptr) -1;
689
159M
  unsigned int compression_p2 = 0;
690
691
159M
  if (abfd->my_archive != NULL
692
159M
      && !bfd_is_thin_archive (abfd->my_archive))
693
140M
    {
694
140M
      struct areltdata *adata = (struct areltdata *) abfd->arelt_data;
695
140M
      if (adata != NULL)
696
140M
  {
697
140M
    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
140M
    if (adata->arch_header != NULL
701
140M
        && memcmp (((struct ar_hdr *) adata->arch_header)->ar_fmag,
702
140M
       "Z\012", 2) == 0)
703
2.50k
      compression_p2 = 3;
704
140M
    abfd = abfd->my_archive;
705
140M
  }
706
140M
    }
707
708
159M
  file_size = bfd_get_size (abfd) << compression_p2;
709
159M
  if (archive_size < file_size)
710
10.3M
    return archive_size;
711
149M
  return file_size;
712
159M
}
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
9.61k
{
736
9.61k
  while (abfd->my_archive != NULL
737
9.61k
   && !bfd_is_thin_archive (abfd->my_archive))
738
0
    {
739
0
      offset += abfd->origin;
740
0
      abfd = abfd->my_archive;
741
0
    }
742
9.61k
  offset += abfd->origin;
743
744
9.61k
  if (abfd->iovec == NULL)
745
0
    {
746
0
      bfd_set_error (bfd_error_invalid_operation);
747
0
      return MAP_FAILED;
748
0
    }
749
750
9.61k
  return abfd->iovec->bmmap (abfd, addr, len, prot, flags, offset,
751
9.61k
           map_addr, map_len);
752
9.61k
}
753
754
/* Memory file I/O operations.  */
755
756
static file_ptr
757
memory_bread (bfd *abfd, void *ptr, file_ptr size)
758
385
{
759
385
  struct bfd_in_memory *bim;
760
385
  bfd_size_type get;
761
762
385
  bim = (struct bfd_in_memory *) abfd->iostream;
763
385
  get = size;
764
385
  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
385
  memcpy (ptr, bim->buffer + abfd->where, (size_t) get);
773
385
  return get;
774
385
}
775
776
static file_ptr
777
memory_bwrite (bfd *abfd, const void *ptr, file_ptr size)
778
2.20k
{
779
2.20k
  struct bfd_in_memory *bim = (struct bfd_in_memory *) abfd->iostream;
780
781
2.20k
  if (abfd->where + size > bim->size)
782
2.20k
    {
783
2.20k
      bfd_size_type newsize, oldsize;
784
785
2.20k
      oldsize = (bim->size + 127) & ~(bfd_size_type) 127;
786
2.20k
      bim->size = abfd->where + size;
787
      /* Round up to cut down on memory fragmentation */
788
2.20k
      newsize = (bim->size + 127) & ~(bfd_size_type) 127;
789
2.20k
      if (newsize > oldsize)
790
2.20k
  {
791
2.20k
    bim->buffer = (bfd_byte *) bfd_realloc_or_free (bim->buffer, newsize);
792
2.20k
    if (bim->buffer == NULL)
793
0
      {
794
0
        bim->size = 0;
795
0
        return 0;
796
0
      }
797
2.20k
    if (newsize > bim->size)
798
373
      memset (bim->buffer + bim->size, 0, newsize - bim->size);
799
2.20k
  }
800
2.20k
    }
801
2.20k
  memcpy (bim->buffer + abfd->where, ptr, (size_t) size);
802
2.20k
  return size;
803
2.20k
}
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
345
{
814
345
  file_ptr nwhere;
815
345
  struct bfd_in_memory *bim;
816
817
345
  bim = (struct bfd_in_memory *) abfd->iostream;
818
819
345
  if (direction == SEEK_SET)
820
345
    nwhere = position;
821
0
  else
822
0
    nwhere = abfd->where + position;
823
824
345
  if (nwhere < 0)
825
0
    {
826
0
      abfd->where = 0;
827
0
      errno = EINVAL;
828
0
      return -1;
829
0
    }
830
831
345
  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
345
  return 0;
863
345
}
864
865
static int
866
memory_bclose (struct bfd *abfd)
867
66.5k
{
868
66.5k
  struct bfd_in_memory *bim = (struct bfd_in_memory *) abfd->iostream;
869
870
66.5k
  free (bim->buffer);
871
66.5k
  free (bim);
872
66.5k
  abfd->iostream = NULL;
873
874
66.5k
  return 0;
875
66.5k
}
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
11
{
886
11
  struct bfd_in_memory *bim = (struct bfd_in_memory *) abfd->iostream;
887
888
11
  memset (statbuf, 0, sizeof (*statbuf));
889
11
  statbuf->st_size = bim->size;
890
891
11
  return 0;
892
11
}
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
156
{
930
156
  char *source_date_epoch;
931
156
  unsigned long long epoch;
932
933
  /* FIXME: We could probably cache this lookup,
934
     and the parsing of its value below.  */
935
156
  source_date_epoch = getenv ("SOURCE_DATE_EPOCH");
936
937
156
  if (source_date_epoch == NULL)
938
156
    {
939
156
      if (now)
940
140
  return now;
941
16
      return time (NULL);
942
156
    }
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
156
}