X-Git-Url: http://drtracing.org/?a=blobdiff_plain;f=bfd%2Fbfdio.c;h=5f144bc7f3fee833ff97924ec8f2e3eec37364b9;hb=ebe84f23d2f3c0cb145cc7b3acfb011a4c7df1c9;hp=13c6a5e549a6294ad7fa2fe7d87376c437191c8a;hpb=07d6d2b8345ef3dc82eab49635acac9ee67dbb18;p=deliverable%2Fbinutils-gdb.git diff --git a/bfd/bfdio.c b/bfd/bfdio.c index 13c6a5e549..5f144bc7f3 100644 --- a/bfd/bfdio.c +++ b/bfd/bfdio.c @@ -1,6 +1,6 @@ /* Low-level I/O routines for BFDs. - Copyright (C) 1990-2017 Free Software Foundation, Inc. + Copyright (C) 1990-2020 Free Software Foundation, Inc. Written by Cygnus Support. @@ -25,6 +25,10 @@ #include #include "bfd.h" #include "libbfd.h" +#include "aout/ar.h" +#if defined (_WIN32) +#include +#endif #ifndef S_IXUSR #define S_IXUSR 0100 /* Execute by owner. */ @@ -92,12 +96,7 @@ _bfd_real_fopen (const char *filename, const char *modes) In fopen-vms.h, they are separated from the mode with a comma. Split here. */ vms_attr = strchr (modes, ','); - if (vms_attr == NULL) - { - /* No attributes. */ - return close_on_exec (fopen (filename, modes)); - } - else + if (vms_attr != NULL) { /* Attributes found. Split. */ size_t modes_len = strlen (modes) + 1; @@ -115,13 +114,38 @@ _bfd_real_fopen (const char *filename, const char *modes) } return close_on_exec (fopen (filename, at[0], at[1], at[2])); } -#else /* !VMS */ -#if defined (HAVE_FOPEN64) + +#elif defined (_WIN32) + size_t filelen = strlen (filename) + 1; + + if (filelen > MAX_PATH - 1) + { + FILE * file; + char * fullpath = (char *) malloc (filelen + 8); + int i; + + /* Add a Microsoft recommended prefix that + will allow the extra-long path to work. */ + strcpy (fullpath, "\\\\?\\"); + strcat (fullpath, filename); + + /* Convert any UNIX style path separators into the DOS form. */ + for (i = 0; fullpath[i]; i++) + { + if (IS_UNIX_DIR_SEPARATOR (fullpath[i])) + fullpath[i] = '\\'; + } + + file = close_on_exec (fopen (fullpath, modes)); + free (fullpath); + return file; + } + +#elif defined (HAVE_FOPEN64) return close_on_exec (fopen64 (filename, modes)); -#else - return close_on_exec (fopen (filename, modes)); #endif -#endif /* !VMS */ + + return close_on_exec (fopen (filename, modes)); } /* @@ -176,27 +200,41 @@ DESCRIPTION bfd_size_type bfd_bread (void *ptr, bfd_size_type size, bfd *abfd) { - size_t nread; + file_ptr nread; + bfd *element_bfd = abfd; + ufile_ptr offset = 0; + + while (abfd->my_archive != NULL + && !bfd_is_thin_archive (abfd->my_archive)) + { + offset += abfd->origin; + abfd = abfd->my_archive; + } + offset += abfd->origin; /* If this is an archive element, don't read past the end of this element. */ - if (abfd->arelt_data != NULL) + if (element_bfd->arelt_data != NULL) { - bfd_size_type maxbytes = arelt_size (abfd); + bfd_size_type maxbytes = arelt_size (element_bfd); - if (abfd->where + size > maxbytes) + if (abfd->where < offset || abfd->where - offset >= maxbytes) { - if (abfd->where >= maxbytes) - return 0; - size = maxbytes - abfd->where; + bfd_set_error (bfd_error_invalid_operation); + return -1; } + if (abfd->where - offset + size > maxbytes) + size = maxbytes - (abfd->where - offset); } - if (abfd->iovec) - nread = abfd->iovec->bread (abfd, ptr, size); - else - nread = 0; - if (nread != (size_t) -1) + if (abfd->iovec == NULL) + { + bfd_set_error (bfd_error_invalid_operation); + return -1; + } + + nread = abfd->iovec->bread (abfd, ptr, size); + if (nread != -1) abfd->where += nread; return nread; @@ -205,16 +243,22 @@ bfd_bread (void *ptr, bfd_size_type size, bfd *abfd) bfd_size_type bfd_bwrite (const void *ptr, bfd_size_type size, bfd *abfd) { - size_t nwrote; + file_ptr nwrote; - if (abfd->iovec) - nwrote = abfd->iovec->bwrite (abfd, ptr, size); - else - nwrote = 0; + while (abfd->my_archive != NULL + && !bfd_is_thin_archive (abfd->my_archive)) + abfd = abfd->my_archive; - if (nwrote != (size_t) -1) + if (abfd->iovec == NULL) + { + bfd_set_error (bfd_error_invalid_operation); + return -1; + } + + nwrote = abfd->iovec->bwrite (abfd, ptr, size); + if (nwrote != -1) abfd->where += nwrote; - if (nwrote != size) + if ((bfd_size_type) nwrote != size) { #ifdef ENOSPC errno = ENOSPC; @@ -227,33 +271,36 @@ bfd_bwrite (const void *ptr, bfd_size_type size, bfd *abfd) file_ptr bfd_tell (bfd *abfd) { + ufile_ptr offset = 0; file_ptr ptr; - if (abfd->iovec) + while (abfd->my_archive != NULL + && !bfd_is_thin_archive (abfd->my_archive)) { - bfd *parent_bfd = abfd; - ptr = abfd->iovec->btell (abfd); - - while (parent_bfd->my_archive != NULL - && !bfd_is_thin_archive (parent_bfd->my_archive)) - { - ptr -= parent_bfd->origin; - parent_bfd = parent_bfd->my_archive; - } + offset += abfd->origin; + abfd = abfd->my_archive; } - else - ptr = 0; + offset += abfd->origin; + if (abfd->iovec == NULL) + return 0; + + ptr = abfd->iovec->btell (abfd); abfd->where = ptr; - return ptr; + return ptr - offset; } int bfd_flush (bfd *abfd) { - if (abfd->iovec) - return abfd->iovec->bflush (abfd); - return 0; + while (abfd->my_archive != NULL + && !bfd_is_thin_archive (abfd->my_archive)) + abfd = abfd->my_archive; + + if (abfd->iovec == NULL) + return 0; + + return abfd->iovec->bflush (abfd); } /* Returns 0 for success, negative value for failure (in which case @@ -263,11 +310,17 @@ bfd_stat (bfd *abfd, struct stat *statbuf) { int result; - if (abfd->iovec) - result = abfd->iovec->bstat (abfd, statbuf); - else - result = -1; + while (abfd->my_archive != NULL + && !bfd_is_thin_archive (abfd->my_archive)) + abfd = abfd->my_archive; + + if (abfd->iovec == NULL) + { + bfd_set_error (bfd_error_invalid_operation); + return -1; + } + result = abfd->iovec->bstat (abfd, statbuf); if (result < 0) bfd_set_error (bfd_error_system_call); return result; @@ -280,79 +333,53 @@ int bfd_seek (bfd *abfd, file_ptr position, int direction) { int result; - file_ptr file_position; - /* For the time being, a BFD may not seek to it's end. The problem - is that we don't easily have a way to recognize the end of an - element in an archive. */ - - BFD_ASSERT (direction == SEEK_SET || direction == SEEK_CUR); - - if (direction == SEEK_CUR && position == 0) - return 0; + ufile_ptr offset = 0; - if (abfd->my_archive == NULL || bfd_is_thin_archive (abfd->my_archive)) + while (abfd->my_archive != NULL + && !bfd_is_thin_archive (abfd->my_archive)) { - if (direction == SEEK_SET && (bfd_vma) position == abfd->where) - return 0; + offset += abfd->origin; + abfd = abfd->my_archive; } - else - { - /* We need something smarter to optimize access to archives. - Currently, anything inside an archive is read via the file - handle for the archive. Which means that a bfd_seek on one - component affects the `current position' in the archive, as - well as in any other component. - - It might be sufficient to put a spike through the cache - abstraction, and look to the archive for the file position, - but I think we should try for something cleaner. + offset += abfd->origin; - In the meantime, no optimization for archives. */ + if (abfd->iovec == NULL) + { + bfd_set_error (bfd_error_invalid_operation); + return -1; } - file_position = position; - if (direction == SEEK_SET) - { - bfd *parent_bfd = abfd; + /* For the time being, a BFD may not seek to it's end. The problem + is that we don't easily have a way to recognize the end of an + element in an archive. */ + BFD_ASSERT (direction == SEEK_SET || direction == SEEK_CUR); - while (parent_bfd->my_archive != NULL - && !bfd_is_thin_archive (parent_bfd->my_archive)) - { - file_position += parent_bfd->origin; - parent_bfd = parent_bfd->my_archive; - } - } + if (direction != SEEK_CUR) + position += offset; - if (abfd->iovec) - result = abfd->iovec->bseek (abfd, file_position, direction); - else - result = -1; + if ((direction == SEEK_CUR && position == 0) + || (direction == SEEK_SET && (ufile_ptr) position == abfd->where)) + return 0; + result = abfd->iovec->bseek (abfd, position, direction); if (result != 0) { - int hold_errno = errno; - - /* Force redetermination of `where' field. */ - bfd_tell (abfd); - /* An EINVAL error probably means that the file offset was absurd. */ - if (hold_errno == EINVAL) + if (errno == EINVAL) bfd_set_error (bfd_error_file_truncated); else - { - bfd_set_error (bfd_error_system_call); - errno = hold_errno; - } + bfd_set_error (bfd_error_system_call); } else { /* Adjust `where' field. */ - if (direction == SEEK_SET) - abfd->where = position; - else + if (direction == SEEK_CUR) abfd->where += position; + else + abfd->where = position; } + return result; } @@ -377,10 +404,7 @@ bfd_get_mtime (bfd *abfd) if (abfd->mtime_set) return abfd->mtime; - if (abfd->iovec == NULL) - return 0; - - if (abfd->iovec->bstat (abfd, &buf) != 0) + if (bfd_stat (abfd, &buf) != 0) return 0; abfd->mtime = buf.st_mtime; /* Save value in case anyone wants it */ @@ -418,20 +442,32 @@ DESCRIPTION of space for the 15 bazillon byte table it is about to read. This function at least allows us to answer the question, "is the size reasonable?". + + A return value of zero indicates the file size is unknown. */ ufile_ptr bfd_get_size (bfd *abfd) { - struct stat buf; - - if (abfd->iovec == NULL) - return 0; + /* A size of 0 means we haven't yet called bfd_stat. A size of 1 + means we have a cached value of 0, ie. unknown. */ + if (abfd->size <= 1 || bfd_write_p (abfd)) + { + struct stat buf; - if (abfd->iovec->bstat (abfd, &buf) != 0) - return 0; + if (abfd->size == 1 && !bfd_write_p (abfd)) + return 0; - return buf.st_size; + if (bfd_stat (abfd, &buf) != 0 + || buf.st_size == 0 + || buf.st_size - (ufile_ptr) buf.st_size != 0) + { + abfd->size = 1; + return 0; + } + abfd->size = buf.st_size; + } + return abfd->size; } /* @@ -451,11 +487,25 @@ DESCRIPTION ufile_ptr bfd_get_file_size (bfd *abfd) { + ufile_ptr file_size, archive_size = (ufile_ptr) -1; + if (abfd->my_archive != NULL && !bfd_is_thin_archive (abfd->my_archive)) - return arelt_size (abfd); + { + struct areltdata *adata = (struct areltdata *) abfd->arelt_data; + archive_size = adata->parsed_size; + /* If the archive is compressed we can't compare against file size. */ + if (adata->arch_header != NULL + && memcmp (((struct ar_hdr *) adata->arch_header)->ar_fmag, + "Z\012", 2) == 0) + return archive_size; + abfd = abfd->my_archive; + } - return bfd_get_size (abfd); + file_size = bfd_get_size (abfd); + if (archive_size < file_size) + return archive_size; + return file_size; } /* @@ -479,10 +529,19 @@ 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) { - void *ret = (void *)-1; + while (abfd->my_archive != NULL + && !bfd_is_thin_archive (abfd->my_archive)) + { + offset += abfd->origin; + abfd = abfd->my_archive; + } + offset += abfd->origin; if (abfd->iovec == NULL) - return ret; + { + bfd_set_error (bfd_error_invalid_operation); + return (void *) -1; + } return abfd->iovec->bmmap (abfd, addr, len, prot, flags, offset, map_addr, map_len); @@ -604,8 +663,7 @@ memory_bclose (struct bfd *abfd) { struct bfd_in_memory *bim = (struct bfd_in_memory *) abfd->iostream; - if (bim->buffer != NULL) - free (bim->buffer); + free (bim->buffer); free (bim); abfd->iostream = NULL;