relative optional parameter will now be handled by setting the RelativeName of the relative struct to NT converted and collapsed relative path and the ContainingDirectory to an open handle of current working directory. CurDir is currently not implemented.
-- v5: ntdll/tests: Tests for RtlDosPathNameToRelativeNtPathName_U_WithStatus ntdll: Implement handling of relative in RtlDosPathNameToRelativeNtPathName_U_WithStatus
From: Rayhan Faizel rayhan.faizel@hotmail.com
--- dlls/ntdll/path.c | 229 +++++++++++++++++++++++++++++----------------- 1 file changed, 147 insertions(+), 82 deletions(-)
diff --git a/dlls/ntdll/path.c b/dlls/ntdll/path.c index 37ad4bbcea2..d8d487ec0e9 100644 --- a/dlls/ntdll/path.c +++ b/dlls/ntdll/path.c @@ -290,7 +290,6 @@ NTSTATUS WINAPI RtlDosPathNameToNtPathName_U_WithStatus(const WCHAR *dos_path, U *file_part = ntpath->Buffer + ntpath->Length / sizeof(WCHAR) - wcslen(*file_part);
/* FIXME: cd filling */ - out: if (ptr != local) RtlFreeHeap(GetProcessHeap(), 0, ptr); return nts; @@ -309,6 +308,82 @@ BOOLEAN WINAPI RtlDosPathNameToNtPathName_U(PCWSTR dos_path, return RtlDosPathNameToNtPathName_U_WithStatus(dos_path, ntpath, file_part, cd) == STATUS_SUCCESS; }
+ + +/****************************************************************** + * collapse_path + * + * Helper for RtlGetFullPathName_U. + * Get rid of . and .. components in the path. + */ +static inline void collapse_path( WCHAR *path, UINT mark ) +{ + WCHAR *p, *next; + + /* convert every / into a \ */ + for (p = path; *p; p++) if (*p == '/') *p = '\'; + + /* collapse duplicate backslashes */ + next = path + max( 1, mark ); + for (p = next; *p; p++) if (*p != '\' || next[-1] != '\') *next++ = *p; + *next = 0; + + p = path + mark; + while (*p) + { + if (*p == '.') + { + switch(p[1]) + { + case '\': /* .\ component */ + next = p + 2; + memmove( p, next, (wcslen(next) + 1) * sizeof(WCHAR) ); + continue; + case 0: /* final . */ + if (p > path + mark) p--; + *p = 0; + continue; + case '.': + if (p[2] == '\') /* ..\ component */ + { + next = p + 3; + if (p > path + mark) + { + p--; + while (p > path + mark && p[-1] != '\') p--; + } + memmove( p, next, (wcslen(next) + 1) * sizeof(WCHAR) ); + continue; + } + else if (!p[2]) /* final .. */ + { + if (p > path + mark) + { + p--; + while (p > path + mark && p[-1] != '\') p--; + if (p > path + mark) p--; + } + *p = 0; + continue; + } + break; + } + } + /* skip to the next component */ + while (*p && *p != '\') p++; + if (*p == '\') + { + /* remove last dot in previous dir name */ + if (p > path + mark && p[-1] == '.') memmove( p-1, p, (wcslen(p) + 1) * sizeof(WCHAR) ); + else p++; + } + } + + /* remove trailing spaces and dots (yes, Windows really does that, don't ask) */ + while (p > path + mark && (p[-1] == ' ' || p[-1] == '.')) p--; + *p = 0; +} + /************************************************************************** * RtlDosPathNameToRelativeNtPathName_U_WithStatus [NTDLL.@] * @@ -317,17 +392,83 @@ BOOLEAN WINAPI RtlDosPathNameToNtPathName_U(PCWSTR dos_path, NTSTATUS WINAPI RtlDosPathNameToRelativeNtPathName_U_WithStatus(const WCHAR *dos_path, UNICODE_STRING *ntpath, WCHAR **file_part, RTL_RELATIVE_NAME *relative) { + + NTSTATUS ret; TRACE("(%s,%p,%p,%p)\n", debugstr_w(dos_path), ntpath, file_part, relative);
+ + ret = RtlDosPathNameToNtPathName_U_WithStatus(dos_path, ntpath, file_part, NULL); + if (relative) { - FIXME("Unsupported parameter\n"); - memset(relative, 0, sizeof(*relative)); - } + DOS_PATHNAME_TYPE type = RtlDetermineDosPathNameType_U(dos_path); + DWORD dosdev = RtlIsDosDeviceName_U(dos_path); + + relative->RelativeName.Buffer = NULL; + relative->ContainerDirectory = 0; + relative->CurDirRef = NULL; + + if (type == RELATIVE_PATH && !dosdev) + { + HANDLE handle;
- /* FIXME: fill parameter relative */ + IO_STATUS_BLOCK io; + OBJECT_ATTRIBUTES attr; + NTSTATUS ret_rel, nts; + UNICODE_STRING *cur_dir, cur_dir_nt; + int dos_path_len = wcslen(dos_path); + + WCHAR *converted_path = RtlAllocateHeap(GetProcessHeap(), 0, (dos_path_len+1) * sizeof(WCHAR));; + wcscpy(converted_path, dos_path); + collapse_path(converted_path, 0); + + /* RTL_Relative_name is filled for ./ and ... on real Windows for whatever reason, so we will make exceptions for these */ + if (wcscmp(dos_path,L"./") && wcscmp(dos_path,L".\") && wcscmp(dos_path,L"...") && wcslen(converted_path) == 0) + { + /* Collapsed path is empty so don't bother */ + memset(relative,0,sizeof(*relative)); + goto out; + } + + RtlInitUnicodeString(&(relative->RelativeName),converted_path);
- return RtlDosPathNameToNtPathName_U_WithStatus(dos_path, ntpath, file_part, NULL); + if (NtCurrentTeb()->Tib.SubSystemTib) /* FIXME: hack */ + cur_dir = &((WIN16_SUBSYSTEM_TIB *)NtCurrentTeb()->Tib.SubSystemTib)->curdir.DosPath; + else + cur_dir = &NtCurrentTeb()->Peb->ProcessParameters->CurrentDirectory.DosPath; + + /* FIXME: Better way besides invoking this function twice? Maybe a more direct way of getting current dir in nt path form? */ + ret_rel = RtlDosPathNameToNtPathName_U_WithStatus(cur_dir->Buffer, &cur_dir_nt, NULL, NULL); + if (ret_rel == STATUS_SUCCESS) + { + attr.Length = sizeof(attr); + attr.RootDirectory = 0; + attr.Attributes = OBJ_CASE_INSENSITIVE; + attr.ObjectName = &cur_dir_nt; + attr.SecurityDescriptor = NULL; + attr.SecurityQualityOfService = NULL; + + /* Give open directory handle */ + nts = NtOpenFile(&handle, FILE_READ_ATTRIBUTES | SYNCHRONIZE, &attr, &io, + FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, + FILE_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT); + + if (nts == STATUS_SUCCESS) + relative->ContainerDirectory = handle; + RtlFreeUnicodeString(&cur_dir_nt); + } + + + /* FIXME: No idea what this does. Some reference count or something? */ + relative->CurDirRef = NULL; + } + else + { + memset(relative,0,sizeof(*relative)); + } + } + out: + return ret; }
/************************************************************************** @@ -416,82 +557,6 @@ ULONG WINAPI RtlDosSearchPath_U(LPCWSTR paths, LPCWSTR search, LPCWSTR ext, return len; }
- -/****************************************************************** - * collapse_path - * - * Helper for RtlGetFullPathName_U. - * Get rid of . and .. components in the path. - */ -static inline void collapse_path( WCHAR *path, UINT mark ) -{ - WCHAR *p, *next; - - /* convert every / into a \ */ - for (p = path; *p; p++) if (*p == '/') *p = '\'; - - /* collapse duplicate backslashes */ - next = path + max( 1, mark ); - for (p = next; *p; p++) if (*p != '\' || next[-1] != '\') *next++ = *p; - *next = 0; - - p = path + mark; - while (*p) - { - if (*p == '.') - { - switch(p[1]) - { - case '\': /* .\ component */ - next = p + 2; - memmove( p, next, (wcslen(next) + 1) * sizeof(WCHAR) ); - continue; - case 0: /* final . */ - if (p > path + mark) p--; - *p = 0; - continue; - case '.': - if (p[2] == '\') /* ..\ component */ - { - next = p + 3; - if (p > path + mark) - { - p--; - while (p > path + mark && p[-1] != '\') p--; - } - memmove( p, next, (wcslen(next) + 1) * sizeof(WCHAR) ); - continue; - } - else if (!p[2]) /* final .. */ - { - if (p > path + mark) - { - p--; - while (p > path + mark && p[-1] != '\') p--; - if (p > path + mark) p--; - } - *p = 0; - continue; - } - break; - } - } - /* skip to the next component */ - while (*p && *p != '\') p++; - if (*p == '\') - { - /* remove last dot in previous dir name */ - if (p > path + mark && p[-1] == '.') memmove( p-1, p, (wcslen(p) + 1) * sizeof(WCHAR) ); - else p++; - } - } - - /* remove trailing spaces and dots (yes, Windows really does that, don't ask) */ - while (p > path + mark && (p[-1] == ' ' || p[-1] == '.')) p--; - *p = 0; -} - - /****************************************************************** * skip_unc_prefix *
From: Rayhan Faizel rayhan.faizel@hotmail.com
--- dlls/ntdll/tests/path.c | 270 ++++++++++++++++++++++------------------ 1 file changed, 148 insertions(+), 122 deletions(-)
diff --git a/dlls/ntdll/tests/path.c b/dlls/ntdll/tests/path.c index 4732f6a6aa8..a67c108c14d 100644 --- a/dlls/ntdll/tests/path.c +++ b/dlls/ntdll/tests/path.c @@ -31,6 +31,7 @@ static BOOLEAN (WINAPI *pRtlIsNameLegalDOS8Dot3)(const UNICODE_STRING*,POEM_STRI 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 NTSTATUS (WINAPI* pRtlDosPathNameToRelativeNtPathName_U_WithStatus)(const WCHAR *dos_path,UNICODE_STRING *ntpath, WCHAR **file_part, RTL_RELATIVE_NAME *relative); static NTSTATUS (WINAPI *pNtOpenFile)( HANDLE*, ACCESS_MASK, OBJECT_ATTRIBUTES*, IO_STATUS_BLOCK*, ULONG, ULONG );
static void test_RtlDetermineDosPathNameType_U(void) @@ -434,134 +435,141 @@ static void test_RtlDosPathNameToNtPathName_U(void) const WCHAR *dos; const WCHAR *nt; int file_offset; /* offset to file part */ + const WCHAR* relative; const WCHAR *alt_nt; + const WCHAR *alt_relative; BOOL may_fail; } tests[] = { - {L"c:\", L"\??\c:\", -1}, - {L"c:/", L"\??\c:\", -1}, - {L"c:/foo", L"\??\c:\foo", 7}, - {L"c:/foo.", L"\??\c:\foo", 7}, - {L"c:/foo ", L"\??\c:\foo", 7}, - {L"c:/foo . .", L"\??\c:\foo", 7}, - {L"c:/foo.a", L"\??\c:\foo.a", 7}, - {L"c:/foo a", L"\??\c:\foo a", 7}, - {L"c:/foo*", L"\??\c:\foo*", 7}, - {L"c:/foo*a", L"\??\c:\foo*a", 7}, - {L"c:/foo?", L"\??\c:\foo?", 7}, - {L"c:/foo?a", L"\??\c:\foo?a", 7}, - {L"c:/foo<", L"\??\c:\foo<", 7}, - {L"c:/foo<a", L"\??\c:\foo<a", 7}, - {L"c:/foo>", L"\??\c:\foo>", 7}, - {L"c:/foo>a", L"\??\c:\foo>a", 7}, - {L"c:/foo/", L"\??\c:\foo\", -1}, - {L"c:/foo//", L"\??\c:\foo\", -1}, - {L"C:/foo", L"\??\C:\foo", 7}, - {L"C:/foo/bar", L"\??\C:\foo\bar", 11}, - {L"C:/foo/bar", L"\??\C:\foo\bar", 11}, - {L"c:.", L"\??\C:\windows", 7}, - {L"c:foo", L"\??\C:\windows\foo", 15}, - {L"c:foo/bar", L"\??\C:\windows\foo\bar", 19}, - {L"c:./foo", L"\??\C:\windows\foo", 15}, - {L"c:/./foo", L"\??\c:\foo", 7}, - {L"c:/..", L"\??\c:\", -1}, - {L"c:/foo/.", L"\??\c:\foo", 7}, - {L"c:/foo/./bar", L"\??\c:\foo\bar", 11}, - {L"c:/foo/../bar", L"\??\c:\bar", 7}, - {L"\foo", L"\??\C:\foo", 7}, - {L"foo", L"\??\C:\windows\foo", 15}, - {L".", L"\??\C:\windows", 7}, - {L"./", L"\??\C:\windows\", -1}, - {L"..", L"\??\C:\", -1}, - {L"...", L"\??\C:\windows\", -1}, - {L"./foo", L"\??\C:\windows\foo", 15}, - {L"foo/..", L"\??\C:\windows", 7}, - {L"\windows\nul", L"\??\nul", -1}, - {L"C:NUL.", L"\??\NUL", -1}, - {L"C:NUL", L"\??\NUL", -1}, - {L"AUX" , L"\??\AUX", -1}, - {L"COM1" , L"\??\COM1", -1}, - {L"?<>*"|:", L"\??\C:\windows\?<>*"|:", 15}, - {L"?:", L"\??\?:\", -1}, - - {L"\\foo", L"\??\UNC\foo", -1}, - {L"//foo", L"\??\UNC\foo", -1}, - {L"\/foo", L"\??\UNC\foo", -1}, - {L"//", L"\??\UNC\", -1}, - {L"//foo/", L"\??\UNC\foo\", -1}, - - {L"//.", L"\??\", -1}, - {L"//./", L"\??\", -1}, - {L"//.//", L"\??\", -1}, - {L"//./foo", L"\??\foo", 4}, - {L"//./foo/", L"\??\foo\", -1}, - {L"//./foo/bar", L"\??\foo\bar", 8}, - {L"//./foo/.", L"\??\foo", 4}, - {L"//./foo/..", L"\??\", -1}, - {L"//./foo. . ", L"\??\foo", 4}, - - {L"//?", L"\??\", -1}, - {L"//?/", L"\??\", -1}, - {L"//?//", L"\??\", -1}, - {L"//?/foo", L"\??\foo", 4}, - {L"//?/foo/", L"\??\foo\", -1}, - {L"//?/foo/bar", L"\??\foo\bar", 8}, - {L"//?/foo/.", L"\??\foo", 4}, - {L"//?/foo/..", L"\??\", -1}, - {L"//?/foo. . ", L"\??\foo", 4}, - - {L"\\.", L"\??\", -1}, - {L"\\.\", L"\??\", -1}, - {L"\\.\/", L"\??\", -1}, - {L"\\.\foo", L"\??\foo", 4}, - {L"\\.\foo/", L"\??\foo\", -1}, - {L"\\.\foo/bar", L"\??\foo\bar", 8}, - {L"\\.\foo/.", L"\??\foo", 4}, - {L"\\.\foo/..", L"\??\", -1}, - {L"\\.\foo. . ", L"\??\foo", 4}, - {L"\\.\CON", L"\??\CON", 4, NULL, TRUE}, /* broken on win7 */ - {L"\\.\CONIN$", L"\??\CONIN$", 4}, - {L"\\.\CONOUT$", L"\??\CONOUT$", 4}, + {L"c:\", L"\??\c:\", -1, NULL}, + {L"c:/", L"\??\c:\", -1, NULL}, + {L"c:/foo", L"\??\c:\foo", 7, NULL}, + {L"c:/foo.", L"\??\c:\foo", 7, NULL}, + {L"c:/foo ", L"\??\c:\foo", 7, NULL}, + {L"c:/foo . .", L"\??\c:\foo", 7, NULL}, + {L"c:/foo.a", L"\??\c:\foo.a", 7, NULL}, + {L"c:/foo a", L"\??\c:\foo a", 7, NULL}, + {L"c:/foo*", L"\??\c:\foo*", 7, NULL}, + {L"c:/foo*a", L"\??\c:\foo*a", 7, NULL}, + {L"c:/foo?", L"\??\c:\foo?", 7, NULL}, + {L"c:/foo?a", L"\??\c:\foo?a", 7, NULL}, + {L"c:/foo<", L"\??\c:\foo<", 7, NULL}, + {L"c:/foo<a", L"\??\c:\foo<a", 7, NULL}, + {L"c:/foo>", L"\??\c:\foo>", 7, NULL}, + {L"c:/foo>a", L"\??\c:\foo>a", 7, NULL}, + {L"c:/foo/", L"\??\c:\foo\", -1, NULL}, + {L"c:/foo//", L"\??\c:\foo\", -1, NULL}, + {L"C:/foo", L"\??\C:\foo", 7, NULL}, + {L"C:/foo/bar", L"\??\C:\foo\bar", 11, NULL}, + {L"C:/foo/bar", L"\??\C:\foo\bar", 11, NULL}, + {L"c:.", L"\??\C:\windows", 7, NULL}, + {L"c:foo", L"\??\C:\windows\foo", 15, NULL}, + {L"c:foo/bar", L"\??\C:\windows\foo\bar", 19, NULL}, + {L"c:./foo", L"\??\C:\windows\foo", 15, NULL}, + {L"c:/./foo", L"\??\c:\foo", 7, NULL}, + {L"c:/..", L"\??\c:\", -1, NULL}, + {L"c:/foo/.", L"\??\c:\foo", 7, NULL}, + {L"c:/foo/./bar", L"\??\c:\foo\bar", 11, NULL}, + {L"c:/foo/../bar", L"\??\c:\bar", 7, NULL}, + {L"\foo", L"\??\C:\foo", 7, NULL}, + {L"foo", L"\??\C:\windows\foo", 15, L"foo"}, + {L".", L"\??\C:\windows", 7, NULL}, + {L"./", L"\??\C:\windows\", -1, L""}, + {L"..", L"\??\C:\", -1, NULL}, + {L"...", L"\??\C:\windows\", -1, L""}, + {L"./foo", L"\??\C:\windows\foo", 15, L"foo"}, + {L"./foo/bar", L"\??\C:\windows\foo\bar", 19, L"foo\bar"}, + + {L"foo/bar/baz", L"\??\C:\windows\foo\bar\baz", 23, L"foo\bar\baz"}, + {L"foo/bar/baz/..", L"\??\C:\windows\foo\bar", 19, L"foo\bar"}, + {L"foo/../..", L"\??\C:\", -1, NULL}, + + {L"\windows\nul", L"\??\nul", -1, NULL}, + {L"C:NUL.", L"\??\NUL", -1, NULL}, + {L"C:NUL", L"\??\NUL", -1, NULL}, + {L"AUX" , L"\??\AUX", -1, NULL}, + {L"COM1" , L"\??\COM1", -1, NULL}, + {L"?<>*"|:", L"\??\C:\windows\?<>*"|:", 15, L"?<>*"|:"}, + {L"?:", L"\??\?:\", -1, NULL}, + + {L"\\foo", L"\??\UNC\foo", -1, NULL}, + {L"//foo", L"\??\UNC\foo", -1, NULL}, + {L"\/foo", L"\??\UNC\foo", -1, NULL}, + {L"//", L"\??\UNC\", -1, NULL}, + {L"//foo/", L"\??\UNC\foo\", -1, NULL}, + + {L"//.", L"\??\", -1, NULL}, + {L"//./", L"\??\", -1, NULL}, + {L"//.//", L"\??\", -1, NULL}, + {L"//./foo", L"\??\foo", 4, NULL}, + {L"//./foo/", L"\??\foo\", -1, NULL}, + {L"//./foo/bar", L"\??\foo\bar", 8, NULL}, + {L"//./foo/.", L"\??\foo", 4, NULL}, + {L"//./foo/..", L"\??\", -1, NULL}, + {L"//./foo. . ", L"\??\foo", 4, NULL}, + + {L"//?", L"\??\", -1,NULL}, + {L"//?/", L"\??\", -1, NULL}, + {L"//?//", L"\??\", -1,NULL}, + {L"//?/foo", L"\??\foo", 4,NULL}, + {L"//?/foo/", L"\??\foo\", -1, NULL}, + {L"//?/foo/bar", L"\??\foo\bar", 8, NULL}, + {L"//?/foo/.", L"\??\foo", 4, NULL}, + {L"//?/foo/..", L"\??\", -1, NULL}, + {L"//?/foo. . ", L"\??\foo", 4, NULL}, + + {L"\\.", L"\??\", -1, NULL}, + {L"\\.\", L"\??\", -1, NULL}, + {L"\\.\/", L"\??\", -1, NULL}, + {L"\\.\foo", L"\??\foo", 4, NULL}, + {L"\\.\foo/", L"\??\foo\", -1, NULL}, + {L"\\.\foo/bar", L"\??\foo\bar", 8, NULL}, + {L"\\.\foo/.", L"\??\foo", 4, NULL}, + {L"\\.\foo/..", L"\??\", -1, NULL}, + {L"\\.\foo. . ", L"\??\foo", 4, NULL}, + {L"\\.\CON", L"\??\CON", 4, NULL,NULL, NULL, TRUE}, /* broken on win7 */ + {L"\\.\CONIN$", L"\??\CONIN$", 4, NULL}, + {L"\\.\CONOUT$", L"\??\CONOUT$", 4, NULL},
{L"\\?", L"\??\", -1}, - {L"\\?\", L"\??\", -1}, - - {L"\\?\/", L"\??\/", 4}, - {L"\\?\foo", L"\??\foo", 4}, - {L"\\?\foo/", L"\??\foo/", 4}, - {L"\\?\foo/bar", L"\??\foo/bar", 4}, - {L"\\?\foo/.", L"\??\foo/.", 4}, - {L"\\?\foo/..", L"\??\foo/..", 4}, - {L"\\?\\", L"\??\\", -1}, - {L"\\?\\\", L"\??\\\", -1}, - {L"\\?\foo\", L"\??\foo\", -1}, - {L"\\?\foo\bar",L"\??\foo\bar", 8}, - {L"\\?\foo\.", L"\??\foo\.", 8}, - {L"\\?\foo\..", L"\??\foo\..", 8}, - {L"\\?\foo. . ", L"\??\foo. . ", 4}, - - {L"\??", L"\??\C:\??", 7}, - {L"\??\", L"\??\C:\??\", -1}, - - {L"\??\/", L"\??\/", 4}, - {L"\??\foo", L"\??\foo", 4}, - {L"\??\foo/", L"\??\foo/", 4}, - {L"\??\foo/bar", L"\??\foo/bar", 4}, - {L"\??\foo/.", L"\??\foo/.", 4}, - {L"\??\foo/..", L"\??\foo/..", 4}, - {L"\??\\", L"\??\\", -1}, - {L"\??\\\", L"\??\\\", -1}, - {L"\??\foo\", L"\??\foo\", -1}, - {L"\??\foo\bar", L"\??\foo\bar", 8}, - {L"\??\foo\.", L"\??\foo\.", 8}, - {L"\??\foo\..", L"\??\foo\..", 8}, - {L"\??\foo. . ", L"\??\foo. . ", 4}, - - {L"CONIN$", L"\??\CONIN$", -1, L"\??\C:\windows\CONIN$" /* win7 */ }, - {L"CONOUT$", L"\??\CONOUT$", -1, L"\??\C:\windows\CONOUT$" /* win7 */ }, - {L"cOnOuT$", L"\??\cOnOuT$", -1, L"\??\C:\windows\cOnOuT$" /* win7 */ }, - {L"CONERR$", L"\??\C:\windows\CONERR$", 15}, + {L"\\?\", L"\??\", -1, NULL}, + + {L"\\?\/", L"\??\/", 4, NULL}, + {L"\\?\foo", L"\??\foo", 4, NULL}, + {L"\\?\foo/", L"\??\foo/", 4, NULL}, + {L"\\?\foo/bar", L"\??\foo/bar", 4, NULL}, + {L"\\?\foo/.", L"\??\foo/.", 4, NULL}, + {L"\\?\foo/..", L"\??\foo/..", 4, NULL}, + {L"\\?\\", L"\??\\", -1, NULL}, + {L"\\?\\\", L"\??\\\", -1, NULL}, + {L"\\?\foo\", L"\??\foo\", -1, NULL}, + {L"\\?\foo\bar",L"\??\foo\bar", 8, NULL}, + {L"\\?\foo\.", L"\??\foo\.", 8, NULL}, + {L"\\?\foo\..", L"\??\foo\..", 8, NULL}, + {L"\\?\foo. . ", L"\??\foo. . ", 4, NULL}, + + {L"\??", L"\??\C:\??", 7, NULL}, + {L"\??\", L"\??\C:\??\", -1, NULL}, + + {L"\??\/", L"\??\/", 4, NULL}, + {L"\??\foo", L"\??\foo", 4, NULL}, + {L"\??\foo/", L"\??\foo/", 4, NULL}, + {L"\??\foo/bar", L"\??\foo/bar", 4, NULL}, + {L"\??\foo/.", L"\??\foo/.", 4, NULL}, + {L"\??\foo/..", L"\??\foo/..", 4, NULL}, + {L"\??\\", L"\??\\", -1, NULL}, + {L"\??\\\", L"\??\\\", -1, NULL}, + {L"\??\foo\", L"\??\foo\", -1, NULL}, + {L"\??\foo\bar", L"\??\foo\bar", 8, NULL}, + {L"\??\foo\.", L"\??\foo\.", 8, NULL}, + {L"\??\foo\..", L"\??\foo\..", 8, NULL}, + {L"\??\foo. . ", L"\??\foo. . ", 4, NULL}, + + {L"CONIN$", L"\??\CONIN$", -1, NULL,L"\??\C:\windows\CONIN$", L"CONIN$" /* win7 */ }, + {L"CONOUT$", L"\??\CONOUT$", -1, NULL,L"\??\C:\windows\CONOUT$", L"CONOUT$" /* win7 */ }, + {L"cOnOuT$", L"\??\cOnOuT$", -1, NULL,L"\??\C:\windows\cOnOuT$", L"cOnOuT$" /* win7 */ }, + {L"CONERR$", L"\??\C:\windows\CONERR$", 15, L"CONERR$"}, }; static const WCHAR *error_paths[] = { NULL, L"", L" ", L"C:\nonexistent\nul", L"C:\con\con" @@ -619,6 +627,24 @@ static void test_RtlDosPathNameToNtPathName_U(void) debugstr_w(tests[i].dos), debugstr_w(file_part)); }
+ + if (pRtlDosPathNameToRelativeNtPathName_U_WithStatus) + { + RTL_RELATIVE_NAME rtl; + + RtlFreeUnicodeString(&nameW); + status = pRtlDosPathNameToRelativeNtPathName_U_WithStatus(tests[i].dos, &nameW, &file_part, &rtl); + ok(status == STATUS_SUCCESS, "%s: Got status %#lx.\n", debugstr_w(tests[i].dos), status); + + ok((tests[i].relative && rtl.RelativeName.Buffer && !wcscmp(rtl.RelativeName.Buffer,tests[i].relative)) + || broken(tests[i].alt_relative && rtl.RelativeName.Buffer && !wcscmp(rtl.RelativeName.Buffer,tests[i].alt_relative)) + || (tests[i].relative == NULL && rtl.RelativeName.Buffer == NULL) + , + "%s: Expected relative path %s, got %s.\n", debugstr_w(tests[i].dos), debugstr_w(tests[i].relative), debugstr_w(rtl.RelativeName.Buffer)); + + ok((rtl.RelativeName.Buffer && rtl.ContainerDirectory != 0) || (rtl.RelativeName.Buffer == NULL && rtl.ContainerDirectory == 0), + "Unexpected Directory Handle: %p.\n",rtl.ContainerDirectory); + } RtlFreeUnicodeString(&nameW); }
@@ -726,7 +752,6 @@ static void test_nt_names(void) } }
- START_TEST(path) { HMODULE mod = GetModuleHandleA("ntdll.dll"); @@ -741,6 +766,7 @@ START_TEST(path) pRtlDosPathNameToNtPathName_U = (void *)GetProcAddress(mod, "RtlDosPathNameToNtPathName_U"); pRtlDosPathNameToNtPathName_U_WithStatus = (void *)GetProcAddress(mod, "RtlDosPathNameToNtPathName_U_WithStatus"); pNtOpenFile = (void *)GetProcAddress(mod, "NtOpenFile"); + pRtlDosPathNameToRelativeNtPathName_U_WithStatus = (void*) GetProcAddress(mod,"RtlDosPathNameToRelativeNtPathName_U_WithStatus");
test_RtlDetermineDosPathNameType_U(); test_RtlIsDosDeviceName_U();