Coverage Report

Created: 2023-06-29 07:06

/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-2023 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
47.1k
{
51
47.1k
#if defined (HAVE_FTELLO64)
52
47.1k
  return ftello64 (file);
53
#elif defined (HAVE_FTELLO)
54
  return ftello (file);
55
#else
56
  return ftell (file);
57
#endif
58
47.1k
}
59
60
int
61
_bfd_real_fseek (FILE *file, file_ptr offset, int whence)
62
12.1M
{
63
12.1M
#if defined (HAVE_FSEEKO64)
64
12.1M
  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
12.1M
}
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
19.6k
{
77
19.6k
#if defined (HAVE_FILENO) && defined (F_GETFD)
78
19.6k
  if (file)
79
19.6k
    {
80
19.6k
      int fd = fileno (file);
81
19.6k
      int old = fcntl (fd, F_GETFD, 0);
82
19.6k
      if (old >= 0)
83
19.6k
  fcntl (fd, F_SETFD, old | FD_CLOEXEC);
84
19.6k
    }
85
19.6k
#endif
86
19.6k
  return file;
87
19.6k
}
88
89
FILE *
90
_bfd_real_fopen (const char *filename, const char *modes)
91
19.6k
{
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  prefix[] = L"\\\\?\\";
123
   const size_t   partPathLen = strlen (filename) + 1;
124
#ifdef __MINGW32__
125
#if !HAVE_DECL____LC_CODEPAGE_FUNC
126
/* This prototype was added to locale.h in version 9.0 of MinGW-w64.  */
127
   _CRTIMP unsigned int __cdecl ___lc_codepage_func (void);
128
#endif
129
   const unsigned int cp = ___lc_codepage_func ();
130
#else
131
   const unsigned int cp = CP_UTF8;
132
#endif
133
134
   /* Converting the partial path from ascii to unicode.
135
      1) Get the length: Calling with lpWideCharStr set to null returns the length.
136
      2) Convert the string: Calling with cbMultiByte set to -1 includes the terminating null.  */
137
   size_t         partPathWSize = MultiByteToWideChar (cp, 0, filename, -1, NULL, 0);
138
   wchar_t *      partPath = calloc (partPathWSize, sizeof(wchar_t));
139
   size_t         ix;
140
141
   MultiByteToWideChar (cp, 0, filename, -1, partPath, partPathWSize);
142
143
   /* Convert any UNIX style path separators into the DOS i.e. backslash separator.  */
144
   for (ix = 0; ix < partPathLen; ix++)
145
     if (IS_UNIX_DIR_SEPARATOR(filename[ix]))
146
       partPath[ix] = '\\';
147
148
   /* Getting the full path from the provided partial path.
149
      1) Get the length.
150
      2) Resolve the path.  */
151
   long       fullPathWSize = GetFullPathNameW (partPath, 0, NULL, lpFilePart);
152
   wchar_t *  fullPath = calloc (fullPathWSize + sizeof(prefix) + 1, sizeof(wchar_t));
153
154
   wcscpy (fullPath, prefix);
155
156
   int        prefixLen = sizeof(prefix) / sizeof(wchar_t);
157
158
   /* Do not add a prefix to the null device.  */
159
   if (stricmp (filename, "nul") == 0)
160
    prefixLen = 1;
161
162
   wchar_t *  fullPathOffset = fullPath + prefixLen - 1;
163
164
   GetFullPathNameW (partPath, fullPathWSize, fullPathOffset, lpFilePart);
165
   free (partPath);
166
167
   /* It is non-standard for modes to exceed 16 characters.  */
168
   wchar_t    modesW[16];
169
170
   MultiByteToWideChar (cp, 0, modes, -1, modesW, sizeof(modesW));
171
172
   FILE *     file = _wfopen (fullPath, modesW);
173
   free (fullPath);
174
175
   return close_on_exec (file);
176
177
#elif defined (HAVE_FOPEN64)
178
19.6k
  return close_on_exec (fopen64 (filename, modes));
179
180
#else
181
  return close_on_exec (fopen (filename, modes));
182
#endif
183
19.6k
}
184
185
/*
186
INTERNAL_DEFINITION
187
  struct bfd_iovec
188
189
DESCRIPTION
190
191
  The <<struct bfd_iovec>> contains the internal file I/O class.
192
  Each <<BFD>> has an instance of this class and all file I/O is
193
  routed through it (it is assumed that the instance implements
194
  all methods listed below).
195
196
.struct bfd_iovec
197
.{
198
.  {* To avoid problems with macros, a "b" rather than "f"
199
.     prefix is prepended to each method name.  *}
200
.  {* Attempt to read/write NBYTES on ABFD's IOSTREAM storing/fetching
201
.     bytes starting at PTR.  Return the number of bytes actually
202
.     transfered (a read past end-of-file returns less than NBYTES),
203
.     or -1 (setting <<bfd_error>>) if an error occurs.  *}
204
.  file_ptr (*bread) (struct bfd *abfd, void *ptr, file_ptr nbytes);
205
.  file_ptr (*bwrite) (struct bfd *abfd, const void *ptr,
206
.          file_ptr nbytes);
207
.  {* Return the current IOSTREAM file offset, or -1 (setting <<bfd_error>>
208
.     if an error occurs.  *}
209
.  file_ptr (*btell) (struct bfd *abfd);
210
.  {* For the following, on successful completion a value of 0 is returned.
211
.     Otherwise, a value of -1 is returned (and <<bfd_error>> is set).  *}
212
.  int (*bseek) (struct bfd *abfd, file_ptr offset, int whence);
213
.  int (*bclose) (struct bfd *abfd);
214
.  int (*bflush) (struct bfd *abfd);
215
.  int (*bstat) (struct bfd *abfd, struct stat *sb);
216
.  {* Mmap a part of the files. ADDR, LEN, PROT, FLAGS and OFFSET are the usual
217
.     mmap parameter, except that LEN and OFFSET do not need to be page
218
.     aligned.  Returns (void *)-1 on failure, mmapped address on success.
219
.     Also write in MAP_ADDR the address of the page aligned buffer and in
220
.     MAP_LEN the size mapped (a page multiple).  Use unmap with MAP_ADDR and
221
.     MAP_LEN to unmap.  *}
222
.  void *(*bmmap) (struct bfd *abfd, void *addr, bfd_size_type len,
223
.      int prot, int flags, file_ptr offset,
224
.      void **map_addr, bfd_size_type *map_len);
225
.};
226
227
.extern const struct bfd_iovec _bfd_memory_iovec;
228
.
229
*/
230
231
232
/*
233
FUNCTION
234
  bfd_bread
235
236
SYNOPSIS
237
  bfd_size_type bfd_bread (void *, bfd_size_type, bfd *);
238
239
DESCRIPTION
240
  Attempt to read SIZE bytes from ABFD's iostream to PTR.
241
  Return the amount read.
242
*/
243
244
bfd_size_type
245
bfd_bread (void *ptr, bfd_size_type size, bfd *abfd)
246
16.9M
{
247
16.9M
  file_ptr nread;
248
16.9M
  bfd *element_bfd = abfd;
249
16.9M
  ufile_ptr offset = 0;
250
251
18.3M
  while (abfd->my_archive != NULL
252
18.3M
   && !bfd_is_thin_archive (abfd->my_archive))
253
1.38M
    {
254
1.38M
      offset += abfd->origin;
255
1.38M
      abfd = abfd->my_archive;
256
1.38M
    }
257
16.9M
  offset += abfd->origin;
258
259
  /* If this is a non-thin archive element, don't read past the end of
260
     this element.  */
261
16.9M
  if (element_bfd->arelt_data != NULL
262
16.9M
      && element_bfd->my_archive != NULL
263
16.9M
      && !bfd_is_thin_archive (element_bfd->my_archive))
264
1.38M
    {
265
1.38M
      bfd_size_type maxbytes = arelt_size (element_bfd);
266
267
1.38M
      if (abfd->where < offset || abfd->where - offset >= maxbytes)
268
11.8k
  {
269
11.8k
    bfd_set_error (bfd_error_invalid_operation);
270
11.8k
    return -1;
271
11.8k
  }
272
1.36M
      if (abfd->where - offset + size > maxbytes)
273
154k
  size = maxbytes - (abfd->where - offset);
274
1.36M
    }
275
276
16.9M
  if (abfd->iovec == NULL)
277
0
    {
278
0
      bfd_set_error (bfd_error_invalid_operation);
279
0
      return -1;
280
0
    }
281
282
16.9M
  nread = abfd->iovec->bread (abfd, ptr, size);
283
16.9M
  if (nread != -1)
284
16.9M
    abfd->where += nread;
285
286
16.9M
  return nread;
287
16.9M
}
288
289
/*
290
FUNCTION
291
  bfd_bwrite
292
293
SYNOPSIS
294
  bfd_size_type bfd_bwrite (const void *, bfd_size_type, bfd *);
295
296
DESCRIPTION
297
  Attempt to write SIZE bytes to ABFD's iostream from PTR.
298
  Return the amount written.
299
*/
300
301
bfd_size_type
302
bfd_bwrite (const void *ptr, bfd_size_type size, bfd *abfd)
303
622
{
304
622
  file_ptr nwrote;
305
306
622
  while (abfd->my_archive != NULL
307
622
   && !bfd_is_thin_archive (abfd->my_archive))
308
0
    abfd = abfd->my_archive;
309
310
622
  if (abfd->iovec == NULL)
311
0
    {
312
0
      bfd_set_error (bfd_error_invalid_operation);
313
0
      return -1;
314
0
    }
315
316
622
  nwrote = abfd->iovec->bwrite (abfd, ptr, size);
317
622
  if (nwrote != -1)
318
568
    abfd->where += nwrote;
319
622
  if ((bfd_size_type) nwrote != size)
320
54
    {
321
54
#ifdef ENOSPC
322
54
      errno = ENOSPC;
323
54
#endif
324
54
      bfd_set_error (bfd_error_system_call);
325
54
    }
326
622
  return nwrote;
327
622
}
328
329
/*
330
FUNCTION
331
  bfd_tell
332
333
SYNOPSIS
334
  file_ptr bfd_tell (bfd *);
335
336
DESCRIPTION
337
  Return ABFD's iostream file position.
338
*/
339
340
file_ptr
341
bfd_tell (bfd *abfd)
342
47.1k
{
343
47.1k
  ufile_ptr offset = 0;
344
47.1k
  file_ptr ptr;
345
346
47.3k
  while (abfd->my_archive != NULL
347
47.3k
   && !bfd_is_thin_archive (abfd->my_archive))
348
191
    {
349
191
      offset += abfd->origin;
350
191
      abfd = abfd->my_archive;
351
191
    }
352
47.1k
  offset += abfd->origin;
353
354
47.1k
  if (abfd->iovec == NULL)
355
0
    return 0;
356
357
47.1k
  ptr = abfd->iovec->btell (abfd);
358
47.1k
  abfd->where = ptr;
359
47.1k
  return ptr - offset;
360
47.1k
}
361
362
/*
363
FUNCTION
364
  bfd_flush
365
366
SYNOPSIS
367
  int bfd_flush (bfd *);
368
369
DESCRIPTION
370
  Flush ABFD's iostream pending IO.
371
*/
372
373
int
374
bfd_flush (bfd *abfd)
375
0
{
376
0
  while (abfd->my_archive != NULL
377
0
   && !bfd_is_thin_archive (abfd->my_archive))
378
0
    abfd = abfd->my_archive;
379
380
0
  if (abfd->iovec == NULL)
381
0
    return 0;
382
383
0
  return abfd->iovec->bflush (abfd);
384
0
}
385
386
/*
387
FUNCTION
388
  bfd_stat
389
390
SYNOPSIS
391
  int bfd_stat (bfd *, struct stat *);
392
393
DESCRIPTION
394
  Call fstat on ABFD's iostream.  Return 0 on success, and a
395
  negative value on failure.
396
*/
397
398
int
399
bfd_stat (bfd *abfd, struct stat *statbuf)
400
64.3k
{
401
64.3k
  int result;
402
403
74.1k
  while (abfd->my_archive != NULL
404
74.1k
   && !bfd_is_thin_archive (abfd->my_archive))
405
9.83k
    abfd = abfd->my_archive;
406
407
64.3k
  if (abfd->iovec == NULL)
408
0
    {
409
0
      bfd_set_error (bfd_error_invalid_operation);
410
0
      return -1;
411
0
    }
412
413
64.3k
  result = abfd->iovec->bstat (abfd, statbuf);
414
64.3k
  if (result < 0)
415
0
    bfd_set_error (bfd_error_system_call);
416
64.3k
  return result;
417
64.3k
}
418
419
/*
420
FUNCTION
421
  bfd_seek
422
423
SYNOPSIS
424
  int bfd_seek (bfd *, file_ptr, int);
425
426
DESCRIPTION
427
  Call fseek on ABFD's iostream.  Return 0 on success, and a
428
  negative value on failure.
429
*/
430
431
int
432
bfd_seek (bfd *abfd, file_ptr position, int direction)
433
12.1M
{
434
12.1M
  int result;
435
12.1M
  ufile_ptr offset = 0;
436
437
13.6M
  while (abfd->my_archive != NULL
438
13.6M
   && !bfd_is_thin_archive (abfd->my_archive))
439
1.48M
    {
440
1.48M
      offset += abfd->origin;
441
1.48M
      abfd = abfd->my_archive;
442
1.48M
    }
443
12.1M
  offset += abfd->origin;
444
445
12.1M
  if (abfd->iovec == NULL)
446
0
    {
447
0
      bfd_set_error (bfd_error_invalid_operation);
448
0
      return -1;
449
0
    }
450
451
  /* For the time being, a BFD may not seek to it's end.  The problem
452
     is that we don't easily have a way to recognize the end of an
453
     element in an archive.  */
454
12.1M
  BFD_ASSERT (direction == SEEK_SET || direction == SEEK_CUR);
455
456
12.1M
  if (direction != SEEK_CUR)
457
12.0M
    position += offset;
458
459
12.1M
  result = abfd->iovec->bseek (abfd, position, direction);
460
12.1M
  if (result != 0)
461
1.67k
    {
462
      /* An EINVAL error probably means that the file offset was
463
   absurd.  */
464
1.67k
      if (errno == EINVAL)
465
1.67k
  bfd_set_error (bfd_error_file_truncated);
466
0
      else
467
0
  bfd_set_error (bfd_error_system_call);
468
1.67k
    }
469
12.1M
  else
470
12.1M
    {
471
      /* Adjust `where' field.  */
472
12.1M
      if (direction == SEEK_CUR)
473
81.5k
  abfd->where += position;
474
12.0M
      else
475
12.0M
  abfd->where = position;
476
12.1M
    }
477
478
12.1M
  return result;
479
12.1M
}
480
481
/*
482
FUNCTION
483
  bfd_get_mtime
484
485
SYNOPSIS
486
  long bfd_get_mtime (bfd *abfd);
487
488
DESCRIPTION
489
  Return the file modification time (as read from the file system, or
490
  from the archive header for archive members).
491
492
*/
493
494
long
495
bfd_get_mtime (bfd *abfd)
496
0
{
497
0
  struct stat buf;
498
499
0
  if (abfd->mtime_set)
500
0
    return abfd->mtime;
501
502
0
  if (bfd_stat (abfd, &buf) != 0)
503
0
    return 0;
504
505
0
  abfd->mtime = buf.st_mtime;   /* Save value in case anyone wants it */
506
0
  return buf.st_mtime;
507
0
}
508
509
/*
510
FUNCTION
511
  bfd_get_size
512
513
SYNOPSIS
514
  ufile_ptr bfd_get_size (bfd *abfd);
515
516
DESCRIPTION
517
  Return the file size (as read from file system) for the file
518
  associated with BFD @var{abfd}.
519
520
  The initial motivation for, and use of, this routine is not
521
  so we can get the exact size of the object the BFD applies to, since
522
  that might not be generally possible (archive members for example).
523
  It would be ideal if someone could eventually modify
524
  it so that such results were guaranteed.
525
526
  Instead, we want to ask questions like "is this NNN byte sized
527
  object I'm about to try read from file offset YYY reasonable?"
528
  As as example of where we might do this, some object formats
529
  use string tables for which the first <<sizeof (long)>> bytes of the
530
  table contain the size of the table itself, including the size bytes.
531
  If an application tries to read what it thinks is one of these
532
  string tables, without some way to validate the size, and for
533
  some reason the size is wrong (byte swapping error, wrong location
534
  for the string table, etc.), the only clue is likely to be a read
535
  error when it tries to read the table, or a "virtual memory
536
  exhausted" error when it tries to allocate 15 bazillon bytes
537
  of space for the 15 bazillon byte table it is about to read.
538
  This function at least allows us to answer the question, "is the
539
  size reasonable?".
540
541
  A return value of zero indicates the file size is unknown.
542
*/
543
544
ufile_ptr
545
bfd_get_size (bfd *abfd)
546
2.41M
{
547
  /* A size of 0 means we haven't yet called bfd_stat.  A size of 1
548
     means we have a cached value of 0, ie. unknown.  */
549
2.41M
  if (abfd->size <= 1 || bfd_write_p (abfd))
550
19.4k
    {
551
19.4k
      struct stat buf;
552
553
19.4k
      if (abfd->size == 1 && !bfd_write_p (abfd))
554
70
  return 0;
555
556
19.3k
      if (bfd_stat (abfd, &buf) != 0
557
19.3k
    || buf.st_size == 0
558
19.3k
    || buf.st_size - (ufile_ptr) buf.st_size != 0)
559
0
  {
560
0
    abfd->size = 1;
561
0
    return 0;
562
0
  }
563
19.3k
      abfd->size = buf.st_size;
564
19.3k
    }
565
2.41M
  return abfd->size;
566
2.41M
}
567
568
/*
569
FUNCTION
570
  bfd_get_file_size
571
572
SYNOPSIS
573
  ufile_ptr bfd_get_file_size (bfd *abfd);
574
575
DESCRIPTION
576
  Return the file size (as read from file system) for the file
577
  associated with BFD @var{abfd}.  It supports both normal files
578
  and archive elements.
579
580
*/
581
582
ufile_ptr
583
bfd_get_file_size (bfd *abfd)
584
2.41M
{
585
2.41M
  ufile_ptr file_size, archive_size = (ufile_ptr) -1;
586
2.41M
  unsigned int compression_p2 = 0;
587
588
2.41M
  if (abfd->my_archive != NULL
589
2.41M
      && !bfd_is_thin_archive (abfd->my_archive))
590
212k
    {
591
212k
      struct areltdata *adata = (struct areltdata *) abfd->arelt_data;
592
212k
      if (adata != NULL)
593
212k
  {
594
212k
    archive_size = adata->parsed_size;
595
    /* If the archive is compressed, assume an element won't
596
       expand more than eight times file size.  */
597
212k
    if (adata->arch_header != NULL
598
212k
        && memcmp (((struct ar_hdr *) adata->arch_header)->ar_fmag,
599
204k
       "Z\012", 2) == 0)
600
524
      compression_p2 = 3;
601
212k
    abfd = abfd->my_archive;
602
212k
  }
603
212k
    }
604
605
2.41M
  file_size = bfd_get_size (abfd) << compression_p2;
606
2.41M
  if (archive_size < file_size)
607
167k
    return archive_size;
608
2.25M
  return file_size;
609
2.41M
}
610
611
/*
612
FUNCTION
613
  bfd_mmap
614
615
SYNOPSIS
616
  void *bfd_mmap (bfd *abfd, void *addr, bfd_size_type len,
617
      int prot, int flags, file_ptr offset,
618
      void **map_addr, bfd_size_type *map_len);
619
620
DESCRIPTION
621
  Return mmap()ed region of the file, if possible and implemented.
622
  LEN and OFFSET do not need to be page aligned.  The page aligned
623
  address and length are written to MAP_ADDR and MAP_LEN.
624
625
*/
626
627
void *
628
bfd_mmap (bfd *abfd, void *addr, bfd_size_type len,
629
    int prot, int flags, file_ptr offset,
630
    void **map_addr, bfd_size_type *map_len)
631
0
{
632
0
  while (abfd->my_archive != NULL
633
0
   && !bfd_is_thin_archive (abfd->my_archive))
634
0
    {
635
0
      offset += abfd->origin;
636
0
      abfd = abfd->my_archive;
637
0
    }
638
0
  offset += abfd->origin;
639
640
0
  if (abfd->iovec == NULL)
641
0
    {
642
0
      bfd_set_error (bfd_error_invalid_operation);
643
0
      return (void *) -1;
644
0
    }
645
646
0
  return abfd->iovec->bmmap (abfd, addr, len, prot, flags, offset,
647
0
           map_addr, map_len);
648
0
}
649
650
/* Memory file I/O operations.  */
651
652
static file_ptr
653
memory_bread (bfd *abfd, void *ptr, file_ptr size)
654
0
{
655
0
  struct bfd_in_memory *bim;
656
0
  bfd_size_type get;
657
658
0
  bim = (struct bfd_in_memory *) abfd->iostream;
659
0
  get = size;
660
0
  if (abfd->where + get > bim->size)
661
0
    {
662
0
      if (bim->size < (bfd_size_type) abfd->where)
663
0
  get = 0;
664
0
      else
665
0
  get = bim->size - abfd->where;
666
0
      bfd_set_error (bfd_error_file_truncated);
667
0
    }
668
0
  memcpy (ptr, bim->buffer + abfd->where, (size_t) get);
669
0
  return get;
670
0
}
671
672
static file_ptr
673
memory_bwrite (bfd *abfd, const void *ptr, file_ptr size)
674
568
{
675
568
  struct bfd_in_memory *bim = (struct bfd_in_memory *) abfd->iostream;
676
677
568
  if (abfd->where + size > bim->size)
678
568
    {
679
568
      bfd_size_type newsize, oldsize;
680
681
568
      oldsize = (bim->size + 127) & ~(bfd_size_type) 127;
682
568
      bim->size = abfd->where + size;
683
      /* Round up to cut down on memory fragmentation */
684
568
      newsize = (bim->size + 127) & ~(bfd_size_type) 127;
685
568
      if (newsize > oldsize)
686
568
  {
687
568
    bim->buffer = (bfd_byte *) bfd_realloc_or_free (bim->buffer, newsize);
688
568
    if (bim->buffer == NULL)
689
0
      {
690
0
        bim->size = 0;
691
0
        return 0;
692
0
      }
693
568
    if (newsize > bim->size)
694
161
      memset (bim->buffer + bim->size, 0, newsize - bim->size);
695
568
  }
696
568
    }
697
568
  memcpy (bim->buffer + abfd->where, ptr, (size_t) size);
698
568
  return size;
699
568
}
700
701
static file_ptr
702
memory_btell (bfd *abfd)
703
0
{
704
0
  return abfd->where;
705
0
}
706
707
static int
708
memory_bseek (bfd *abfd, file_ptr position, int direction)
709
0
{
710
0
  file_ptr nwhere;
711
0
  struct bfd_in_memory *bim;
712
713
0
  bim = (struct bfd_in_memory *) abfd->iostream;
714
715
0
  if (direction == SEEK_SET)
716
0
    nwhere = position;
717
0
  else
718
0
    nwhere = abfd->where + position;
719
720
0
  if (nwhere < 0)
721
0
    {
722
0
      abfd->where = 0;
723
0
      errno = EINVAL;
724
0
      return -1;
725
0
    }
726
727
0
  if ((bfd_size_type)nwhere > bim->size)
728
0
    {
729
0
      if (abfd->direction == write_direction
730
0
    || abfd->direction == both_direction)
731
0
  {
732
0
    bfd_size_type newsize, oldsize;
733
734
0
    oldsize = (bim->size + 127) & ~(bfd_size_type) 127;
735
0
    bim->size = nwhere;
736
    /* Round up to cut down on memory fragmentation */
737
0
    newsize = (bim->size + 127) & ~(bfd_size_type) 127;
738
0
    if (newsize > oldsize)
739
0
      {
740
0
        bim->buffer = (bfd_byte *) bfd_realloc_or_free (bim->buffer, newsize);
741
0
        if (bim->buffer == NULL)
742
0
    {
743
0
      errno = EINVAL;
744
0
      bim->size = 0;
745
0
      return -1;
746
0
    }
747
0
        memset (bim->buffer + oldsize, 0, newsize - oldsize);
748
0
      }
749
0
  }
750
0
      else
751
0
  {
752
0
    abfd->where = bim->size;
753
0
    errno = EINVAL;
754
0
    bfd_set_error (bfd_error_file_truncated);
755
0
    return -1;
756
0
  }
757
0
    }
758
0
  return 0;
759
0
}
760
761
static int
762
memory_bclose (struct bfd *abfd)
763
2.10k
{
764
2.10k
  struct bfd_in_memory *bim = (struct bfd_in_memory *) abfd->iostream;
765
766
2.10k
  free (bim->buffer);
767
2.10k
  free (bim);
768
2.10k
  abfd->iostream = NULL;
769
770
2.10k
  return 0;
771
2.10k
}
772
773
static int
774
memory_bflush (bfd *abfd ATTRIBUTE_UNUSED)
775
0
{
776
0
  return 0;
777
0
}
778
779
static int
780
memory_bstat (bfd *abfd, struct stat *statbuf)
781
6
{
782
6
  struct bfd_in_memory *bim = (struct bfd_in_memory *) abfd->iostream;
783
784
6
  memset (statbuf, 0, sizeof (*statbuf));
785
6
  statbuf->st_size = bim->size;
786
787
6
  return 0;
788
6
}
789
790
static void *
791
memory_bmmap (bfd *abfd ATTRIBUTE_UNUSED, void *addr ATTRIBUTE_UNUSED,
792
        bfd_size_type len ATTRIBUTE_UNUSED, int prot ATTRIBUTE_UNUSED,
793
        int flags ATTRIBUTE_UNUSED, file_ptr offset ATTRIBUTE_UNUSED,
794
        void **map_addr ATTRIBUTE_UNUSED,
795
        bfd_size_type *map_len ATTRIBUTE_UNUSED)
796
0
{
797
0
  return (void *)-1;
798
0
}
799
800
const struct bfd_iovec _bfd_memory_iovec =
801
{
802
  &memory_bread, &memory_bwrite, &memory_btell, &memory_bseek,
803
  &memory_bclose, &memory_bflush, &memory_bstat, &memory_bmmap
804
};