Skip to content

Commit

Permalink
Further correct the handling of long pathnames on Windows hosts.
Browse files Browse the repository at this point in the history
	PR 25713
	* bfdio.c (_bfd_real_fopen): Fix handling of parhs longer than 260
	characters on Windows hosts.
  • Loading branch information
Torbjorn-Svensson authored and nickclifton committed Feb 28, 2022
1 parent eda240c commit cb7da2a
Show file tree
Hide file tree
Showing 2 changed files with 45 additions and 39 deletions.
6 changes: 6 additions & 0 deletions bfd/ChangeLog
Original file line number Diff line number Diff line change
@@ -1,3 +1,9 @@
2022-02-28 Torbjörn Svensson <torbjorn.svensson@st.com>

PR 25713
* bfdio.c (_bfd_real_fopen): Fix handling of parhs longer than 260
characters on Windows hosts.

2022-02-28 Nick Clifton <nickc@redhat.com>

PR 28886
Expand Down
78 changes: 39 additions & 39 deletions bfd/bfdio.c
Original file line number Diff line number Diff line change
Expand Up @@ -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
}

/*
Expand Down

0 comments on commit cb7da2a

Please sign in to comment.