mingw: fix getcwd when the parent directory cannot be queried
`GetLongPathName()` function may fail when it is unable to query the parent directory of a path component to determine the long name for that component. It happens, because it uses `FindFirstFile()` function for each next short part of path. The `FindFirstFile()` requires `List Directory` and `Synchronize` desired access for a calling process. In case of lacking such permission for some part of path, the `GetLongPathName()` returns 0 as result and `GetLastError()` returns ERROR_ACCESS_DENIED. `GetFinalPathNameByHandle()` function can help in such cases, because it requires `Read Attributes` and `Synchronize` desired access to the target path only. The `GetFinalPathNameByHandle()` function was introduced on `Windows Server 2008/Windows Vista`. So we need to load it dynamically. `CreateFile()` parameters: `lpFileName` = path to the current directory `dwDesiredAccess` = 0 (it means `Read Attributes` and `Synchronize`) `dwShareMode` = FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE (it prevents `Sharing Violation`) `lpSecurityAttributes` = NULL (default security attributes) `dwCreationDisposition` = OPEN_EXISTING (required to obtain a directory handle) `dwFlagsAndAttributes` = FILE_FLAG_BACKUP_SEMANTICS (required to obtain a directory handle) `hTemplateFile` = NULL (when opening an existing file or directory, `CreateFile` ignores this parameter) The string that is returned by `GetFinalPathNameByHandle()` function uses the \\?\ syntax. To skip the prefix and convert backslashes to slashes, the `normalize_ntpath()` mingw function will be used. Note: `GetFinalPathNameByHandle()` function returns a final path. It is the path that is returned when a path is fully resolved. For example, for a symbolic link named "C:\tmp\mydir" that points to "D:\yourdir", the final path would be "D:\yourdir". Signed-off-by: Anton Serbulov <aserbulov@plesk.com> Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de> Signed-off-by: Junio C Hamano <gitster@pobox.com>
This commit is contained in:
parent
937974fc65
commit
4745feeb8b
@ -202,6 +202,31 @@ static int ask_yes_no_if_possible(const char *format, ...)
|
||||
}
|
||||
}
|
||||
|
||||
/* Normalizes NT paths as returned by some low-level APIs. */
|
||||
static wchar_t *normalize_ntpath(wchar_t *wbuf)
|
||||
{
|
||||
int i;
|
||||
/* fix absolute path prefixes */
|
||||
if (wbuf[0] == '\\') {
|
||||
/* strip NT namespace prefixes */
|
||||
if (!wcsncmp(wbuf, L"\\??\\", 4) ||
|
||||
!wcsncmp(wbuf, L"\\\\?\\", 4))
|
||||
wbuf += 4;
|
||||
else if (!wcsnicmp(wbuf, L"\\DosDevices\\", 12))
|
||||
wbuf += 12;
|
||||
/* replace remaining '...UNC\' with '\\' */
|
||||
if (!wcsnicmp(wbuf, L"UNC\\", 4)) {
|
||||
wbuf += 2;
|
||||
*wbuf = '\\';
|
||||
}
|
||||
}
|
||||
/* convert backslashes to slashes */
|
||||
for (i = 0; wbuf[i]; i++)
|
||||
if (wbuf[i] == '\\')
|
||||
wbuf[i] = '/';
|
||||
return wbuf;
|
||||
}
|
||||
|
||||
int mingw_unlink(const char *pathname)
|
||||
{
|
||||
int ret, tries = 0;
|
||||
@ -925,6 +950,20 @@ char *mingw_getcwd(char *pointer, int len)
|
||||
return NULL;
|
||||
}
|
||||
ret = GetLongPathNameW(cwd, wpointer, ARRAY_SIZE(wpointer));
|
||||
if (!ret && GetLastError() == ERROR_ACCESS_DENIED) {
|
||||
HANDLE hnd = CreateFileW(cwd, 0,
|
||||
FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, NULL,
|
||||
OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, NULL);
|
||||
if (hnd == INVALID_HANDLE_VALUE)
|
||||
return NULL;
|
||||
ret = GetFinalPathNameByHandleW(hnd, wpointer, ARRAY_SIZE(wpointer), 0);
|
||||
CloseHandle(hnd);
|
||||
if (!ret || ret >= ARRAY_SIZE(wpointer))
|
||||
return NULL;
|
||||
if (xwcstoutf(pointer, normalize_ntpath(wpointer), len) < 0)
|
||||
return NULL;
|
||||
return pointer;
|
||||
}
|
||||
if (!ret || ret >= ARRAY_SIZE(wpointer))
|
||||
return NULL;
|
||||
if (xwcstoutf(pointer, wpointer, len) < 0)
|
||||
|
Loading…
Reference in New Issue
Block a user