summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--compat/mingw.c50
1 files changed, 48 insertions, 2 deletions
diff --git a/compat/mingw.c b/compat/mingw.c
index 44264fe3fd..6c3c4ca5a6 100644
--- a/compat/mingw.c
+++ b/compat/mingw.c
@@ -203,6 +203,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;
@@ -918,8 +943,29 @@ struct tm *localtime_r(const time_t *timep, struct tm *result)
char *mingw_getcwd(char *pointer, int len)
{
- wchar_t wpointer[MAX_PATH];
- if (!_wgetcwd(wpointer, ARRAY_SIZE(wpointer)))
+ wchar_t cwd[MAX_PATH], wpointer[MAX_PATH];
+ DWORD ret = GetCurrentDirectoryW(ARRAY_SIZE(cwd), cwd);
+
+ if (!ret || ret >= ARRAY_SIZE(cwd)) {
+ errno = ret ? ENAMETOOLONG : err_win_to_posix(GetLastError());
+ 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)
return NULL;