Signed-off-by: Zebediah Figura z.figura12@gmail.com --- dlls/ntdll/path.c | 8 ++++---- dlls/ntdll/tests/path.c | 7 +++++++ 2 files changed, 11 insertions(+), 4 deletions(-)
diff --git a/dlls/ntdll/path.c b/dlls/ntdll/path.c index ccc95e3..8fe61da 100644 --- a/dlls/ntdll/path.c +++ b/dlls/ntdll/path.c @@ -244,10 +244,10 @@ DOS_PATHNAME_TYPE WINAPI RtlDetermineDosPathNameType_U( PCWSTR path ) if (IS_SEPARATOR(path[0])) { if (!IS_SEPARATOR(path[1])) return ABSOLUTE_PATH; /* "/foo" */ - if (path[2] != '.') return UNC_PATH; /* "//foo" */ - if (IS_SEPARATOR(path[3])) return DEVICE_PATH; /* "//./foo" */ - if (path[3]) return UNC_PATH; /* "//.foo" */ - return UNC_DOT_PATH; /* "//." */ + if (path[2] != '.' && path[2] != '?') return UNC_PATH; /* "//foo" */ + if (IS_SEPARATOR(path[3])) return DEVICE_PATH; /* "//./foo" or "//?/foo" */ + if (path[3]) return UNC_PATH; /* "//.foo" or "//?foo" */ + return UNC_DOT_PATH; /* "//." or "//?" */ } else { diff --git a/dlls/ntdll/tests/path.c b/dlls/ntdll/tests/path.c index 9369e1c..94b76c1 100644 --- a/dlls/ntdll/tests/path.c +++ b/dlls/ntdll/tests/path.c @@ -68,6 +68,13 @@ static void test_RtlDetermineDosPathNameType_U(void) { "//.foo", 1 }, { "\\.", 7 }, { "//.", 7 }, + { "\\?\foo", 6 }, + { "//?/foo", 6 }, + { "/\?/foo", 6 }, + { "\\?foo", 1 }, + { "//?foo", 1 }, + { "\\?", 7 }, + { "//?", 7 }, { NULL, 0 } };
Signed-off-by: Zebediah Figura z.figura12@gmail.com --- dlls/ntdll/tests/path.c | 56 ++++++++++++++++++++++++++++++++++++++++++------- 1 file changed, 49 insertions(+), 7 deletions(-)
diff --git a/dlls/ntdll/tests/path.c b/dlls/ntdll/tests/path.c index 94b76c1..b2a6955 100644 --- a/dlls/ntdll/tests/path.c +++ b/dlls/ntdll/tests/path.c @@ -266,6 +266,7 @@ static void test_RtlGetFullPathName_U(void) static const struct test tests[] = { { "c:/test", "c:\test", "test"}, + { "c:/test/", "c:\test\", NULL}, { "c:/test ", "c:\test", "test"}, { "c:/test.", "c:\test", "test"}, { "c:/test .... .. ", "c:\test", "test"}, @@ -287,22 +288,61 @@ static void test_RtlGetFullPathName_U(void) { "c:/test../file", "c:\test.\file", "file", "c:\test..\file", "file"}, /* vista */ { "c:\test", "c:\test", "test"}, - { NULL, NULL, NULL} + { "C:\test", "C:\test", "test"}, + { "c:/", "c:\", NULL}, + { "c:.", "C:\windows", "windows"}, + { "c:foo", "C:\windows\foo", "foo"}, + { "c:foo/bar", "C:\windows\foo\bar", "bar"}, + { "c:./foo", "C:\windows\foo", "foo"}, + { "\foo", "C:\foo", "foo"}, + { "foo", "C:\windows\foo", "foo"}, + { ".", "C:\windows", "windows"}, + { "..", "C:\", NULL}, + { "...", "C:\windows\", NULL}, + { "./foo", "C:\windows\foo", "foo"}, + { "foo/..", "C:\windows", "windows"}, + { "AUX", "\\.\AUX", NULL}, + { "COM1", "\\.\COM1", NULL}, + { "?<>*"|:", "C:\windows\?<>*"|:", "?<>*"|:"}, + + { "\\foo", "\\foo", NULL}, + { "//foo", "\\foo", NULL}, + { "\/foo", "\\foo", NULL}, + { "//", "\\", NULL}, + { "//foo/", "\\foo\", NULL}, + + { "//.", "\\.\", NULL}, + { "//./", "\\.\", NULL}, + { "//.//", "\\.\", NULL}, + { "//./foo", "\\.\foo", "foo"}, + { "//./foo/", "\\.\foo\", NULL}, + { "//./foo/bar", "\\.\foo\bar", "bar"}, + { "//./foo/.", "\\.\foo", "foo"}, + { "//./foo/..", "\\.\", NULL}, + + { "//?/", "\\?\", NULL}, + { "//?//", "\\?\", NULL}, + { "//?/foo", "\\?\foo", "foo"}, + { "//?/foo/", "\\?\foo\", NULL}, + { "//?/foo/bar", "\\?\foo\bar", "bar"}, + { "//?/foo/.", "\\?\foo", "foo"}, + { "//?/foo/..", "\\?\", NULL}, + + /* RtlGetFullPathName_U() can't understand the global namespace prefix */ + { "\??\foo", "C:\??\foo", "foo"}, + { 0 } };
const struct test *test; WCHAR pathbufW[2*MAX_PATH], rbufferW[MAX_PATH]; - CHAR rbufferA[MAX_PATH], rfileA[MAX_PATH]; + char rbufferA[MAX_PATH], rfileA[MAX_PATH], curdir[MAX_PATH]; ULONG ret; WCHAR *file_part; DWORD reslen; UINT len;
- if (!pRtlGetFullPathName_U) - { - win_skip("RtlGetFullPathName_U is not available\n"); - return; - } + GetCurrentDirectoryA(sizeof(curdir), curdir); + SetCurrentDirectoryA("C:\windows\");
file_part = (WCHAR *)0xdeadbeef; lstrcpyW(rbufferW, deadbeefW); @@ -348,6 +388,8 @@ static void test_RtlGetFullPathName_U(void) ok( !test->rfile, "Got NULL expected "%s"\n", test->rfile ); } } + + SetCurrentDirectoryA(curdir); }
static void test_RtlDosPathNameToNtPathName_U_WithStatus(void)
Signed-off-by: Zebediah Figura z.figura12@gmail.com --- dlls/ntdll/tests/path.c | 147 +++++++++++++++++++++++++++++++++++++++++------- 1 file changed, 127 insertions(+), 20 deletions(-)
diff --git a/dlls/ntdll/tests/path.c b/dlls/ntdll/tests/path.c index b2a6955..a032092 100644 --- a/dlls/ntdll/tests/path.c +++ b/dlls/ntdll/tests/path.c @@ -19,6 +19,7 @@ */
#include "ntdll_test.h" +#include "winnls.h"
static NTSTATUS (WINAPI *pRtlMultiByteToUnicodeN)( LPWSTR dst, DWORD dstlen, LPDWORD reslen, LPCSTR src, DWORD srclen ); @@ -28,6 +29,7 @@ static ULONG (WINAPI *pRtlIsDosDeviceName_U)( PCWSTR dos_name ); static NTSTATUS (WINAPI *pRtlOemStringToUnicodeString)(UNICODE_STRING *, const STRING *, BOOLEAN ); static BOOLEAN (WINAPI *pRtlIsNameLegalDOS8Dot3)(const UNICODE_STRING*,POEM_STRING,PBOOLEAN); static DWORD (WINAPI *pRtlGetFullPathName_U)(const WCHAR*,ULONG,WCHAR*,WCHAR**); +static BOOLEAN (WINAPI *pRtlDosPathNameToNtPathName_U)(const WCHAR*, UNICODE_STRING*, WCHAR**, CURDIR*); static NTSTATUS (WINAPI *pRtlDosPathNameToNtPathName_U_WithStatus)(const WCHAR*, UNICODE_STRING*, WCHAR**, CURDIR*);
static void test_RtlDetermineDosPathNameType_U(void) @@ -392,33 +394,137 @@ static void test_RtlGetFullPathName_U(void) SetCurrentDirectoryA(curdir); }
-static void test_RtlDosPathNameToNtPathName_U_WithStatus(void) +static void test_RtlDosPathNameToNtPathName_U(void) { - static const WCHAR emptyW[] = { 0 }; + char curdir[MAX_PATH]; WCHAR path[MAX_PATH]; UNICODE_STRING nameW; + WCHAR *file_part; NTSTATUS status; + BOOL ret, expect; + int i;
- if (!pRtlDosPathNameToNtPathName_U_WithStatus) + static const struct { - win_skip("RtlDosPathNameToNtPathName_U_WithStatus() is not supported.\n"); - return; + const char *dos; + const char *nt; + int file_offset; /* offset to file part */ + NTSTATUS status; + NTSTATUS alt_status; + int broken; + } + tests[] = + { + { "c:\", "\??\c:\", -1, STATUS_SUCCESS }, + { "c:/", "\??\c:\", -1, STATUS_SUCCESS }, + { "c:/foo", "\??\c:\foo", 7, STATUS_SUCCESS }, + { "c:/foo.", "\??\c:\foo", 7, STATUS_SUCCESS }, + { "c:/foo/", "\??\c:\foo\", -1, STATUS_SUCCESS }, + { "c:/foo//", "\??\c:\foo\", -1, STATUS_SUCCESS }, + { "C:/foo", "\??\C:\foo", 7, STATUS_SUCCESS }, + { "C:/foo/bar", "\??\C:\foo\bar", 11, STATUS_SUCCESS }, + { "C:/foo/bar", "\??\C:\foo\bar", 11, STATUS_SUCCESS }, + { "c:.", "\??\C:\windows", 7, STATUS_SUCCESS }, + { "c:foo", "\??\C:\windows\foo", 15, STATUS_SUCCESS }, + { "c:foo/bar", "\??\C:\windows\foo\bar", 19, STATUS_SUCCESS }, + { "c:./foo", "\??\C:\windows\foo", 15, STATUS_SUCCESS }, + { "c:/./foo", "\??\c:\foo", 7, STATUS_SUCCESS }, + { "c:/foo/.", "\??\c:\foo", 7, STATUS_SUCCESS }, + { "c:/foo/./bar", "\??\c:\foo\bar", 11, STATUS_SUCCESS }, + { "c:/foo/../bar", "\??\c:\bar", 7, STATUS_SUCCESS }, + { "\foo", "\??\C:\foo", 7, STATUS_SUCCESS }, + { "foo", "\??\C:\windows\foo", 15, STATUS_SUCCESS }, + { ".", "\??\C:\windows", 7, STATUS_SUCCESS }, + { "./", "\??\C:\windows\", -1, STATUS_SUCCESS }, + { "..", "\??\C:\", -1, STATUS_SUCCESS }, + { "...", "\??\C:\windows\", -1, STATUS_SUCCESS }, + { "./foo", "\??\C:\windows\foo", 15, STATUS_SUCCESS }, + { "foo/..", "\??\C:\windows", 7, STATUS_SUCCESS }, + { "AUX" , "\??\AUX", -1, STATUS_SUCCESS }, + { "COM1" , "\??\COM1", -1, STATUS_SUCCESS }, + { "?<>*"|:", "\??\C:\windows\?<>*"|:", 15, STATUS_SUCCESS }, + + { "", NULL, -1, STATUS_OBJECT_NAME_INVALID, STATUS_OBJECT_PATH_NOT_FOUND }, + { NULL, NULL, -1, STATUS_OBJECT_NAME_INVALID, STATUS_OBJECT_PATH_NOT_FOUND }, + { " ", NULL, -1, STATUS_OBJECT_NAME_INVALID, STATUS_OBJECT_PATH_NOT_FOUND }, + + { "\\foo", "\??\UNC\foo", -1, STATUS_SUCCESS }, + { "//foo", "\??\UNC\foo", -1, STATUS_SUCCESS }, + { "\/foo", "\??\UNC\foo", -1, STATUS_SUCCESS }, + { "//", "\??\UNC\", -1, STATUS_SUCCESS }, + { "//foo/", "\??\UNC\foo\", -1, STATUS_SUCCESS }, + + { "//.", "\??\", -1, STATUS_SUCCESS }, + { "//./", "\??\", -1, STATUS_SUCCESS }, + { "//.//", "\??\", -1, STATUS_SUCCESS }, + { "//./foo", "\??\foo", 4, STATUS_SUCCESS }, + { "//./foo/", "\??\foo\", -1, STATUS_SUCCESS }, + { "//./foo/bar", "\??\foo\bar", 8, STATUS_SUCCESS }, + { "//./foo/.", "\??\foo", 4, STATUS_SUCCESS }, + { "//./foo/..", "\??\", -1, STATUS_SUCCESS }, + + { "//?", "\??\", -1, STATUS_SUCCESS }, + { "//?/", "\??\", -1, STATUS_SUCCESS }, + { "//?//", "\??\", -1, STATUS_SUCCESS }, + { "//?/foo", "\??\foo", 4, STATUS_SUCCESS }, + { "//?/foo/", "\??\foo\", -1, STATUS_SUCCESS }, + { "//?/foo/bar", "\??\foo\bar", 8, STATUS_SUCCESS }, + { "//?/foo/.", "\??\foo", 4, STATUS_SUCCESS }, + { "//?/foo/..", "\??\", -1, STATUS_SUCCESS }, + + { "\\?", "\??\", -1, STATUS_SUCCESS }, + { "\\?\", "\??\", -1, STATUS_SUCCESS }, + + { "\\?\/", "\??\/", 4, STATUS_SUCCESS }, + { "\\?\foo", "\??\foo", 4, STATUS_SUCCESS }, + { "\\?\foo/", "\??\foo/", 4, STATUS_SUCCESS }, + { "\\?\foo/bar", "\??\foo/bar", 4, STATUS_SUCCESS }, + { "\\?\foo/.", "\??\foo/.", 4, STATUS_SUCCESS }, + { "\\?\foo/..", "\??\foo/..", 4, STATUS_SUCCESS }, + { "\\?\\", "\??\\", -1, STATUS_SUCCESS }, + { "\\?\\\", "\??\\\", -1, STATUS_SUCCESS }, + { "\\?\foo\", "\??\foo\", -1, STATUS_SUCCESS }, + { "\\?\foo\bar", "\??\foo\bar", 8, STATUS_SUCCESS }, + { "\\?\foo\.", "\??\foo\.", 8, STATUS_SUCCESS }, + { "\\?\foo\..", "\??\foo\..", 8, STATUS_SUCCESS }, + }; + + GetCurrentDirectoryA(sizeof(curdir), curdir); + SetCurrentDirectoryA("C:\windows\"); + + for (i = 0; i < ARRAY_SIZE(tests); ++i) + { + MultiByteToWideChar(CP_ACP, 0, tests[i].dos, -1, path, sizeof(path)); + ret = pRtlDosPathNameToNtPathName_U(path, &nameW, &file_part, NULL); + + if (pRtlDosPathNameToNtPathName_U_WithStatus) + { + status = pRtlDosPathNameToNtPathName_U_WithStatus(path, &nameW, &file_part, NULL); + ok(status == tests[i].status || status == tests[i].alt_status, + "%s: Expected status %#x, got %#x.\n", tests[i].dos, tests[i].status, status); + } + + expect = (tests[i].status == STATUS_SUCCESS); + ok(ret == expect, "%s: Expected %#x, got %#x.\n", tests[i].dos, expect, ret); + + if (ret != TRUE) continue; + + MultiByteToWideChar(CP_ACP, 0, tests[i].nt, -1, path, sizeof(path)); + ok(!lstrcmpW(nameW.Buffer, path), "%s: Expected %s, got %s.\n", + tests[i].dos, tests[i].nt, wine_dbgstr_w(nameW.Buffer)); + + if (tests[i].file_offset > 0) + ok(file_part == nameW.Buffer + tests[i].file_offset, + "%s: Expected file part %s, got %s.\n", tests[i].dos, + wine_dbgstr_w(nameW.Buffer + tests[i].file_offset), wine_dbgstr_w(file_part)); + else + ok(file_part == NULL, "%s: Expected NULL file part, got %s.\n", + tests[i].dos, wine_dbgstr_w(file_part)); + + RtlFreeUnicodeString(&nameW); }
- GetCurrentDirectoryW( MAX_PATH, path ); - - status = pRtlDosPathNameToNtPathName_U_WithStatus( path, &nameW, NULL, NULL ); - ok(!status, "Failed convert to nt path, %#x.\n", status); - - status = pRtlDosPathNameToNtPathName_U_WithStatus( NULL, &nameW, NULL, NULL ); - ok(status == STATUS_OBJECT_NAME_INVALID || broken(status == STATUS_OBJECT_PATH_NOT_FOUND) /* W2k3 */, - "Unexpected status %#x.\n", status); - - status = pRtlDosPathNameToNtPathName_U_WithStatus( emptyW, &nameW, NULL, NULL ); - ok(status == STATUS_OBJECT_NAME_INVALID || broken(status == STATUS_OBJECT_PATH_NOT_FOUND) /* W2k3 */, - "Unexpected status %#x.\n", status); - - RtlFreeUnicodeString( &nameW ); + SetCurrentDirectoryA(curdir); }
START_TEST(path) @@ -437,11 +543,12 @@ START_TEST(path) pRtlOemStringToUnicodeString = (void *)GetProcAddress(mod,"RtlOemStringToUnicodeString"); pRtlIsNameLegalDOS8Dot3 = (void *)GetProcAddress(mod,"RtlIsNameLegalDOS8Dot3"); pRtlGetFullPathName_U = (void *)GetProcAddress(mod,"RtlGetFullPathName_U"); + pRtlDosPathNameToNtPathName_U = (void *)GetProcAddress(mod, "RtlDosPathNameToNtPathName_U"); pRtlDosPathNameToNtPathName_U_WithStatus = (void *)GetProcAddress(mod, "RtlDosPathNameToNtPathName_U_WithStatus");
test_RtlDetermineDosPathNameType_U(); test_RtlIsDosDeviceName_U(); test_RtlIsNameLegalDOS8Dot3(); test_RtlGetFullPathName_U(); - test_RtlDosPathNameToNtPathName_U_WithStatus(); + test_RtlDosPathNameToNtPathName_U(); }
Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=45654 Signed-off-by: Zebediah Figura z.figura12@gmail.com --- dlls/ntdll/path.c | 6 ++++-- dlls/ntdll/tests/path.c | 25 +++++++++++++++++++++++++ 2 files changed, 29 insertions(+), 2 deletions(-)
diff --git a/dlls/ntdll/path.c b/dlls/ntdll/path.c index 8fe61da..9794b67 100644 --- a/dlls/ntdll/path.c +++ b/dlls/ntdll/path.c @@ -340,7 +340,8 @@ ULONG WINAPI RtlIsDosDeviceName_U( PCWSTR dos_name ) NTSTATUS WINAPI RtlDosPathNameToNtPathName_U_WithStatus(const WCHAR *dos_path, UNICODE_STRING *ntpath, WCHAR **file_part, CURDIR *cd) { - static const WCHAR LongFileNamePfxW[] = {'\','\','?','\'}; + static const WCHAR global_prefix[] = {'\','\','?','\'}; + static const WCHAR global_prefix2[] = {'\','?','?','\'}; ULONG sz, offset; WCHAR local[MAX_PATH]; LPWSTR ptr; @@ -356,7 +357,8 @@ NTSTATUS WINAPI RtlDosPathNameToNtPathName_U_WithStatus(const WCHAR *dos_path, U if (!dos_path || !*dos_path) return STATUS_OBJECT_NAME_INVALID;
- if (!strncmpW(dos_path, LongFileNamePfxW, 4)) + if (!memcmp(dos_path, global_prefix, sizeof(global_prefix)) || + (!memcmp(dos_path, global_prefix2, sizeof(global_prefix2)) && dos_path[4])) { ntpath->Length = strlenW(dos_path) * sizeof(WCHAR); ntpath->MaximumLength = ntpath->Length + sizeof(WCHAR); diff --git a/dlls/ntdll/tests/path.c b/dlls/ntdll/tests/path.c index a032092..7baf474 100644 --- a/dlls/ntdll/tests/path.c +++ b/dlls/ntdll/tests/path.c @@ -396,6 +396,8 @@ static void test_RtlGetFullPathName_U(void)
static void test_RtlDosPathNameToNtPathName_U(void) { + static const WCHAR broken_global_prefix[] = {'\','?','?','\','C',':','\','?','?'}; + char curdir[MAX_PATH]; WCHAR path[MAX_PATH]; UNICODE_STRING nameW; @@ -487,6 +489,22 @@ static void test_RtlDosPathNameToNtPathName_U(void) { "\\?\foo\bar", "\??\foo\bar", 8, STATUS_SUCCESS }, { "\\?\foo\.", "\??\foo\.", 8, STATUS_SUCCESS }, { "\\?\foo\..", "\??\foo\..", 8, STATUS_SUCCESS }, + + { "\??", "\??\C:\??", 7, STATUS_SUCCESS }, + { "\??\", "\??\C:\??\", -1, STATUS_SUCCESS }, + + { "\??\/", "\??\/", 4, STATUS_SUCCESS }, + { "\??\foo", "\??\foo", 4, STATUS_SUCCESS }, + { "\??\foo/", "\??\foo/", 4, STATUS_SUCCESS }, + { "\??\foo/bar", "\??\foo/bar", 4, STATUS_SUCCESS }, + { "\??\foo/.", "\??\foo/.", 4, STATUS_SUCCESS }, + { "\??\foo/..", "\??\foo/..", 4, STATUS_SUCCESS }, + { "\??\\", "\??\\", -1, STATUS_SUCCESS }, + { "\??\\\", "\??\\\", -1, STATUS_SUCCESS }, + { "\??\foo\", "\??\foo\", -1, STATUS_SUCCESS }, + { "\??\foo\bar", "\??\foo\bar", 8, STATUS_SUCCESS }, + { "\??\foo\.", "\??\foo\.", 8, STATUS_SUCCESS }, + { "\??\foo\..", "\??\foo\..", 8, STATUS_SUCCESS }, };
GetCurrentDirectoryA(sizeof(curdir), curdir); @@ -509,6 +527,13 @@ static void test_RtlDosPathNameToNtPathName_U(void)
if (ret != TRUE) continue;
+ if (!strncmp(tests[i].dos, "\??\", 4) && tests[i].dos[4] && + broken(!memcmp(nameW.Buffer, broken_global_prefix, sizeof(broken_global_prefix)))) + { + /* Windows version prior to 2003 don't interpret the ??\ prefix */ + continue; + } + MultiByteToWideChar(CP_ACP, 0, tests[i].nt, -1, path, sizeof(path)); ok(!lstrcmpW(nameW.Buffer, path), "%s: Expected %s, got %s.\n", tests[i].dos, tests[i].nt, wine_dbgstr_w(nameW.Buffer));