/* Low-level I/O routines for BFDs.
- Copyright (C) 1990-2020 Free Software Foundation, Inc.
+ Copyright (C) 1990-2023 Free Software Foundation, Inc.
Written by Cygnus Support.
#include <limits.h>
#include "bfd.h"
#include "libbfd.h"
+#include "aout/ar.h"
+#if defined (_WIN32)
+#include <windows.h>
+#include <locale.h>
+#endif
#ifndef S_IXUSR
#define S_IXUSR 0100 /* Execute by owner. */
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;
}
return close_on_exec (fopen (filename, at[0], at[1], at[2]));
}
-#else /* !VMS */
-#if defined (HAVE_FOPEN64)
+
+#elif defined (_WIN32)
+ /* PR 25713: Handle extra long path names possibly containing '..' and '.'. */
+ wchar_t ** lpFilePart = {NULL};
+ const wchar_t prefix[] = L"\\\\?\\";
+ const size_t partPathLen = strlen (filename) + 1;
+#ifdef __MINGW32__
+#if !HAVE_DECL____LC_CODEPAGE_FUNC
+/* This prototype was added to locale.h in version 9.0 of MinGW-w64. */
+ _CRTIMP unsigned int __cdecl ___lc_codepage_func (void);
+#endif
+ const unsigned int cp = ___lc_codepage_func ();
+#else
+ const unsigned int cp = CP_UTF8;
+#endif
+
+ /* Converting the partial path from ascii to unicode.
+ 1) Get the length: Calling with lpWideCharStr set to null returns the length.
+ 2) Convert the string: Calling with cbMultiByte set to -1 includes the terminating null. */
+ size_t partPathWSize = MultiByteToWideChar (cp, 0, filename, -1, NULL, 0);
+ wchar_t * partPath = calloc (partPathWSize, sizeof(wchar_t));
+ size_t ix;
+
+ MultiByteToWideChar (cp, 0, filename, -1, partPath, partPathWSize);
+
+ /* Convert any UNIX style path separators into the DOS i.e. backslash separator. */
+ for (ix = 0; ix < partPathLen; ix++)
+ if (IS_UNIX_DIR_SEPARATOR(filename[ix]))
+ partPath[ix] = '\\';
+
+ /* Getting the full path from the provided partial path.
+ 1) Get the length.
+ 2) Resolve the path. */
+ long fullPathWSize = GetFullPathNameW (partPath, 0, NULL, lpFilePart);
+ wchar_t * fullPath = calloc (fullPathWSize + sizeof(prefix) + 1, sizeof(wchar_t));
+
+ wcscpy (fullPath, prefix);
+
+ int prefixLen = sizeof(prefix) / sizeof(wchar_t);
+ wchar_t * fullPathOffset = fullPath + prefixLen - 1;
+
+ GetFullPathNameW (partPath, fullPathWSize, fullPathOffset, lpFilePart);
+ free (partPath);
+
+ /* It is non-standard for modes to exceed 16 characters. */
+ wchar_t modesW[16];
+
+ MultiByteToWideChar (cp, 0, modes, -1, modesW, sizeof(modesW));
+
+ FILE * file = _wfopen (fullPath, modesW);
+ free (fullPath);
+
+ return close_on_exec (file);
+
+#elif defined (HAVE_FOPEN64)
return close_on_exec (fopen64 (filename, modes));
+
#else
return close_on_exec (fopen (filename, modes));
#endif
-#endif /* !VMS */
}
/*
offset += abfd->origin;
abfd = abfd->my_archive;
}
+ offset += abfd->origin;
- /* If this is an archive element, don't read past the end of
+ /* If this is a non-thin archive element, don't read past the end of
this element. */
- if (element_bfd->arelt_data != NULL)
+ if (element_bfd->arelt_data != NULL
+ && element_bfd->my_archive != NULL
+ && !bfd_is_thin_archive (element_bfd->my_archive))
{
bfd_size_type maxbytes = arelt_size (element_bfd);
offset += abfd->origin;
abfd = abfd->my_archive;
}
+ offset += abfd->origin;
if (abfd->iovec == NULL)
return 0;
offset += abfd->origin;
abfd = abfd->my_archive;
}
+ offset += abfd->origin;
if (abfd->iovec == NULL)
{
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;
+ /* 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 (bfd_stat (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;
}
/*
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;
+ if (adata != NULL)
+ {
+ 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;
}
/*
offset += abfd->origin;
abfd = abfd->my_archive;
}
+ offset += abfd->origin;
if (abfd->iovec == NULL)
{
{
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;