Signed-off-by: Zhiyi Zhang zzhang@codeweavers.com --- .../api-ms-win-core-path-l1-1-0.spec | 2 +- dlls/kernelbase/kernelbase.spec | 2 +- dlls/kernelbase/path.c | 38 ++++++++++ dlls/kernelbase/tests/path.c | 69 +++++++++++++++++++ include/pathcch.h | 1 + 5 files changed, 110 insertions(+), 2 deletions(-)
diff --git a/dlls/api-ms-win-core-path-l1-1-0/api-ms-win-core-path-l1-1-0.spec b/dlls/api-ms-win-core-path-l1-1-0/api-ms-win-core-path-l1-1-0.spec index a09889f415..61eb22031e 100644 --- a/dlls/api-ms-win-core-path-l1-1-0/api-ms-win-core-path-l1-1-0.spec +++ b/dlls/api-ms-win-core-path-l1-1-0/api-ms-win-core-path-l1-1-0.spec @@ -10,7 +10,7 @@ @ stub PathCchCombine @ stub PathCchCombineEx @ stdcall PathCchFindExtension(wstr long ptr) kernelbase.PathCchFindExtension -@ stub PathCchIsRoot +@ stdcall PathCchIsRoot(wstr) kernelbase.PathCchIsRoot @ stub PathCchRemoveBackslash @ stub PathCchRemoveBackslashEx @ stdcall PathCchRemoveExtension(wstr long) kernelbase.PathCchRemoveExtension diff --git a/dlls/kernelbase/kernelbase.spec b/dlls/kernelbase/kernelbase.spec index aefc63e54c..ffb5a95721 100644 --- a/dlls/kernelbase/kernelbase.spec +++ b/dlls/kernelbase/kernelbase.spec @@ -1039,7 +1039,7 @@ # @ stub PathCchCombine # @ stub PathCchCombineEx @ stdcall PathCchFindExtension(wstr long ptr) -# @ stub PathCchIsRoot +@ stdcall PathCchIsRoot(wstr) # @ stub PathCchRemoveBackslash # @ stub PathCchRemoveBackslashEx @ stdcall PathCchRemoveExtension(wstr long) diff --git a/dlls/kernelbase/path.c b/dlls/kernelbase/path.c index c59fba8d3e..ff8e0dddd1 100644 --- a/dlls/kernelbase/path.c +++ b/dlls/kernelbase/path.c @@ -242,6 +242,44 @@ HRESULT WINAPI PathCchFindExtension(const WCHAR *path, SIZE_T size, const WCHAR return S_OK; }
+BOOL WINAPI PathCchIsRoot(const WCHAR *path) +{ + const WCHAR *root_end; + const WCHAR *next; + BOOL is_unc; + + TRACE("%s\n", wine_dbgstr_w(path)); + + if (!path || !*path) return FALSE; + + root_end = get_root_end(path); + if (!root_end) return FALSE; + + if ((is_unc = is_prefixed_unc(path)) || (path[0] == '\' && path[1] == '\' && path[2] != '?')) + { + next = root_end + 1; + /* No extra segments */ + if ((is_unc && !*next) || (!is_unc && !*next)) return TRUE; + + /* Has first segment with an ending backslash but no remaining characters */ + if (get_next_segment(next, &next) && !*next) return FALSE; + /* Has first segment with no ending backslash */ + else if (!*next) + return TRUE; + /* Has first segment with an ending backslash and has remaining characters*/ + else + { + next++; + /* Second segment must have no backslash and no remaining characters */ + return !get_next_segment(next, &next) && !*next; + } + } + else if (*root_end == '\' && !root_end[1]) + return TRUE; + else + return FALSE; +} + HRESULT WINAPI PathCchRemoveExtension(WCHAR *path, SIZE_T size) { const WCHAR *extension; diff --git a/dlls/kernelbase/tests/path.c b/dlls/kernelbase/tests/path.c index 5b47b84831..6d37bbf8ef 100644 --- a/dlls/kernelbase/tests/path.c +++ b/dlls/kernelbase/tests/path.c @@ -35,6 +35,7 @@ HRESULT (WINAPI *pPathCchAddBackslashEx)(WCHAR *out, SIZE_T size, WCHAR **endptr HRESULT (WINAPI *pPathCchAddExtension)(WCHAR *path, SIZE_T size, const WCHAR *extension); HRESULT (WINAPI *pPathCchCombineEx)(WCHAR *out, SIZE_T size, const WCHAR *path1, const WCHAR *path2, DWORD flags); HRESULT (WINAPI *pPathCchFindExtension)(const WCHAR *path, SIZE_T size, const WCHAR **extension); +BOOL (WINAPI *pPathCchIsRoot)(const WCHAR *path); HRESULT (WINAPI *pPathCchRemoveExtension)(WCHAR *path, SIZE_T size); HRESULT (WINAPI *pPathCchRenameExtension)(WCHAR *path, SIZE_T size, const WCHAR *extension); HRESULT (WINAPI *pPathCchSkipRoot)(const WCHAR *path, const WCHAR **root_end); @@ -477,6 +478,72 @@ static void test_PathCchFindExtension(void) } }
+struct isroot_test +{ + const CHAR *path; + BOOL ret; +}; + +static const struct isroot_test isroot_tests[] = +{ + {"", FALSE}, + {"a", FALSE}, + {"C:", FALSE}, + {"C:\", TRUE}, + {"C:\a", FALSE}, + {"\\?\C:\", TRUE}, + {"\\?\C:", FALSE}, + {"\\?\C:\a", FALSE}, + {"\", TRUE}, + {"\a\", FALSE}, + {"\a\b", FALSE}, + {"\\", TRUE}, + {"\\a", TRUE}, + {"\\a\", FALSE}, + {"\\a\b", TRUE}, + {"\\a\b\", FALSE}, + {"\\a\b\c", FALSE}, + {"\\?\UNC\", TRUE}, + {"\\?\UNC\a", TRUE}, + {"\\?\UNC\a\", FALSE}, + {"\\?\UNC\a\b", TRUE}, + {"\\?\UNC\a\b\", FALSE}, + {"\\?\UNC\a\b\c", FALSE}, + {"\\?\Volume{e51a1864-6f2d-4019-b73d-f4e60e600c26}", FALSE}, + {"\\?\Volume{e51a1864-6f2d-4019-b73d-f4e60e600c26}\", TRUE}, + {"\\?\Volume{e51a1864-6f2d-4019-b73d-f4e60e600c26}\a", FALSE}, + {"..\a", FALSE}, + + /* Wrong MSDN examples */ + {"\a", FALSE}, + {"X:", FALSE}, + {"\server", FALSE} +}; + +static void test_PathCchIsRoot(void) +{ + WCHAR pathW[MAX_PATH]; + BOOL ret; + INT i; + + if (!pPathCchIsRoot) + { + win_skip("PathCchIsRoot() is not available.\n"); + return; + } + + ret = pPathCchIsRoot(NULL); + ok(ret == FALSE, "expect return FALSE\n"); + + for (i = 0; i < ARRAY_SIZE(isroot_tests); i++) + { + const struct isroot_test *t = isroot_tests + i; + MultiByteToWideChar(CP_ACP, 0, t->path, -1, pathW, ARRAY_SIZE(pathW)); + ret = pPathCchIsRoot(pathW); + ok(ret == t->ret, "path %s expect return %d, got %d\n", t->path, t->ret, ret); + } +} + struct removeextension_test { const CHAR *path; @@ -1039,6 +1106,7 @@ START_TEST(path) pPathCchAddBackslashEx = (void *)GetProcAddress(hmod, "PathCchAddBackslashEx"); pPathCchAddExtension = (void *)GetProcAddress(hmod, "PathCchAddExtension"); pPathCchFindExtension = (void *)GetProcAddress(hmod, "PathCchFindExtension"); + pPathCchIsRoot = (void *)GetProcAddress(hmod, "PathCchIsRoot"); pPathCchRemoveExtension = (void *)GetProcAddress(hmod, "PathCchRemoveExtension"); pPathCchRenameExtension = (void *)GetProcAddress(hmod, "PathCchRenameExtension"); pPathCchSkipRoot = (void *)GetProcAddress(hmod, "PathCchSkipRoot"); @@ -1051,6 +1119,7 @@ START_TEST(path) test_PathCchAddBackslashEx(); test_PathCchAddExtension(); test_PathCchFindExtension(); + test_PathCchIsRoot(); test_PathCchRemoveExtension(); test_PathCchRenameExtension(); test_PathCchSkipRoot(); diff --git a/include/pathcch.h b/include/pathcch.h index 56920b3444..443ccd3a4f 100644 --- a/include/pathcch.h +++ b/include/pathcch.h @@ -30,6 +30,7 @@ HRESULT WINAPI PathCchAddBackslashEx(WCHAR *path, SIZE_T size, WCHAR **end, SIZE HRESULT WINAPI PathCchAddExtension(WCHAR *path, SIZE_T size, const WCHAR *extension); HRESULT WINAPI PathCchCombineEx(WCHAR *out, SIZE_T size, const WCHAR *path1, const WCHAR *path2, DWORD flags); HRESULT WINAPI PathCchFindExtension(const WCHAR *path, SIZE_T size, const WCHAR **extension); +BOOL WINAPI PathCchIsRoot(const WCHAR *path); HRESULT WINAPI PathCchRemoveExtension(WCHAR *path, SIZE_T size); HRESULT WINAPI PathCchRenameExtension(WCHAR *path, SIZE_T size, const WCHAR *extension); HRESULT WINAPI PathCchSkipRoot(const WCHAR *path, const WCHAR **root_end);