aboutsummaryrefslogtreecommitdiff
path: root/bfd/bfdio.c
diff options
context:
space:
mode:
authorTorbj?rn Svensson <torbjorn.svensson@st.com>2022-02-28 12:17:33 +0000
committerNick Clifton <nickc@redhat.com>2022-02-28 12:17:33 +0000
commitcb7da2a640c405e0658c135b3ab2ac5be2fdc53a (patch)
tree4ec67dd382068a667e07b3d7baf8cc75e38384e5 /bfd/bfdio.c
parenteda240cd356adf6224f35e609f3ada37d1799168 (diff)
downloadbinutils-cb7da2a640c405e0658c135b3ab2ac5be2fdc53a.zip
binutils-cb7da2a640c405e0658c135b3ab2ac5be2fdc53a.tar.gz
binutils-cb7da2a640c405e0658c135b3ab2ac5be2fdc53a.tar.bz2
Further correct the handling of long pathnames on Windows hosts.
PR 25713 * bfdio.c (_bfd_real_fopen): Fix handling of parhs longer than 260 characters on Windows hosts.
Diffstat (limited to 'bfd/bfdio.c')
-rw-r--r--bfd/bfdio.c78
1 files changed, 39 insertions, 39 deletions
diff --git a/bfd/bfdio.c b/bfd/bfdio.c
index 41b18b6..82310ff 100644
--- a/bfd/bfdio.c
+++ b/bfd/bfdio.c
@@ -116,55 +116,55 @@ _bfd_real_fopen (const char *filename, const char *modes)
}
#elif defined (_WIN32)
- size_t filelen;
+ /* PR 25713: Handle extra long path names possibly containing '..' and '.'. */
- /* PR 25713: Handle extra long path names.
- For relative paths, convert them to absolute, in case that version is too long. */
- if (! IS_ABSOLUTE_PATH (filename) && (strstr (filename, ".o") != NULL))
- {
- char cwd[1024];
+ wchar_t **lpFilePart = {NULL};
+ const wchar_t prefix[] = L"\\\\?\\";
+ const wchar_t ccs[] = L", ccs=UNICODE";
+ const size_t partPathLen = strlen(filename) + 1;
- getcwd (cwd, sizeof (cwd));
- filelen = strlen (cwd) + 1;
- strncat (cwd, "\\", sizeof (cwd) - filelen);
- ++ filelen;
- strncat (cwd, filename, sizeof (cwd) - filelen);
+ /* 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_UTF8, 0, partPathOrig, -1, NULL, 0);
+ wchar_t *partPath = calloc (partPathWSize, sizeof(wchar_t));
- filename = cwd;
- }
+ MultiByteToWideChar (CP_UTF8, 0, partPathOrig, -1, partPath, partPathWSize);
- filelen = strlen (filename) + 1;
+ /* Convert any UNIX style path separators into the DOS i.e. backslash separator. */
+ size_t ix;
+ for (ix = 0; ix < partPathLen; ix++)
+ if (IS_UNIX_DIR_SEPARATOR(filename[ix]))
+ partPath[ix] = '\\';
- if (filelen > MAX_PATH - 1)
- {
- FILE * file;
- char * fullpath;
- int i;
-
- fullpath = (char *) malloc (filelen + 8);
-
- /* 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;
- }
+ /* 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 + sizeof(ccs)];
+ MultiByteToWideChar (CP_UTF8, 0, modes, -1, modesW, sizeof(modesW));
+ wcscat (modesW, ccs);
+
+ FILE* file = _wfopen (fullPath, mdesW);
+ free (fullPath);
+
+ return close_on_exec (file);
#elif defined (HAVE_FOPEN64)
return close_on_exec (fopen64 (filename, modes));
-#endif
+#else
return close_on_exec (fopen (filename, modes));
+#endif
}
/*