aboutsummaryrefslogtreecommitdiff
path: root/bfd/bfdio.c
diff options
context:
space:
mode:
Diffstat (limited to 'bfd/bfdio.c')
-rw-r--r--bfd/bfdio.c108
1 files changed, 72 insertions, 36 deletions
diff --git a/bfd/bfdio.c b/bfd/bfdio.c
index 4ed0eea..718cbe8 100644
--- a/bfd/bfdio.c
+++ b/bfd/bfdio.c
@@ -29,6 +29,8 @@
#if defined (_WIN32)
#include <windows.h>
#include <locale.h>
+/* FIXME: Do we need a configure time test for the presence of this headers ? */
+#include <shlwapi.h> /* Needed for PathIsNetworkPathA(). */
#endif
#ifndef S_IXUSR
@@ -118,61 +120,95 @@ _bfd_real_fopen (const char *filename, const char *modes)
#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;
+ wchar_t ** lpFilePart = {NULL};
+ const wchar_t prefixDOS[] = L"\\\\?\\";
+ const wchar_t prefixUNC[] = L"\\\\?\\UNC\\";
+ const size_t partPathLen = strlen (filename) + 1;
+ const wchar_t * prefix;
+ size_t sizeof_prefix;
+
+ /* PR 31527: Paths that begin with two backslash characters
+ (\\) are interpreted as Universal Naming Convention (UNC)
+ paths. They use the "\\?\UNC\" prefix for network UNC paths
+ and the "\\?\" prefix for dos UNC paths. For more information
+ see: https://learn.microsoft.com/en-us/windows/win32/fileio/maximum-file-path-limitation?tabs=registry
+ */
+ bool is_network_path = PathIsNetworkPathA (filename);
+
+ if (is_network_path)
+ {
+ prefix = prefixUNC;
+ sizeof_prefix = sizeof (prefixUNC);
+ }
+ else
+ {
+ prefix = prefixDOS;
+ sizeof_prefix = sizeof (prefixDOS);
+ }
+
#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);
+ /* 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 ();
+ const unsigned int cp = ___lc_codepage_func ();
#else
- const unsigned int cp = CP_UTF8;
+ 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;
+ /* 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);
+ 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] = '\\';
+ /* 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));
+ /* 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);
+ wcscpy (fullPath, prefix);
- int prefixLen = sizeof(prefix) / sizeof(wchar_t);
+ int prefixLen = sizeof_prefix / sizeof(wchar_t);
- /* Do not add a prefix to the null device. */
- if (stricmp (filename, "nul") == 0)
+ /* Do not add a prefix to the null device. */
+ if (stricmp (filename, "nul") == 0)
prefixLen = 1;
- wchar_t * fullPathOffset = fullPath + prefixLen - 1;
+ wchar_t * fullPathOffset = fullPath + prefixLen - 1;
+
+ GetFullPathNameW (partPath, fullPathWSize, fullPathOffset, lpFilePart);
+
+ if (is_network_path)
+ {
+ /* Remove begining of the beginning two backslash characters (\\). */
+ wchar_t *_fullPath = calloc (fullPathWSize + sizeof_prefix + 1, sizeof(wchar_t));
+
+ GetFullPathNameW (fullPath, fullPathWSize + sizeof_prefix + 1, _fullPath, lpFilePart);
+ free (fullPath);
+ fullPath = _fullPath;
+ }
- GetFullPathNameW (partPath, fullPathWSize, fullPathOffset, lpFilePart);
- free (partPath);
+ free (partPath);
- /* It is non-standard for modes to exceed 16 characters. */
- wchar_t modesW[16];
+ /* It is non-standard for modes to exceed 16 characters. */
+ wchar_t modesW[16];
- MultiByteToWideChar (cp, 0, modes, -1, modesW, sizeof(modesW));
+ MultiByteToWideChar (cp, 0, modes, -1, modesW, sizeof(modesW));
- FILE * file = _wfopen (fullPath, modesW);
- free (fullPath);
+ FILE * file = _wfopen (fullPath, modesW);
+ free (fullPath);
- return close_on_exec (file);
+ return close_on_exec (file);
#elif defined (HAVE_FOPEN64)
return close_on_exec (fopen64 (filename, modes));