[PATCH 0/1] MR9414: Draft: shlwapi: Handling of "C:\...xx" in PathCanonicalize[AW].
## Description This is intended to solve https://bugs.winehq.org/show_bug.cgi?id=58129 Add tests for verification, which pass on my locale win10 machine. ##Todo - [] Removed UNC path check which seems okay, but i am not sure why it was introduced. git blame did not help me, therefore any hints or examples to test are welcome. -- https://gitlab.winehq.org/wine/wine/-/merge_requests/9414
From: Thomas Csovcsity <thc.fr13nd(a)gmail.com> --- dlls/kernelbase/path.c | 54 ++++++++++++++++----------------------- dlls/shlwapi/tests/path.c | 45 ++++++++++++++++++++++++++++++++ 2 files changed, 67 insertions(+), 32 deletions(-) diff --git a/dlls/kernelbase/path.c b/dlls/kernelbase/path.c index ece259ebe7b..8bb1ca1be90 100644 --- a/dlls/kernelbase/path.c +++ b/dlls/kernelbase/path.c @@ -1313,44 +1313,21 @@ BOOL WINAPI PathCanonicalizeW(WCHAR *buffer, const WCHAR *path) /* Canonicalize the rest of the path */ while (*src) { - if (*src == '.') + if (*src == '\\') { - if (src[1] == '\\' && (src == path || src[-1] == '\\' || src[-1] == ':')) + if ((dst > buffer + 2) && dst[-2] == '\\' && dst[-1] == '.') { - src += 2; /* Skip .\ */ + dst -= 1; /* Skip .\ */ + src++; } - else if (src[1] == '.' && dst != buffer && dst[-1] == '\\') + else if ((dst > buffer + 4) && dst[-3] == '\\' && dst[-2] == '.' && dst[-1] == '.') { - /* \.. backs up a directory, over the root if it has no \ following X:. - * .. is ignored if it would remove a UNC server name or initial \\ - */ - if (dst != buffer) + /* \.. backs up a directory */ + dst -= 4; + while (dst > buffer && *dst != '\\') { - *dst = '\0'; /* Allow PathIsUNCServerShareA test on lpszBuf */ - if (dst > buffer + 1 && dst[-1] == '\\' && (dst[-2] != '\\' || dst > buffer + 2)) - { - if (dst[-2] == ':' && (dst > buffer + 3 || dst[-3] == ':')) - { - dst -= 2; - while (dst > buffer && *dst != '\\') - dst--; - if (*dst == '\\') - dst++; /* Reset to last '\' */ - else - dst = buffer; /* Start path again from new root */ - } - else if (dst[-2] != ':' && !PathIsUNCServerShareW(buffer)) - dst -= 2; - } - while (dst > buffer && *dst != '\\') - dst--; - if (dst == buffer) - { - *dst++ = '\\'; - src++; - } + dst--; } - src += 2; /* Skip .. in src path */ } else *dst++ = *src++; @@ -1359,6 +1336,19 @@ BOOL WINAPI PathCanonicalizeW(WCHAR *buffer, const WCHAR *path) *dst++ = *src++; } + /* Remove trailing \.. and back up if possible and keep X: */ + if ((dst > buffer + 4) && dst[-3] == '\\' && dst[-2] == '.' && dst[-1] == '.' ) + { + dst -= 4; + if (*dst != ':') + { + while (dst > buffer && *dst != '\\') + dst--; + } + else + dst++; + } + /* Append \ to naked drive specs */ if (dst - buffer == 2 && dst[-1] == ':') *dst++ = '\\'; diff --git a/dlls/shlwapi/tests/path.c b/dlls/shlwapi/tests/path.c index fb8d3f1b9c1..07353b48b73 100644 --- a/dlls/shlwapi/tests/path.c +++ b/dlls/shlwapi/tests/path.c @@ -700,6 +700,15 @@ static void test_PathCombineA(void) ok(!lstrcmpA(str, "C:\\"), "Expected C:\\, got %s\n", str); ok(GetLastError() == 0xdeadbeef, "Expected 0xdeadbeef, got %ld\n", GetLastError()); + /* try ...xx as file */ + /* try forward slashes */ + SetLastError(0xdeadbeef); + lstrcpyA(dest, "control"); + str = PathCombineA(dest, "C:\\", "...xx"); + ok(str == dest, "Expected str == dest, got %p\n", str); + ok(!lstrcmpA(str, "C:\\...xx"), "Expected C:\\...xx, got %s\n", str); + ok(GetLastError() == 0xdeadbeef, "Expected 0xdeadbeef, got %ld\n", GetLastError()); + /* try relative paths */ /* try forward slashes */ SetLastError(0xdeadbeef); @@ -1076,6 +1085,42 @@ static void test_PathCanonicalizeA(void) "Expected 0xdeadbeef or ERROR_FILENAME_EXCED_RANGE, got %ld\n", GetLastError()); } ok(lstrlenA(too_long) == LONG_LEN - 1, "Expected length LONG_LEN - 1, got %i\n", lstrlenA(too_long)); + + /* try C:\.. */ + memset(dest, 0, LONG_LEN + MAX_PATH); + lstrcpyA(dest, "test"); + SetLastError(0xdeadbeef); + res = PathCanonicalizeA(dest, "C:\\.."); + ok(res, "Expected success\n"); + ok(GetLastError() == 0xdeadbeef, "Expected 0xdeadbeef, got %ld\n", GetLastError()); + ok(!lstrcmpA(dest, "C:\\"), "C:\\, got %s\n", dest); + + /* try C:\...x */ + memset(dest, 0, LONG_LEN + MAX_PATH); + lstrcpyA(dest, "test"); + SetLastError(0xdeadbeef); + res = PathCanonicalizeA(dest, "C:\\...x"); + ok(res, "Expected success\n"); + ok(GetLastError() == 0xdeadbeef, "Expected 0xdeadbeef, got %ld\n", GetLastError()); + ok(!lstrcmpA(dest, "C:\\...x"), "C:\\...x, got %s\n", dest); + + /* try C:\test\...x */ + memset(dest, 0, LONG_LEN + MAX_PATH); + lstrcpyA(dest, "test"); + SetLastError(0xdeadbeef); + res = PathCanonicalizeA(dest, "C:\\test\\...x"); + ok(res, "Expected success\n"); + ok(GetLastError() == 0xdeadbeef, "Expected 0xdeadbeef, got %ld\n", GetLastError()); + ok(!lstrcmpA(dest, "C:\\test\\...x"), "C:\\test\\...x, got %s\n", dest); + + /* try C:\test\...\x */ + memset(dest, 0, LONG_LEN + MAX_PATH); + lstrcpyA(dest, "test"); + SetLastError(0xdeadbeef); + res = PathCanonicalizeA(dest, "C:\\test\\...\\x"); + ok(res, "Expected success\n"); + ok(GetLastError() == 0xdeadbeef, "Expected 0xdeadbeef, got %ld\n", GetLastError()); + ok(!lstrcmpA(dest, "C:\\test\\...\\x"), "C:\\test\\...\\x, got %s\n", dest); } static void test_PathFindExtensionA(void) -- GitLab https://gitlab.winehq.org/wine/wine/-/merge_requests/9414
For simple tests like that you can add to the file_tests[] array in test_UrlCanonicalizeA() and the TEST_COMBINE[] array. -- https://gitlab.winehq.org/wine/wine/-/merge_requests/9414#note_121389
On Tue Nov 11 13:38:17 2025 +0000, Elizabeth Figura wrote:
For simple tests like that you can add to the file_tests[] array in test_UrlCanonicalizeA() and the TEST_COMBINE[] array. Sorry i do not get it. I modified [PathCanonicalizeW from dlls/kernelbase/path.c](https://gitlab.winehq.org/wine/wine/-/merge_requests/9414/diffs?commit_id=f3...). It seems you refer to UrlCanonicalizeW, which does not call PathCanonicalizeW. That is why i am not sure of the deleted UNC part in the old code. Maybe i missed something. I would appreciate a detailed hint to understand it.
-- https://gitlab.winehq.org/wine/wine/-/merge_requests/9414#note_121504
participants (3)
-
Elizabeth Figura (@zfigura) -
Thomas Csovcsity -
Thomas Csovcsity (@thc13)