15796c8dcSSimon Schubert /* Low-level I/O routines for BFDs.
25796c8dcSSimon Schubert
35796c8dcSSimon Schubert Copyright 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1997, 1998,
4a45ae5f8SJohn Marino 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2011
55796c8dcSSimon Schubert Free Software Foundation, Inc.
65796c8dcSSimon Schubert
75796c8dcSSimon Schubert Written by Cygnus Support.
85796c8dcSSimon Schubert
95796c8dcSSimon Schubert This file is part of BFD, the Binary File Descriptor library.
105796c8dcSSimon Schubert
115796c8dcSSimon Schubert This program is free software; you can redistribute it and/or modify
125796c8dcSSimon Schubert it under the terms of the GNU General Public License as published by
135796c8dcSSimon Schubert the Free Software Foundation; either version 3 of the License, or
145796c8dcSSimon Schubert (at your option) any later version.
155796c8dcSSimon Schubert
165796c8dcSSimon Schubert This program is distributed in the hope that it will be useful,
175796c8dcSSimon Schubert but WITHOUT ANY WARRANTY; without even the implied warranty of
185796c8dcSSimon Schubert MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
195796c8dcSSimon Schubert GNU General Public License for more details.
205796c8dcSSimon Schubert
215796c8dcSSimon Schubert You should have received a copy of the GNU General Public License
225796c8dcSSimon Schubert along with this program; if not, write to the Free Software
235796c8dcSSimon Schubert Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston,
245796c8dcSSimon Schubert MA 02110-1301, USA. */
255796c8dcSSimon Schubert
265796c8dcSSimon Schubert #include "sysdep.h"
275796c8dcSSimon Schubert #include <limits.h>
285796c8dcSSimon Schubert #include "bfd.h"
295796c8dcSSimon Schubert #include "libbfd.h"
305796c8dcSSimon Schubert
315796c8dcSSimon Schubert #ifndef S_IXUSR
325796c8dcSSimon Schubert #define S_IXUSR 0100 /* Execute by owner. */
335796c8dcSSimon Schubert #endif
345796c8dcSSimon Schubert #ifndef S_IXGRP
355796c8dcSSimon Schubert #define S_IXGRP 0010 /* Execute by group. */
365796c8dcSSimon Schubert #endif
375796c8dcSSimon Schubert #ifndef S_IXOTH
385796c8dcSSimon Schubert #define S_IXOTH 0001 /* Execute by others. */
395796c8dcSSimon Schubert #endif
405796c8dcSSimon Schubert
415796c8dcSSimon Schubert #ifndef FD_CLOEXEC
425796c8dcSSimon Schubert #define FD_CLOEXEC 1
435796c8dcSSimon Schubert #endif
445796c8dcSSimon Schubert
455796c8dcSSimon Schubert file_ptr
real_ftell(FILE * file)465796c8dcSSimon Schubert real_ftell (FILE *file)
475796c8dcSSimon Schubert {
485796c8dcSSimon Schubert #if defined (HAVE_FTELLO64)
495796c8dcSSimon Schubert return ftello64 (file);
505796c8dcSSimon Schubert #elif defined (HAVE_FTELLO)
515796c8dcSSimon Schubert return ftello (file);
525796c8dcSSimon Schubert #else
535796c8dcSSimon Schubert return ftell (file);
545796c8dcSSimon Schubert #endif
555796c8dcSSimon Schubert }
565796c8dcSSimon Schubert
575796c8dcSSimon Schubert int
real_fseek(FILE * file,file_ptr offset,int whence)585796c8dcSSimon Schubert real_fseek (FILE *file, file_ptr offset, int whence)
595796c8dcSSimon Schubert {
605796c8dcSSimon Schubert #if defined (HAVE_FSEEKO64)
615796c8dcSSimon Schubert return fseeko64 (file, offset, whence);
625796c8dcSSimon Schubert #elif defined (HAVE_FSEEKO)
635796c8dcSSimon Schubert return fseeko (file, offset, whence);
645796c8dcSSimon Schubert #else
655796c8dcSSimon Schubert return fseek (file, offset, whence);
665796c8dcSSimon Schubert #endif
675796c8dcSSimon Schubert }
685796c8dcSSimon Schubert
695796c8dcSSimon Schubert /* Mark FILE as close-on-exec. Return FILE. FILE may be NULL, in
705796c8dcSSimon Schubert which case nothing is done. */
715796c8dcSSimon Schubert static FILE *
close_on_exec(FILE * file)725796c8dcSSimon Schubert close_on_exec (FILE *file)
735796c8dcSSimon Schubert {
745796c8dcSSimon Schubert #if defined (HAVE_FILENO) && defined (F_GETFD)
755796c8dcSSimon Schubert if (file)
765796c8dcSSimon Schubert {
775796c8dcSSimon Schubert int fd = fileno (file);
785796c8dcSSimon Schubert int old = fcntl (fd, F_GETFD, 0);
795796c8dcSSimon Schubert if (old >= 0)
805796c8dcSSimon Schubert fcntl (fd, F_SETFD, old | FD_CLOEXEC);
815796c8dcSSimon Schubert }
825796c8dcSSimon Schubert #endif
835796c8dcSSimon Schubert return file;
845796c8dcSSimon Schubert }
855796c8dcSSimon Schubert
865796c8dcSSimon Schubert FILE *
real_fopen(const char * filename,const char * modes)875796c8dcSSimon Schubert real_fopen (const char *filename, const char *modes)
885796c8dcSSimon Schubert {
895796c8dcSSimon Schubert #ifdef VMS
905796c8dcSSimon Schubert char *vms_attr;
915796c8dcSSimon Schubert
925796c8dcSSimon Schubert /* On VMS, fopen allows file attributes as optionnal arguments.
935796c8dcSSimon Schubert We need to use them but we'd better to use the common prototype.
945796c8dcSSimon Schubert In fopen-vms.h, they are separated from the mode with a comma.
955796c8dcSSimon Schubert Split here. */
965796c8dcSSimon Schubert vms_attr = strchr (modes, ',');
975796c8dcSSimon Schubert if (vms_attr == NULL)
985796c8dcSSimon Schubert {
995796c8dcSSimon Schubert /* No attributes. */
1005796c8dcSSimon Schubert return close_on_exec (fopen (filename, modes));
1015796c8dcSSimon Schubert }
1025796c8dcSSimon Schubert else
1035796c8dcSSimon Schubert {
1045796c8dcSSimon Schubert /* Attributes found. Split. */
1055796c8dcSSimon Schubert size_t modes_len = strlen (modes) + 1;
1065796c8dcSSimon Schubert char attrs[modes_len + 1];
1075796c8dcSSimon Schubert char *at[3];
1085796c8dcSSimon Schubert int i;
1095796c8dcSSimon Schubert
1105796c8dcSSimon Schubert memcpy (attrs, modes, modes_len);
1115796c8dcSSimon Schubert at[0] = attrs;
1125796c8dcSSimon Schubert for (i = 0; i < 2; i++)
1135796c8dcSSimon Schubert {
1145796c8dcSSimon Schubert at[i + 1] = strchr (at[i], ',');
1155796c8dcSSimon Schubert BFD_ASSERT (at[i + 1] != NULL);
1165796c8dcSSimon Schubert *(at[i + 1]++) = 0; /* Replace ',' with a nul, and skip it. */
1175796c8dcSSimon Schubert }
1185796c8dcSSimon Schubert return close_on_exec (fopen (filename, at[0], at[1], at[2]));
1195796c8dcSSimon Schubert }
1205796c8dcSSimon Schubert #else /* !VMS */
1215796c8dcSSimon Schubert #if defined (HAVE_FOPEN64)
1225796c8dcSSimon Schubert return close_on_exec (fopen64 (filename, modes));
1235796c8dcSSimon Schubert #else
1245796c8dcSSimon Schubert return close_on_exec (fopen (filename, modes));
1255796c8dcSSimon Schubert #endif
1265796c8dcSSimon Schubert #endif /* !VMS */
1275796c8dcSSimon Schubert }
1285796c8dcSSimon Schubert
1295796c8dcSSimon Schubert /*
1305796c8dcSSimon Schubert INTERNAL_DEFINITION
1315796c8dcSSimon Schubert struct bfd_iovec
1325796c8dcSSimon Schubert
1335796c8dcSSimon Schubert DESCRIPTION
1345796c8dcSSimon Schubert
1355796c8dcSSimon Schubert The <<struct bfd_iovec>> contains the internal file I/O class.
1365796c8dcSSimon Schubert Each <<BFD>> has an instance of this class and all file I/O is
1375796c8dcSSimon Schubert routed through it (it is assumed that the instance implements
1385796c8dcSSimon Schubert all methods listed below).
1395796c8dcSSimon Schubert
1405796c8dcSSimon Schubert .struct bfd_iovec
1415796c8dcSSimon Schubert .{
1425796c8dcSSimon Schubert . {* To avoid problems with macros, a "b" rather than "f"
1435796c8dcSSimon Schubert . prefix is prepended to each method name. *}
1445796c8dcSSimon Schubert . {* Attempt to read/write NBYTES on ABFD's IOSTREAM storing/fetching
1455796c8dcSSimon Schubert . bytes starting at PTR. Return the number of bytes actually
1465796c8dcSSimon Schubert . transfered (a read past end-of-file returns less than NBYTES),
1475796c8dcSSimon Schubert . or -1 (setting <<bfd_error>>) if an error occurs. *}
1485796c8dcSSimon Schubert . file_ptr (*bread) (struct bfd *abfd, void *ptr, file_ptr nbytes);
1495796c8dcSSimon Schubert . file_ptr (*bwrite) (struct bfd *abfd, const void *ptr,
1505796c8dcSSimon Schubert . file_ptr nbytes);
1515796c8dcSSimon Schubert . {* Return the current IOSTREAM file offset, or -1 (setting <<bfd_error>>
1525796c8dcSSimon Schubert . if an error occurs. *}
1535796c8dcSSimon Schubert . file_ptr (*btell) (struct bfd *abfd);
1545796c8dcSSimon Schubert . {* For the following, on successful completion a value of 0 is returned.
1555796c8dcSSimon Schubert . Otherwise, a value of -1 is returned (and <<bfd_error>> is set). *}
1565796c8dcSSimon Schubert . int (*bseek) (struct bfd *abfd, file_ptr offset, int whence);
1575796c8dcSSimon Schubert . int (*bclose) (struct bfd *abfd);
1585796c8dcSSimon Schubert . int (*bflush) (struct bfd *abfd);
1595796c8dcSSimon Schubert . int (*bstat) (struct bfd *abfd, struct stat *sb);
160a45ae5f8SJohn Marino . {* Mmap a part of the files. ADDR, LEN, PROT, FLAGS and OFFSET are the usual
161a45ae5f8SJohn Marino . mmap parameter, except that LEN and OFFSET do not need to be page
162a45ae5f8SJohn Marino . aligned. Returns (void *)-1 on failure, mmapped address on success.
163a45ae5f8SJohn Marino . Also write in MAP_ADDR the address of the page aligned buffer and in
164a45ae5f8SJohn Marino . MAP_LEN the size mapped (a page multiple). Use unmap with MAP_ADDR and
165a45ae5f8SJohn Marino . MAP_LEN to unmap. *}
1665796c8dcSSimon Schubert . void *(*bmmap) (struct bfd *abfd, void *addr, bfd_size_type len,
167a45ae5f8SJohn Marino . int prot, int flags, file_ptr offset,
168a45ae5f8SJohn Marino . void **map_addr, bfd_size_type *map_len);
1695796c8dcSSimon Schubert .};
1705796c8dcSSimon Schubert
171cf7f2e2dSJohn Marino .extern const struct bfd_iovec _bfd_memory_iovec;
172cf7f2e2dSJohn Marino
1735796c8dcSSimon Schubert */
1745796c8dcSSimon Schubert
1755796c8dcSSimon Schubert
1765796c8dcSSimon Schubert /* Return value is amount read. */
1775796c8dcSSimon Schubert
1785796c8dcSSimon Schubert bfd_size_type
bfd_bread(void * ptr,bfd_size_type size,bfd * abfd)1795796c8dcSSimon Schubert bfd_bread (void *ptr, bfd_size_type size, bfd *abfd)
1805796c8dcSSimon Schubert {
1815796c8dcSSimon Schubert size_t nread;
1825796c8dcSSimon Schubert
1835796c8dcSSimon Schubert /* If this is an archive element, don't read past the end of
1845796c8dcSSimon Schubert this element. */
1855796c8dcSSimon Schubert if (abfd->arelt_data != NULL)
1865796c8dcSSimon Schubert {
187*ef5ccd6cSJohn Marino bfd_size_type maxbytes = arelt_size (abfd);
188*ef5ccd6cSJohn Marino
189cf7f2e2dSJohn Marino if (abfd->where + size > maxbytes)
1905796c8dcSSimon Schubert {
191cf7f2e2dSJohn Marino if (abfd->where >= maxbytes)
192cf7f2e2dSJohn Marino return 0;
193cf7f2e2dSJohn Marino size = maxbytes - abfd->where;
1945796c8dcSSimon Schubert }
1955796c8dcSSimon Schubert }
1965796c8dcSSimon Schubert
1975796c8dcSSimon Schubert if (abfd->iovec)
1985796c8dcSSimon Schubert nread = abfd->iovec->bread (abfd, ptr, size);
1995796c8dcSSimon Schubert else
2005796c8dcSSimon Schubert nread = 0;
2015796c8dcSSimon Schubert if (nread != (size_t) -1)
2025796c8dcSSimon Schubert abfd->where += nread;
2035796c8dcSSimon Schubert
2045796c8dcSSimon Schubert return nread;
2055796c8dcSSimon Schubert }
2065796c8dcSSimon Schubert
2075796c8dcSSimon Schubert bfd_size_type
bfd_bwrite(const void * ptr,bfd_size_type size,bfd * abfd)2085796c8dcSSimon Schubert bfd_bwrite (const void *ptr, bfd_size_type size, bfd *abfd)
2095796c8dcSSimon Schubert {
2105796c8dcSSimon Schubert size_t nwrote;
2115796c8dcSSimon Schubert
2125796c8dcSSimon Schubert if (abfd->iovec)
2135796c8dcSSimon Schubert nwrote = abfd->iovec->bwrite (abfd, ptr, size);
2145796c8dcSSimon Schubert else
2155796c8dcSSimon Schubert nwrote = 0;
2165796c8dcSSimon Schubert
2175796c8dcSSimon Schubert if (nwrote != (size_t) -1)
2185796c8dcSSimon Schubert abfd->where += nwrote;
2195796c8dcSSimon Schubert if (nwrote != size)
2205796c8dcSSimon Schubert {
2215796c8dcSSimon Schubert #ifdef ENOSPC
2225796c8dcSSimon Schubert errno = ENOSPC;
2235796c8dcSSimon Schubert #endif
2245796c8dcSSimon Schubert bfd_set_error (bfd_error_system_call);
2255796c8dcSSimon Schubert }
2265796c8dcSSimon Schubert return nwrote;
2275796c8dcSSimon Schubert }
2285796c8dcSSimon Schubert
2295796c8dcSSimon Schubert file_ptr
bfd_tell(bfd * abfd)2305796c8dcSSimon Schubert bfd_tell (bfd *abfd)
2315796c8dcSSimon Schubert {
2325796c8dcSSimon Schubert file_ptr ptr;
2335796c8dcSSimon Schubert
2345796c8dcSSimon Schubert if (abfd->iovec)
2355796c8dcSSimon Schubert {
236*ef5ccd6cSJohn Marino bfd *parent_bfd = abfd;
2375796c8dcSSimon Schubert ptr = abfd->iovec->btell (abfd);
2385796c8dcSSimon Schubert
239*ef5ccd6cSJohn Marino while (parent_bfd->my_archive != NULL)
240*ef5ccd6cSJohn Marino {
241*ef5ccd6cSJohn Marino ptr -= parent_bfd->origin;
242*ef5ccd6cSJohn Marino parent_bfd = parent_bfd->my_archive;
243*ef5ccd6cSJohn Marino }
2445796c8dcSSimon Schubert }
2455796c8dcSSimon Schubert else
2465796c8dcSSimon Schubert ptr = 0;
2475796c8dcSSimon Schubert
2485796c8dcSSimon Schubert abfd->where = ptr;
2495796c8dcSSimon Schubert return ptr;
2505796c8dcSSimon Schubert }
2515796c8dcSSimon Schubert
2525796c8dcSSimon Schubert int
bfd_flush(bfd * abfd)2535796c8dcSSimon Schubert bfd_flush (bfd *abfd)
2545796c8dcSSimon Schubert {
2555796c8dcSSimon Schubert if (abfd->iovec)
2565796c8dcSSimon Schubert return abfd->iovec->bflush (abfd);
2575796c8dcSSimon Schubert return 0;
2585796c8dcSSimon Schubert }
2595796c8dcSSimon Schubert
2605796c8dcSSimon Schubert /* Returns 0 for success, negative value for failure (in which case
2615796c8dcSSimon Schubert bfd_get_error can retrieve the error code). */
2625796c8dcSSimon Schubert int
bfd_stat(bfd * abfd,struct stat * statbuf)2635796c8dcSSimon Schubert bfd_stat (bfd *abfd, struct stat *statbuf)
2645796c8dcSSimon Schubert {
2655796c8dcSSimon Schubert int result;
2665796c8dcSSimon Schubert
2675796c8dcSSimon Schubert if (abfd->iovec)
2685796c8dcSSimon Schubert result = abfd->iovec->bstat (abfd, statbuf);
2695796c8dcSSimon Schubert else
2705796c8dcSSimon Schubert result = -1;
2715796c8dcSSimon Schubert
2725796c8dcSSimon Schubert if (result < 0)
2735796c8dcSSimon Schubert bfd_set_error (bfd_error_system_call);
2745796c8dcSSimon Schubert return result;
2755796c8dcSSimon Schubert }
2765796c8dcSSimon Schubert
2775796c8dcSSimon Schubert /* Returns 0 for success, nonzero for failure (in which case bfd_get_error
2785796c8dcSSimon Schubert can retrieve the error code). */
2795796c8dcSSimon Schubert
2805796c8dcSSimon Schubert int
bfd_seek(bfd * abfd,file_ptr position,int direction)2815796c8dcSSimon Schubert bfd_seek (bfd *abfd, file_ptr position, int direction)
2825796c8dcSSimon Schubert {
2835796c8dcSSimon Schubert int result;
2845796c8dcSSimon Schubert file_ptr file_position;
2855796c8dcSSimon Schubert /* For the time being, a BFD may not seek to it's end. The problem
2865796c8dcSSimon Schubert is that we don't easily have a way to recognize the end of an
2875796c8dcSSimon Schubert element in an archive. */
2885796c8dcSSimon Schubert
2895796c8dcSSimon Schubert BFD_ASSERT (direction == SEEK_SET || direction == SEEK_CUR);
2905796c8dcSSimon Schubert
2915796c8dcSSimon Schubert if (direction == SEEK_CUR && position == 0)
2925796c8dcSSimon Schubert return 0;
2935796c8dcSSimon Schubert
2945796c8dcSSimon Schubert if (abfd->format != bfd_archive && abfd->my_archive == 0)
2955796c8dcSSimon Schubert {
2965796c8dcSSimon Schubert if (direction == SEEK_SET && (bfd_vma) position == abfd->where)
2975796c8dcSSimon Schubert return 0;
2985796c8dcSSimon Schubert }
2995796c8dcSSimon Schubert else
3005796c8dcSSimon Schubert {
3015796c8dcSSimon Schubert /* We need something smarter to optimize access to archives.
3025796c8dcSSimon Schubert Currently, anything inside an archive is read via the file
3035796c8dcSSimon Schubert handle for the archive. Which means that a bfd_seek on one
3045796c8dcSSimon Schubert component affects the `current position' in the archive, as
3055796c8dcSSimon Schubert well as in any other component.
3065796c8dcSSimon Schubert
3075796c8dcSSimon Schubert It might be sufficient to put a spike through the cache
3085796c8dcSSimon Schubert abstraction, and look to the archive for the file position,
3095796c8dcSSimon Schubert but I think we should try for something cleaner.
3105796c8dcSSimon Schubert
3115796c8dcSSimon Schubert In the meantime, no optimization for archives. */
3125796c8dcSSimon Schubert }
3135796c8dcSSimon Schubert
3145796c8dcSSimon Schubert file_position = position;
315*ef5ccd6cSJohn Marino if (direction == SEEK_SET)
316*ef5ccd6cSJohn Marino {
317*ef5ccd6cSJohn Marino bfd *parent_bfd = abfd;
318*ef5ccd6cSJohn Marino
319*ef5ccd6cSJohn Marino while (parent_bfd->my_archive != NULL)
320*ef5ccd6cSJohn Marino {
321*ef5ccd6cSJohn Marino file_position += parent_bfd->origin;
322*ef5ccd6cSJohn Marino parent_bfd = parent_bfd->my_archive;
323*ef5ccd6cSJohn Marino }
324*ef5ccd6cSJohn Marino }
3255796c8dcSSimon Schubert
3265796c8dcSSimon Schubert if (abfd->iovec)
3275796c8dcSSimon Schubert result = abfd->iovec->bseek (abfd, file_position, direction);
3285796c8dcSSimon Schubert else
3295796c8dcSSimon Schubert result = -1;
3305796c8dcSSimon Schubert
3315796c8dcSSimon Schubert if (result != 0)
3325796c8dcSSimon Schubert {
3335796c8dcSSimon Schubert int hold_errno = errno;
3345796c8dcSSimon Schubert
3355796c8dcSSimon Schubert /* Force redetermination of `where' field. */
3365796c8dcSSimon Schubert bfd_tell (abfd);
3375796c8dcSSimon Schubert
3385796c8dcSSimon Schubert /* An EINVAL error probably means that the file offset was
3395796c8dcSSimon Schubert absurd. */
3405796c8dcSSimon Schubert if (hold_errno == EINVAL)
3415796c8dcSSimon Schubert bfd_set_error (bfd_error_file_truncated);
3425796c8dcSSimon Schubert else
3435796c8dcSSimon Schubert {
3445796c8dcSSimon Schubert bfd_set_error (bfd_error_system_call);
3455796c8dcSSimon Schubert errno = hold_errno;
3465796c8dcSSimon Schubert }
3475796c8dcSSimon Schubert }
3485796c8dcSSimon Schubert else
3495796c8dcSSimon Schubert {
3505796c8dcSSimon Schubert /* Adjust `where' field. */
3515796c8dcSSimon Schubert if (direction == SEEK_SET)
3525796c8dcSSimon Schubert abfd->where = position;
3535796c8dcSSimon Schubert else
3545796c8dcSSimon Schubert abfd->where += position;
3555796c8dcSSimon Schubert }
3565796c8dcSSimon Schubert return result;
3575796c8dcSSimon Schubert }
3585796c8dcSSimon Schubert
3595796c8dcSSimon Schubert /*
3605796c8dcSSimon Schubert FUNCTION
3615796c8dcSSimon Schubert bfd_get_mtime
3625796c8dcSSimon Schubert
3635796c8dcSSimon Schubert SYNOPSIS
3645796c8dcSSimon Schubert long bfd_get_mtime (bfd *abfd);
3655796c8dcSSimon Schubert
3665796c8dcSSimon Schubert DESCRIPTION
3675796c8dcSSimon Schubert Return the file modification time (as read from the file system, or
3685796c8dcSSimon Schubert from the archive header for archive members).
3695796c8dcSSimon Schubert
3705796c8dcSSimon Schubert */
3715796c8dcSSimon Schubert
3725796c8dcSSimon Schubert long
bfd_get_mtime(bfd * abfd)3735796c8dcSSimon Schubert bfd_get_mtime (bfd *abfd)
3745796c8dcSSimon Schubert {
3755796c8dcSSimon Schubert struct stat buf;
3765796c8dcSSimon Schubert
3775796c8dcSSimon Schubert if (abfd->mtime_set)
3785796c8dcSSimon Schubert return abfd->mtime;
3795796c8dcSSimon Schubert
3805796c8dcSSimon Schubert if (abfd->iovec == NULL)
3815796c8dcSSimon Schubert return 0;
3825796c8dcSSimon Schubert
3835796c8dcSSimon Schubert if (abfd->iovec->bstat (abfd, &buf) != 0)
3845796c8dcSSimon Schubert return 0;
3855796c8dcSSimon Schubert
3865796c8dcSSimon Schubert abfd->mtime = buf.st_mtime; /* Save value in case anyone wants it */
3875796c8dcSSimon Schubert return buf.st_mtime;
3885796c8dcSSimon Schubert }
3895796c8dcSSimon Schubert
3905796c8dcSSimon Schubert /*
3915796c8dcSSimon Schubert FUNCTION
3925796c8dcSSimon Schubert bfd_get_size
3935796c8dcSSimon Schubert
3945796c8dcSSimon Schubert SYNOPSIS
3955796c8dcSSimon Schubert file_ptr bfd_get_size (bfd *abfd);
3965796c8dcSSimon Schubert
3975796c8dcSSimon Schubert DESCRIPTION
3985796c8dcSSimon Schubert Return the file size (as read from file system) for the file
3995796c8dcSSimon Schubert associated with BFD @var{abfd}.
4005796c8dcSSimon Schubert
4015796c8dcSSimon Schubert The initial motivation for, and use of, this routine is not
4025796c8dcSSimon Schubert so we can get the exact size of the object the BFD applies to, since
4035796c8dcSSimon Schubert that might not be generally possible (archive members for example).
4045796c8dcSSimon Schubert It would be ideal if someone could eventually modify
4055796c8dcSSimon Schubert it so that such results were guaranteed.
4065796c8dcSSimon Schubert
4075796c8dcSSimon Schubert Instead, we want to ask questions like "is this NNN byte sized
4085796c8dcSSimon Schubert object I'm about to try read from file offset YYY reasonable?"
4095796c8dcSSimon Schubert As as example of where we might do this, some object formats
4105796c8dcSSimon Schubert use string tables for which the first <<sizeof (long)>> bytes of the
4115796c8dcSSimon Schubert table contain the size of the table itself, including the size bytes.
4125796c8dcSSimon Schubert If an application tries to read what it thinks is one of these
4135796c8dcSSimon Schubert string tables, without some way to validate the size, and for
4145796c8dcSSimon Schubert some reason the size is wrong (byte swapping error, wrong location
4155796c8dcSSimon Schubert for the string table, etc.), the only clue is likely to be a read
4165796c8dcSSimon Schubert error when it tries to read the table, or a "virtual memory
4175796c8dcSSimon Schubert exhausted" error when it tries to allocate 15 bazillon bytes
4185796c8dcSSimon Schubert of space for the 15 bazillon byte table it is about to read.
4195796c8dcSSimon Schubert This function at least allows us to answer the question, "is the
4205796c8dcSSimon Schubert size reasonable?".
4215796c8dcSSimon Schubert */
4225796c8dcSSimon Schubert
4235796c8dcSSimon Schubert file_ptr
bfd_get_size(bfd * abfd)4245796c8dcSSimon Schubert bfd_get_size (bfd *abfd)
4255796c8dcSSimon Schubert {
4265796c8dcSSimon Schubert struct stat buf;
4275796c8dcSSimon Schubert
4285796c8dcSSimon Schubert if (abfd->iovec == NULL)
4295796c8dcSSimon Schubert return 0;
4305796c8dcSSimon Schubert
4315796c8dcSSimon Schubert if (abfd->iovec->bstat (abfd, &buf) != 0)
4325796c8dcSSimon Schubert return 0;
4335796c8dcSSimon Schubert
4345796c8dcSSimon Schubert return buf.st_size;
4355796c8dcSSimon Schubert }
4365796c8dcSSimon Schubert
4375796c8dcSSimon Schubert
4385796c8dcSSimon Schubert /*
4395796c8dcSSimon Schubert FUNCTION
4405796c8dcSSimon Schubert bfd_mmap
4415796c8dcSSimon Schubert
4425796c8dcSSimon Schubert SYNOPSIS
4435796c8dcSSimon Schubert void *bfd_mmap (bfd *abfd, void *addr, bfd_size_type len,
444a45ae5f8SJohn Marino int prot, int flags, file_ptr offset,
445a45ae5f8SJohn Marino void **map_addr, bfd_size_type *map_len);
4465796c8dcSSimon Schubert
4475796c8dcSSimon Schubert DESCRIPTION
4485796c8dcSSimon Schubert Return mmap()ed region of the file, if possible and implemented.
449a45ae5f8SJohn Marino LEN and OFFSET do not need to be page aligned. The page aligned
450a45ae5f8SJohn Marino address and length are written to MAP_ADDR and MAP_LEN.
4515796c8dcSSimon Schubert
4525796c8dcSSimon Schubert */
4535796c8dcSSimon Schubert
4545796c8dcSSimon Schubert void *
bfd_mmap(bfd * abfd,void * addr,bfd_size_type len,int prot,int flags,file_ptr offset,void ** map_addr,bfd_size_type * map_len)4555796c8dcSSimon Schubert bfd_mmap (bfd *abfd, void *addr, bfd_size_type len,
456a45ae5f8SJohn Marino int prot, int flags, file_ptr offset,
457a45ae5f8SJohn Marino void **map_addr, bfd_size_type *map_len)
4585796c8dcSSimon Schubert {
4595796c8dcSSimon Schubert void *ret = (void *)-1;
4605796c8dcSSimon Schubert
4615796c8dcSSimon Schubert if (abfd->iovec == NULL)
4625796c8dcSSimon Schubert return ret;
4635796c8dcSSimon Schubert
464a45ae5f8SJohn Marino return abfd->iovec->bmmap (abfd, addr, len, prot, flags, offset,
465a45ae5f8SJohn Marino map_addr, map_len);
4665796c8dcSSimon Schubert }
467cf7f2e2dSJohn Marino
468cf7f2e2dSJohn Marino /* Memory file I/O operations. */
469cf7f2e2dSJohn Marino
470cf7f2e2dSJohn Marino static file_ptr
memory_bread(bfd * abfd,void * ptr,file_ptr size)471cf7f2e2dSJohn Marino memory_bread (bfd *abfd, void *ptr, file_ptr size)
472cf7f2e2dSJohn Marino {
473cf7f2e2dSJohn Marino struct bfd_in_memory *bim;
474cf7f2e2dSJohn Marino bfd_size_type get;
475cf7f2e2dSJohn Marino
476cf7f2e2dSJohn Marino bim = (struct bfd_in_memory *) abfd->iostream;
477cf7f2e2dSJohn Marino get = size;
478cf7f2e2dSJohn Marino if (abfd->where + get > bim->size)
479cf7f2e2dSJohn Marino {
480cf7f2e2dSJohn Marino if (bim->size < (bfd_size_type) abfd->where)
481cf7f2e2dSJohn Marino get = 0;
482cf7f2e2dSJohn Marino else
483cf7f2e2dSJohn Marino get = bim->size - abfd->where;
484cf7f2e2dSJohn Marino bfd_set_error (bfd_error_file_truncated);
485cf7f2e2dSJohn Marino }
486cf7f2e2dSJohn Marino memcpy (ptr, bim->buffer + abfd->where, (size_t) get);
487cf7f2e2dSJohn Marino return get;
488cf7f2e2dSJohn Marino }
489cf7f2e2dSJohn Marino
490cf7f2e2dSJohn Marino static file_ptr
memory_bwrite(bfd * abfd,const void * ptr,file_ptr size)491cf7f2e2dSJohn Marino memory_bwrite (bfd *abfd, const void *ptr, file_ptr size)
492cf7f2e2dSJohn Marino {
493cf7f2e2dSJohn Marino struct bfd_in_memory *bim = (struct bfd_in_memory *) abfd->iostream;
494cf7f2e2dSJohn Marino
495cf7f2e2dSJohn Marino if (abfd->where + size > bim->size)
496cf7f2e2dSJohn Marino {
497cf7f2e2dSJohn Marino bfd_size_type newsize, oldsize;
498cf7f2e2dSJohn Marino
499cf7f2e2dSJohn Marino oldsize = (bim->size + 127) & ~(bfd_size_type) 127;
500cf7f2e2dSJohn Marino bim->size = abfd->where + size;
501cf7f2e2dSJohn Marino /* Round up to cut down on memory fragmentation */
502cf7f2e2dSJohn Marino newsize = (bim->size + 127) & ~(bfd_size_type) 127;
503cf7f2e2dSJohn Marino if (newsize > oldsize)
504cf7f2e2dSJohn Marino {
505cf7f2e2dSJohn Marino bim->buffer = (bfd_byte *) bfd_realloc_or_free (bim->buffer, newsize);
506cf7f2e2dSJohn Marino if (bim->buffer == NULL)
507cf7f2e2dSJohn Marino {
508cf7f2e2dSJohn Marino bim->size = 0;
509cf7f2e2dSJohn Marino return 0;
510cf7f2e2dSJohn Marino }
511cf7f2e2dSJohn Marino if (newsize > bim->size)
512cf7f2e2dSJohn Marino memset (bim->buffer + bim->size, 0, newsize - bim->size);
513cf7f2e2dSJohn Marino }
514cf7f2e2dSJohn Marino }
515cf7f2e2dSJohn Marino memcpy (bim->buffer + abfd->where, ptr, (size_t) size);
516cf7f2e2dSJohn Marino return size;
517cf7f2e2dSJohn Marino }
518cf7f2e2dSJohn Marino
519cf7f2e2dSJohn Marino static file_ptr
memory_btell(bfd * abfd)520cf7f2e2dSJohn Marino memory_btell (bfd *abfd)
521cf7f2e2dSJohn Marino {
522cf7f2e2dSJohn Marino return abfd->where;
523cf7f2e2dSJohn Marino }
524cf7f2e2dSJohn Marino
525cf7f2e2dSJohn Marino static int
memory_bseek(bfd * abfd,file_ptr position,int direction)526cf7f2e2dSJohn Marino memory_bseek (bfd *abfd, file_ptr position, int direction)
527cf7f2e2dSJohn Marino {
528cf7f2e2dSJohn Marino file_ptr nwhere;
529cf7f2e2dSJohn Marino struct bfd_in_memory *bim;
530cf7f2e2dSJohn Marino
531cf7f2e2dSJohn Marino bim = (struct bfd_in_memory *) abfd->iostream;
532cf7f2e2dSJohn Marino
533cf7f2e2dSJohn Marino if (direction == SEEK_SET)
534cf7f2e2dSJohn Marino nwhere = position;
535cf7f2e2dSJohn Marino else
536cf7f2e2dSJohn Marino nwhere = abfd->where + position;
537cf7f2e2dSJohn Marino
538cf7f2e2dSJohn Marino if (nwhere < 0)
539cf7f2e2dSJohn Marino {
540cf7f2e2dSJohn Marino abfd->where = 0;
541cf7f2e2dSJohn Marino errno = EINVAL;
542cf7f2e2dSJohn Marino return -1;
543cf7f2e2dSJohn Marino }
544cf7f2e2dSJohn Marino
545cf7f2e2dSJohn Marino if ((bfd_size_type)nwhere > bim->size)
546cf7f2e2dSJohn Marino {
547cf7f2e2dSJohn Marino if (abfd->direction == write_direction
548cf7f2e2dSJohn Marino || abfd->direction == both_direction)
549cf7f2e2dSJohn Marino {
550cf7f2e2dSJohn Marino bfd_size_type newsize, oldsize;
551cf7f2e2dSJohn Marino
552cf7f2e2dSJohn Marino oldsize = (bim->size + 127) & ~(bfd_size_type) 127;
553cf7f2e2dSJohn Marino bim->size = nwhere;
554cf7f2e2dSJohn Marino /* Round up to cut down on memory fragmentation */
555cf7f2e2dSJohn Marino newsize = (bim->size + 127) & ~(bfd_size_type) 127;
556cf7f2e2dSJohn Marino if (newsize > oldsize)
557cf7f2e2dSJohn Marino {
558cf7f2e2dSJohn Marino bim->buffer = (bfd_byte *) bfd_realloc_or_free (bim->buffer, newsize);
559cf7f2e2dSJohn Marino if (bim->buffer == NULL)
560cf7f2e2dSJohn Marino {
561cf7f2e2dSJohn Marino errno = EINVAL;
562cf7f2e2dSJohn Marino bim->size = 0;
563cf7f2e2dSJohn Marino return -1;
564cf7f2e2dSJohn Marino }
565cf7f2e2dSJohn Marino memset (bim->buffer + oldsize, 0, newsize - oldsize);
566cf7f2e2dSJohn Marino }
567cf7f2e2dSJohn Marino }
568cf7f2e2dSJohn Marino else
569cf7f2e2dSJohn Marino {
570cf7f2e2dSJohn Marino abfd->where = bim->size;
571cf7f2e2dSJohn Marino errno = EINVAL;
572cf7f2e2dSJohn Marino bfd_set_error (bfd_error_file_truncated);
573cf7f2e2dSJohn Marino return -1;
574cf7f2e2dSJohn Marino }
575cf7f2e2dSJohn Marino }
576cf7f2e2dSJohn Marino return 0;
577cf7f2e2dSJohn Marino }
578cf7f2e2dSJohn Marino
579cf7f2e2dSJohn Marino static int
memory_bclose(struct bfd * abfd)580cf7f2e2dSJohn Marino memory_bclose (struct bfd *abfd)
581cf7f2e2dSJohn Marino {
582cf7f2e2dSJohn Marino struct bfd_in_memory *bim = (struct bfd_in_memory *) abfd->iostream;
583cf7f2e2dSJohn Marino
584cf7f2e2dSJohn Marino if (bim->buffer != NULL)
585cf7f2e2dSJohn Marino free (bim->buffer);
586cf7f2e2dSJohn Marino free (bim);
587cf7f2e2dSJohn Marino abfd->iostream = NULL;
588cf7f2e2dSJohn Marino
589*ef5ccd6cSJohn Marino return 0;
590cf7f2e2dSJohn Marino }
591cf7f2e2dSJohn Marino
592cf7f2e2dSJohn Marino static int
memory_bflush(bfd * abfd ATTRIBUTE_UNUSED)593cf7f2e2dSJohn Marino memory_bflush (bfd *abfd ATTRIBUTE_UNUSED)
594cf7f2e2dSJohn Marino {
595cf7f2e2dSJohn Marino return 0;
596cf7f2e2dSJohn Marino }
597cf7f2e2dSJohn Marino
598cf7f2e2dSJohn Marino static int
memory_bstat(bfd * abfd,struct stat * statbuf)599cf7f2e2dSJohn Marino memory_bstat (bfd *abfd, struct stat *statbuf)
600cf7f2e2dSJohn Marino {
601cf7f2e2dSJohn Marino struct bfd_in_memory *bim = (struct bfd_in_memory *) abfd->iostream;
602cf7f2e2dSJohn Marino
603a45ae5f8SJohn Marino memset (statbuf, 0, sizeof (*statbuf));
604cf7f2e2dSJohn Marino statbuf->st_size = bim->size;
605cf7f2e2dSJohn Marino
606cf7f2e2dSJohn Marino return 0;
607cf7f2e2dSJohn Marino }
608cf7f2e2dSJohn Marino
609cf7f2e2dSJohn Marino static void *
memory_bmmap(bfd * abfd ATTRIBUTE_UNUSED,void * addr ATTRIBUTE_UNUSED,bfd_size_type len ATTRIBUTE_UNUSED,int prot ATTRIBUTE_UNUSED,int flags ATTRIBUTE_UNUSED,file_ptr offset ATTRIBUTE_UNUSED,void ** map_addr ATTRIBUTE_UNUSED,bfd_size_type * map_len ATTRIBUTE_UNUSED)610cf7f2e2dSJohn Marino memory_bmmap (bfd *abfd ATTRIBUTE_UNUSED, void *addr ATTRIBUTE_UNUSED,
611cf7f2e2dSJohn Marino bfd_size_type len ATTRIBUTE_UNUSED, int prot ATTRIBUTE_UNUSED,
612a45ae5f8SJohn Marino int flags ATTRIBUTE_UNUSED, file_ptr offset ATTRIBUTE_UNUSED,
613a45ae5f8SJohn Marino void **map_addr ATTRIBUTE_UNUSED,
614a45ae5f8SJohn Marino bfd_size_type *map_len ATTRIBUTE_UNUSED)
615cf7f2e2dSJohn Marino {
616cf7f2e2dSJohn Marino return (void *)-1;
617cf7f2e2dSJohn Marino }
618cf7f2e2dSJohn Marino
619cf7f2e2dSJohn Marino const struct bfd_iovec _bfd_memory_iovec =
620cf7f2e2dSJohn Marino {
621cf7f2e2dSJohn Marino &memory_bread, &memory_bwrite, &memory_btell, &memory_bseek,
622cf7f2e2dSJohn Marino &memory_bclose, &memory_bflush, &memory_bstat, &memory_bmmap
623cf7f2e2dSJohn Marino };
624