Subversion Repositories Kolibri OS

Rev

Rev 5199 | Details | Compare with Previous | Last modification | View Log | RSS feed

Rev Author Line No. Line
5197 serge 1
/* Low-level I/O routines for BFDs.
2
 
6324 serge 3
   Copyright (C) 1990-2015 Free Software Foundation, Inc.
5197 serge 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 
26
#include "bfd.h"
27
#include "libbfd.h"
28
 
29
#ifndef S_IXUSR
30
#define S_IXUSR 0100    /* Execute by owner.  */
31
#endif
32
#ifndef S_IXGRP
33
#define S_IXGRP 0010    /* Execute by group.  */
34
#endif
35
#ifndef S_IXOTH
36
#define S_IXOTH 0001    /* Execute by others.  */
37
#endif
38
 
39
#ifndef FD_CLOEXEC
40
#define FD_CLOEXEC 1
41
#endif
42
 
43
file_ptr
44
real_ftell (FILE *file)
45
{
46
#if defined (HAVE_FTELLO64)
47
  return ftello64 (file);
48
#elif defined (HAVE_FTELLO)
49
  return ftello (file);
50
#else
51
  return ftell (file);
52
#endif
53
}
54
 
55
int
56
real_fseek (FILE *file, file_ptr offset, int whence)
57
{
58
#if defined (HAVE_FSEEKO64)
59
  return fseeko64 (file, offset, whence);
60
#elif defined (HAVE_FSEEKO)
61
  return fseeko (file, offset, whence);
62
#else
63
  return fseek (file, offset, whence);
64
#endif
65
}
66
 
67
/* Mark FILE as close-on-exec.  Return FILE.  FILE may be NULL, in
68
   which case nothing is done.  */
69
static FILE *
70
close_on_exec (FILE *file)
71
{
72
  return file;
73
}
74
 
75
FILE *
76
real_fopen (const char *filename, const char *modes)
77
{
78
#ifdef VMS
79
  char *vms_attr;
80
 
81
  /* On VMS, fopen allows file attributes as optional arguments.
82
     We need to use them but we'd better to use the common prototype.
83
     In fopen-vms.h, they are separated from the mode with a comma.
84
     Split here.  */
85
  vms_attr = strchr (modes, ',');
86
  if (vms_attr == NULL)
87
    {
88
      /* No attributes.  */
89
      return close_on_exec (fopen (filename, modes));
90
    }
91
  else
92
    {
93
      /* Attributes found.  Split.  */
94
      size_t modes_len = strlen (modes) + 1;
95
      char attrs[modes_len + 1];
96
      char *at[3];
97
      int i;
98
 
99
      memcpy (attrs, modes, modes_len);
100
      at[0] = attrs;
101
      for (i = 0; i < 2; i++)
102
	{
103
	  at[i + 1] = strchr (at[i], ',');
104
	  BFD_ASSERT (at[i + 1] != NULL);
105
	  *(at[i + 1]++) = 0; /* Replace ',' with a nul, and skip it.  */
106
	}
107
      return close_on_exec (fopen (filename, at[0], at[1], at[2]));
108
    }
109
#else /* !VMS */
110
#if defined (HAVE_FOPEN64)
111
  return close_on_exec (fopen64 (filename, modes));
112
#else
113
  return close_on_exec (fopen (filename, modes));
114
#endif
115
#endif /* !VMS */
116
}
117
 
118
/*
119
INTERNAL_DEFINITION
120
	struct bfd_iovec
121
 
122
DESCRIPTION
123
 
124
	The <> contains the internal file I/O class.
125
	Each <> has an instance of this class and all file I/O is
126
	routed through it (it is assumed that the instance implements
127
	all methods listed below).
128
 
129
.struct bfd_iovec
130
.{
131
.  {* To avoid problems with macros, a "b" rather than "f"
132
.     prefix is prepended to each method name.  *}
133
.  {* Attempt to read/write NBYTES on ABFD's IOSTREAM storing/fetching
134
.     bytes starting at PTR.  Return the number of bytes actually
135
.     transfered (a read past end-of-file returns less than NBYTES),
136
.     or -1 (setting <>) if an error occurs.  *}
137
.  file_ptr (*bread) (struct bfd *abfd, void *ptr, file_ptr nbytes);
138
.  file_ptr (*bwrite) (struct bfd *abfd, const void *ptr,
139
.                      file_ptr nbytes);
140
.  {* Return the current IOSTREAM file offset, or -1 (setting <>
141
.     if an error occurs.  *}
142
.  file_ptr (*btell) (struct bfd *abfd);
143
.  {* For the following, on successful completion a value of 0 is returned.
144
.     Otherwise, a value of -1 is returned (and  <> is set).  *}
145
.  int (*bseek) (struct bfd *abfd, file_ptr offset, int whence);
146
.  int (*bclose) (struct bfd *abfd);
147
.  int (*bflush) (struct bfd *abfd);
148
.  int (*bstat) (struct bfd *abfd, struct stat *sb);
149
.  {* Mmap a part of the files. ADDR, LEN, PROT, FLAGS and OFFSET are the usual
150
.     mmap parameter, except that LEN and OFFSET do not need to be page
151
.     aligned.  Returns (void *)-1 on failure, mmapped address on success.
152
.     Also write in MAP_ADDR the address of the page aligned buffer and in
153
.     MAP_LEN the size mapped (a page multiple).  Use unmap with MAP_ADDR and
154
.     MAP_LEN to unmap.  *}
155
.  void *(*bmmap) (struct bfd *abfd, void *addr, bfd_size_type len,
156
.                  int prot, int flags, file_ptr offset,
157
.                  void **map_addr, bfd_size_type *map_len);
158
.};
159
 
160
.extern const struct bfd_iovec _bfd_memory_iovec;
161
 
162
*/
163
 
164
 
165
/* Return value is amount read.  */
166
 
167
bfd_size_type
168
bfd_bread (void *ptr, bfd_size_type size, bfd *abfd)
169
{
170
  size_t nread;
171
 
172
  /* If this is an archive element, don't read past the end of
173
     this element.  */
174
  if (abfd->arelt_data != NULL)
175
    {
176
      bfd_size_type maxbytes = arelt_size (abfd);
177
 
178
      if (abfd->where + size > maxbytes)
179
        {
180
          if (abfd->where >= maxbytes)
181
            return 0;
182
          size = maxbytes - abfd->where;
183
        }
184
    }
185
 
186
  if (abfd->iovec)
187
    nread = abfd->iovec->bread (abfd, ptr, size);
188
  else
189
    nread = 0;
190
  if (nread != (size_t) -1)
191
    abfd->where += nread;
192
 
193
  return nread;
194
}
195
 
196
bfd_size_type
197
bfd_bwrite (const void *ptr, bfd_size_type size, bfd *abfd)
198
{
199
  size_t nwrote;
200
 
201
  if (abfd->iovec)
202
    nwrote = abfd->iovec->bwrite (abfd, ptr, size);
203
  else
204
    nwrote = 0;
205
 
206
  if (nwrote != (size_t) -1)
207
    abfd->where += nwrote;
208
  if (nwrote != size)
209
    {
210
#ifdef ENOSPC
211
      errno = ENOSPC;
212
#endif
213
      bfd_set_error (bfd_error_system_call);
214
    }
215
  return nwrote;
216
}
217
 
218
file_ptr
219
bfd_tell (bfd *abfd)
220
{
221
  file_ptr ptr;
222
 
223
  if (abfd->iovec)
224
    {
225
      bfd *parent_bfd = abfd;
226
      ptr = abfd->iovec->btell (abfd);
227
 
228
      while (parent_bfd->my_archive != NULL)
229
	{
230
	  ptr -= parent_bfd->origin;
231
	  parent_bfd = parent_bfd->my_archive;
232
	}
233
    }
234
  else
235
    ptr = 0;
236
 
237
  abfd->where = ptr;
238
  return ptr;
239
}
240
 
241
int
242
bfd_flush (bfd *abfd)
243
{
244
  if (abfd->iovec)
245
    return abfd->iovec->bflush (abfd);
246
  return 0;
247
}
248
 
249
/* Returns 0 for success, negative value for failure (in which case
250
   bfd_get_error can retrieve the error code).  */
251
int
252
bfd_stat (bfd *abfd, struct stat *statbuf)
253
{
254
  int result;
255
 
256
  if (abfd->iovec)
257
    result = abfd->iovec->bstat (abfd, statbuf);
258
  else
259
    result = -1;
260
 
261
  if (result < 0)
262
    bfd_set_error (bfd_error_system_call);
263
  return result;
264
}
265
 
266
/* Returns 0 for success, nonzero for failure (in which case bfd_get_error
267
   can retrieve the error code).  */
268
 
269
int
270
bfd_seek (bfd *abfd, file_ptr position, int direction)
271
{
272
  int result;
273
  file_ptr file_position;
274
  /* For the time being, a BFD may not seek to it's end.  The problem
275
     is that we don't easily have a way to recognize the end of an
276
     element in an archive.  */
277
 
278
  BFD_ASSERT (direction == SEEK_SET || direction == SEEK_CUR);
279
 
280
  if (direction == SEEK_CUR && position == 0)
281
    return 0;
282
 
283
  if (abfd->format != bfd_archive && abfd->my_archive == 0)
284
    {
285
      if (direction == SEEK_SET && (bfd_vma) position == abfd->where)
286
	return 0;
287
    }
288
  else
289
    {
290
      /* We need something smarter to optimize access to archives.
291
	 Currently, anything inside an archive is read via the file
292
	 handle for the archive.  Which means that a bfd_seek on one
293
	 component affects the `current position' in the archive, as
294
	 well as in any other component.
295
 
296
	 It might be sufficient to put a spike through the cache
297
	 abstraction, and look to the archive for the file position,
298
	 but I think we should try for something cleaner.
299
 
300
	 In the meantime, no optimization for archives.  */
301
    }
302
 
303
  file_position = position;
304
  if (direction == SEEK_SET)
305
    {
306
      bfd *parent_bfd = abfd;
307
 
308
      while (parent_bfd->my_archive != NULL)
309
        {
310
          file_position += parent_bfd->origin;
311
          parent_bfd = parent_bfd->my_archive;
312
        }
313
    }
314
 
315
  if (abfd->iovec)
316
    result = abfd->iovec->bseek (abfd, file_position, direction);
317
  else
318
    result = -1;
319
 
320
  if (result != 0)
321
    {
322
      int hold_errno = errno;
323
 
324
      /* Force redetermination of `where' field.  */
325
      bfd_tell (abfd);
326
 
327
      /* An EINVAL error probably means that the file offset was
328
         absurd.  */
329
      if (hold_errno == EINVAL)
330
	bfd_set_error (bfd_error_file_truncated);
331
      else
332
	{
333
	  bfd_set_error (bfd_error_system_call);
334
	  errno = hold_errno;
335
	}
336
    }
337
  else
338
    {
339
      /* Adjust `where' field.  */
340
      if (direction == SEEK_SET)
341
	abfd->where = position;
342
      else
343
	abfd->where += position;
344
    }
345
  return result;
346
}
347
 
348
/*
349
FUNCTION
350
	bfd_get_mtime
351
 
352
SYNOPSIS
353
	long bfd_get_mtime (bfd *abfd);
354
 
355
DESCRIPTION
356
	Return the file modification time (as read from the file system, or
357
	from the archive header for archive members).
358
 
359
*/
360
 
361
long
362
bfd_get_mtime (bfd *abfd)
363
{
364
  struct stat buf;
365
 
366
  if (abfd->mtime_set)
367
    return abfd->mtime;
368
 
369
  if (abfd->iovec == NULL)
370
    return 0;
371
 
372
  if (abfd->iovec->bstat (abfd, &buf) != 0)
373
    return 0;
374
 
375
  abfd->mtime = buf.st_mtime;		/* Save value in case anyone wants it */
376
  return buf.st_mtime;
377
}
378
 
379
/*
380
FUNCTION
381
	bfd_get_size
382
 
383
SYNOPSIS
384
	file_ptr bfd_get_size (bfd *abfd);
385
 
386
DESCRIPTION
387
	Return the file size (as read from file system) for the file
388
	associated with BFD @var{abfd}.
389
 
390
	The initial motivation for, and use of, this routine is not
391
	so we can get the exact size of the object the BFD applies to, since
392
	that might not be generally possible (archive members for example).
393
	It would be ideal if someone could eventually modify
394
	it so that such results were guaranteed.
395
 
396
	Instead, we want to ask questions like "is this NNN byte sized
397
	object I'm about to try read from file offset YYY reasonable?"
398
	As as example of where we might do this, some object formats
399
	use string tables for which the first <> bytes of the
400
	table contain the size of the table itself, including the size bytes.
401
	If an application tries to read what it thinks is one of these
402
	string tables, without some way to validate the size, and for
403
	some reason the size is wrong (byte swapping error, wrong location
404
	for the string table, etc.), the only clue is likely to be a read
405
	error when it tries to read the table, or a "virtual memory
406
	exhausted" error when it tries to allocate 15 bazillon bytes
407
	of space for the 15 bazillon byte table it is about to read.
408
	This function at least allows us to answer the question, "is the
409
	size reasonable?".
410
*/
411
 
412
file_ptr
413
bfd_get_size (bfd *abfd)
414
{
415
  struct stat buf;
416
 
417
  if (abfd->iovec == NULL)
418
    return 0;
419
 
420
  if (abfd->iovec->bstat (abfd, &buf) != 0)
421
    return 0;
422
 
423
  return buf.st_size;
424
}
425
 
426
 
427
/*
428
FUNCTION
429
	bfd_mmap
430
 
431
SYNOPSIS
432
	void *bfd_mmap (bfd *abfd, void *addr, bfd_size_type len,
433
	                int prot, int flags, file_ptr offset,
434
	                void **map_addr, bfd_size_type *map_len);
435
 
436
DESCRIPTION
437
	Return mmap()ed region of the file, if possible and implemented.
438
        LEN and OFFSET do not need to be page aligned.  The page aligned
439
        address and length are written to MAP_ADDR and MAP_LEN.
440
 
441
*/
442
 
443
void *
444
bfd_mmap (bfd *abfd, void *addr, bfd_size_type len,
445
	  int prot, int flags, file_ptr offset,
446
          void **map_addr, bfd_size_type *map_len)
447
{
448
  void *ret = (void *)-1;
449
 
450
  if (abfd->iovec == NULL)
451
    return ret;
452
 
453
  return abfd->iovec->bmmap (abfd, addr, len, prot, flags, offset,
454
                             map_addr, map_len);
455
}
456
 
457
/* Memory file I/O operations.  */
458
 
459
static file_ptr
460
memory_bread (bfd *abfd, void *ptr, file_ptr size)
461
{
462
  struct bfd_in_memory *bim;
463
  bfd_size_type get;
464
 
465
  bim = (struct bfd_in_memory *) abfd->iostream;
466
  get = size;
467
  if (abfd->where + get > bim->size)
468
    {
469
      if (bim->size < (bfd_size_type) abfd->where)
470
        get = 0;
471
      else
472
        get = bim->size - abfd->where;
473
      bfd_set_error (bfd_error_file_truncated);
474
    }
475
  memcpy (ptr, bim->buffer + abfd->where, (size_t) get);
476
  return get;
477
}
478
 
479
static file_ptr
480
memory_bwrite (bfd *abfd, const void *ptr, file_ptr size)
481
{
482
  struct bfd_in_memory *bim = (struct bfd_in_memory *) abfd->iostream;
483
 
484
  if (abfd->where + size > bim->size)
485
    {
486
      bfd_size_type newsize, oldsize;
487
 
488
      oldsize = (bim->size + 127) & ~(bfd_size_type) 127;
489
      bim->size = abfd->where + size;
490
      /* Round up to cut down on memory fragmentation */
491
      newsize = (bim->size + 127) & ~(bfd_size_type) 127;
492
      if (newsize > oldsize)
493
        {
494
          bim->buffer = (bfd_byte *) bfd_realloc_or_free (bim->buffer, newsize);
495
          if (bim->buffer == NULL)
496
            {
497
              bim->size = 0;
498
              return 0;
499
            }
500
          if (newsize > bim->size)
501
            memset (bim->buffer + bim->size, 0, newsize - bim->size);
502
        }
503
    }
504
  memcpy (bim->buffer + abfd->where, ptr, (size_t) size);
505
  return size;
506
}
507
 
508
static file_ptr
509
memory_btell (bfd *abfd)
510
{
511
  return abfd->where;
512
}
513
 
514
static int
515
memory_bseek (bfd *abfd, file_ptr position, int direction)
516
{
517
  file_ptr nwhere;
518
  struct bfd_in_memory *bim;
519
 
520
  bim = (struct bfd_in_memory *) abfd->iostream;
521
 
522
  if (direction == SEEK_SET)
523
    nwhere = position;
524
  else
525
    nwhere = abfd->where + position;
526
 
527
  if (nwhere < 0)
528
    {
529
      abfd->where = 0;
530
      errno = EINVAL;
531
      return -1;
532
    }
533
 
534
  if ((bfd_size_type)nwhere > bim->size)
535
    {
536
      if (abfd->direction == write_direction
537
          || abfd->direction == both_direction)
538
        {
539
          bfd_size_type newsize, oldsize;
540
 
541
          oldsize = (bim->size + 127) & ~(bfd_size_type) 127;
542
          bim->size = nwhere;
543
          /* Round up to cut down on memory fragmentation */
544
          newsize = (bim->size + 127) & ~(bfd_size_type) 127;
545
          if (newsize > oldsize)
546
            {
547
              bim->buffer = (bfd_byte *) bfd_realloc_or_free (bim->buffer, newsize);
548
              if (bim->buffer == NULL)
549
                {
550
                  errno = EINVAL;
551
                  bim->size = 0;
552
                  return -1;
553
                }
554
              memset (bim->buffer + oldsize, 0, newsize - oldsize);
555
            }
556
        }
557
      else
558
        {
559
          abfd->where = bim->size;
560
          errno = EINVAL;
561
          bfd_set_error (bfd_error_file_truncated);
562
          return -1;
563
        }
564
    }
565
  return 0;
566
}
567
 
568
static int
569
memory_bclose (struct bfd *abfd)
570
{
571
  struct bfd_in_memory *bim = (struct bfd_in_memory *) abfd->iostream;
572
 
573
  if (bim->buffer != NULL)
574
    free (bim->buffer);
575
  free (bim);
576
  abfd->iostream = NULL;
577
 
578
  return 0;
579
}
580
 
581
static int
582
memory_bflush (bfd *abfd ATTRIBUTE_UNUSED)
583
{
584
  return 0;
585
}
586
 
587
static int
588
memory_bstat (bfd *abfd, struct stat *statbuf)
589
{
590
  struct bfd_in_memory *bim = (struct bfd_in_memory *) abfd->iostream;
591
 
592
  memset (statbuf, 0, sizeof (*statbuf));
593
  statbuf->st_size = bim->size;
594
 
595
  return 0;
596
}
597
 
598
static void *
599
memory_bmmap (bfd *abfd ATTRIBUTE_UNUSED, void *addr ATTRIBUTE_UNUSED,
600
              bfd_size_type len ATTRIBUTE_UNUSED, int prot ATTRIBUTE_UNUSED,
601
              int flags ATTRIBUTE_UNUSED, file_ptr offset ATTRIBUTE_UNUSED,
602
              void **map_addr ATTRIBUTE_UNUSED,
603
              bfd_size_type *map_len ATTRIBUTE_UNUSED)
604
{
605
  return (void *)-1;
606
}
607
 
608
const struct bfd_iovec _bfd_memory_iovec =
609
{
610
  &memory_bread, &memory_bwrite, &memory_btell, &memory_bseek,
611
  &memory_bclose, &memory_bflush, &memory_bstat, &memory_bmmap
612
};