diff options
Diffstat (limited to 'bfd/bfdio.c')
-rw-r--r-- | bfd/bfdio.c | 108 |
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)); |