Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix Windows-specific problem to determine the real path near a drive root #4253

Merged
merged 2 commits into from
Jan 28, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
29 changes: 21 additions & 8 deletions compat/mingw.c
Original file line number Diff line number Diff line change
Expand Up @@ -1386,6 +1386,7 @@ char *mingw_strbuf_realpath(struct strbuf *resolved, const char *path)
DWORD ret;
int len;
const char *last_component = NULL;
char *append = NULL;

if (xutftowcs_path(wpath, path) < 0)
return NULL;
Expand All @@ -1408,34 +1409,46 @@ char *mingw_strbuf_realpath(struct strbuf *resolved, const char *path)
break; /* found start of last component */

if (p != wpath && (last_component = find_last_dir_sep(path))) {
last_component++; /* skip directory separator */
*p = L'\0';
append = xstrdup(last_component + 1); /* skip directory separator */
/*
* Do not strip the trailing slash at the drive root, otherwise
* the path would be e.g. `C:` (which resolves to the
* _current_ directory on that drive).
*/
if (p[-1] == L':')
p[1] = L'\0';
else
*p = L'\0';
h = CreateFileW(wpath, 0, FILE_SHARE_READ |
FILE_SHARE_WRITE | FILE_SHARE_DELETE,
NULL, OPEN_EXISTING,
FILE_FLAG_BACKUP_SEMANTICS, NULL);
}
}

if (h == INVALID_HANDLE_VALUE)
if (h == INVALID_HANDLE_VALUE) {
realpath_failed:
FREE_AND_NULL(append);
return NULL;
}

ret = GetFinalPathNameByHandleW(h, wpath, ARRAY_SIZE(wpath), 0);
CloseHandle(h);
if (!ret || ret >= ARRAY_SIZE(wpath))
return NULL;
goto realpath_failed;

len = wcslen(wpath) * 3;
strbuf_grow(resolved, len);
len = xwcstoutf(resolved->buf, normalize_ntpath(wpath), len);
if (len < 0)
return NULL;
goto realpath_failed;
resolved->len = len;

if (last_component) {
if (append) {
/* Use forward-slash, like `normalize_ntpath()` */
strbuf_addch(resolved, '/');
strbuf_addstr(resolved, last_component);
strbuf_complete(resolved, '/');
strbuf_addstr(resolved, append);
FREE_AND_NULL(append);
}

return resolved->buf;
Expand Down
6 changes: 6 additions & 0 deletions t/t0060-path-utils.sh
Original file line number Diff line number Diff line change
Expand Up @@ -237,6 +237,12 @@ test_expect_success SYMLINKS 'real path works on symlinks' '
test "$sym" = "$(test-tool path-utils real_path "$dir2/syml")"
'

test_expect_success MINGW 'real path works near drive root' '
# we need a non-existing path at the drive root; simply skip if C:/xyz exists
test -e C:/xyz ||
test C:/xyz = $(test-tool path-utils real_path C:/xyz)
'

test_expect_success SYMLINKS 'prefix_path works with absolute paths to work tree symlinks' '
ln -s target symlink &&
test "$(test-tool path-utils prefix_path prefix "$(pwd)/symlink")" = "symlink"
Expand Down