From: Thomas Csovcsity thc.fr13nd@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)