Index: reactos/dll/ntdll/def/ntdll.spec =================================================================== --- reactos/dll/ntdll/def/ntdll.spec (revision 73897) +++ reactos/dll/ntdll/def/ntdll.spec (working copy) @@ -784,7 +784,7 @@ 779 stdcall RtlNewSecurityObjectEx(ptr ptr ptr ptr long long ptr ptr) 780 stdcall RtlNewSecurityObjectWithMultipleInheritance(ptr ptr ptr ptr long long long ptr ptr) 781 stdcall RtlNormalizeProcessParams(ptr) -782 stdcall RtlNtPathNameToDosPathName(ptr ptr ptr ptr) ; CHECKME +782 stdcall RtlNtPathNameToDosPathName(long ptr ptr ptr) ; CHECKME (last arg) 783 stdcall RtlNtStatusToDosError(long) 784 stdcall RtlNtStatusToDosErrorNoTeb(long) 785 stdcall RtlNumberGenericTableElements(ptr) Index: reactos/sdk/include/ndk/rtlfuncs.h =================================================================== --- reactos/sdk/include/ndk/rtlfuncs.h (revision 73897) +++ reactos/sdk/include/ndk/rtlfuncs.h (working copy) @@ -2762,7 +2762,24 @@ _Out_opt_ PRTL_RELATIVE_NAME_U DirectoryInfo ); + +#define RTL_UNCHANGED_UNK_PATH 1 +#define RTL_CONVERTED_UNC_PATH 2 +#define RTL_CONVERTED_NT_PATH 3 +#define RTL_UNCHANGED_DOS_PATH 4 + NTSYSAPI +NTSTATUS +NTAPI +RtlNtPathNameToDosPathName( + _In_ ULONG Flags, + _Inout_ RTL_UNICODE_STRING_BUFFER* Path, + _Out_opt_ ULONG* PathType, + _Out_opt_ ULONG* Unknown +); + + +NTSYSAPI BOOLEAN NTAPI RtlDosPathNameToRelativeNtPathName_U( Index: reactos/sdk/lib/rtl/path.c =================================================================== --- reactos/sdk/lib/rtl/path.c (revision 73897) +++ reactos/sdk/lib/rtl/path.c (working copy) @@ -45,6 +45,8 @@ const UNICODE_STRING RtlpDosCONDevice = RTL_CONSTANT_STRING(L"CON"); const UNICODE_STRING RtlpDosNULDevice = RTL_CONSTANT_STRING(L"NUL"); +const UNICODE_STRING RtlpDoubleSlashPrefix = RTL_CONSTANT_STRING(L"\\\\"); + PRTLP_CURDIR_REF RtlpCurDirRef; /* PRIVATE FUNCTIONS **********************************************************/ @@ -1787,13 +1789,85 @@ } /* - * @unimplemented + * @implemented */ -NTSTATUS NTAPI -RtlNtPathNameToDosPathName(ULONG Unknown1, ULONG Unknown2, ULONG Unknown3, ULONG Unknown4) +NTSTATUS NTAPI RtlNtPathNameToDosPathName(IN ULONG Flags, + IN OUT RTL_UNICODE_STRING_BUFFER* Path, + OUT ULONG* PathType, + ULONG* Unknown) { - DPRINT1("RtlNtPathNameToDosPathName: stub\n"); - return STATUS_NOT_IMPLEMENTED; + if (PathType) + *PathType = 0; + + if (!Path || Flags) + return STATUS_INVALID_PARAMETER; + + if (Path) + { + PCUNICODE_STRING UsePrefix = NULL, AlternatePrefix = NULL; + + /* The initial check is done on Path->String */ + if (RtlPrefixUnicodeString(&RtlpDosDevicesUncPrefix, &Path->String, TRUE)) + { + UsePrefix = &RtlpDosDevicesUncPrefix; + AlternatePrefix = &RtlpDoubleSlashPrefix; + if (PathType) + *PathType = RTL_CONVERTED_UNC_PATH; + } + else if (RtlPrefixUnicodeString(&RtlpDosDevicesPrefix, &Path->String, TRUE)) + { + UsePrefix = &RtlpDosDevicesPrefix; + if (PathType) + *PathType = RTL_CONVERTED_NT_PATH; + } + + if (UsePrefix) + { + USHORT Len = Path->String.Length - UsePrefix->Length; + if (AlternatePrefix) + Len += AlternatePrefix->Length; + if (Len + sizeof(UNICODE_NULL) <= Path->ByteBuffer.Size) + { + /* Then, the contents of Path->ByteBuffer are always used... */ + if (AlternatePrefix) + { + memcpy(Path->ByteBuffer.Buffer, AlternatePrefix->Buffer, AlternatePrefix->Length); + memmove(Path->ByteBuffer.Buffer + AlternatePrefix->Length, Path->ByteBuffer.Buffer + UsePrefix->Length, + Len - AlternatePrefix->Length); + } + else + { + memmove(Path->ByteBuffer.Buffer, Path->ByteBuffer.Buffer + UsePrefix->Length, Len); + } + Path->String.Buffer = (PWSTR)Path->ByteBuffer.Buffer; + Path->String.Length = Len; + Path->String.MaximumLength = Path->ByteBuffer.Size; + Path->String.Buffer[Len / sizeof(WCHAR)] = UNICODE_NULL; + } + return STATUS_SUCCESS; + } + + if (PathType) + { + switch (RtlDetermineDosPathNameType_Ustr(&Path->String)) + { + case RtlPathTypeUncAbsolute: + case RtlPathTypeDriveAbsolute: + case RtlPathTypeLocalDevice: + case RtlPathTypeRootLocalDevice: + *PathType = RTL_UNCHANGED_DOS_PATH; + break; + case RtlPathTypeUnknown: + case RtlPathTypeDriveRelative: + case RtlPathTypeRooted: + case RtlPathTypeRelative: + *PathType = RTL_UNCHANGED_UNK_PATH; + break; + } + } + } + + return STATUS_SUCCESS; } /* Index: rostests/apitests/ntdll/CMakeLists.txt =================================================================== --- rostests/apitests/ntdll/CMakeLists.txt (revision 73897) +++ rostests/apitests/ntdll/CMakeLists.txt (working copy) @@ -43,6 +43,7 @@ RtlInitializeBitMap.c RtlIsNameLegalDOS8Dot3.c RtlMemoryStream.c + RtlNtPathNameToDosPathName.c RtlReAllocateHeap.c RtlUpcaseUnicodeStringToCountedOemString.c StackOverflow.c Index: rostests/apitests/ntdll/RtlNtPathNameToDosPathName.c =================================================================== --- rostests/apitests/ntdll/RtlNtPathNameToDosPathName.c (nonexistent) +++ rostests/apitests/ntdll/RtlNtPathNameToDosPathName.c (working copy) @@ -0,0 +1,459 @@ +/* + * PROJECT: ReactOS api tests + * LICENSE: GPLv2+ - See COPYING in the top level directory + * PURPOSE: Test for RtlNtPathNameToDosPathName + * PROGRAMMER: Mark Jansen + */ + +#include + +#define WIN32_NO_STATUS +#include + +NTSTATUS (NTAPI *pRtlNtPathNameToDosPathName)(ULONG Flags, RTL_UNICODE_STRING_BUFFER* Path, ULONG* Type, ULONG* Unknown4); + +#define ok_hex_(expression, result) \ + do { \ + int _value = (expression); \ + winetest_ok(_value == (result), "Wrong value for '%s', expected: " #result " (0x%x), got: 0x%x\n", \ + #expression, (int)(result), _value); \ + } while (0) + + +#define ok_ptr_(expression, result) \ + do { \ + void *_value = (expression); \ + winetest_ok(_value == (result), "Wrong value for '%s', expected: " #result " (%p), got: %p\n", \ + #expression, (void*)(result), _value); \ + } while (0) + +#define ok_wstr_(x, y) \ + winetest_ok(wcscmp(x, y) == 0, "Wrong string. Expected '%S', got '%S'\n", y, x) + + + +struct test_entry +{ + WCHAR* InputPath; + WCHAR* OutputPath; + ULONG Type; + + const char* File; + int Line; +}; + +#ifndef RTL_UNCHANGED_UNK_PATH +#define RTL_UNCHANGED_UNK_PATH 1 +#define RTL_CONVERTED_UNC_PATH 2 +#define RTL_CONVERTED_NT_PATH 3 +#define RTL_UNCHANGED_DOS_PATH 4 +#endif + +static struct test_entry test_data[] = +{ + /* Originally from RtlGetFullPathName_*.c (edited) */ + { L"", L"", RTL_UNCHANGED_UNK_PATH, __FILE__, __LINE__ }, + { L".\\test", L".\\test", RTL_UNCHANGED_UNK_PATH, __FILE__, __LINE__ }, + { L"/test", L"/test", RTL_UNCHANGED_UNK_PATH, __FILE__, __LINE__ }, + { L"??\\", L"??\\", RTL_UNCHANGED_UNK_PATH, __FILE__, __LINE__ }, + { L"??\\C:", L"??\\C:", RTL_UNCHANGED_UNK_PATH, __FILE__, __LINE__ }, + { L"??\\C:\\", L"??\\C:\\", RTL_UNCHANGED_UNK_PATH, __FILE__, __LINE__ }, + { L"??\\C:\\test", L"??\\C:\\test", RTL_UNCHANGED_UNK_PATH, __FILE__, __LINE__ }, + { L"??\\C:\\test\\", L"??\\C:\\test\\", RTL_UNCHANGED_UNK_PATH, __FILE__, __LINE__ }, + { L"C:", L"C:", RTL_UNCHANGED_UNK_PATH, __FILE__, __LINE__ }, + { L"C:/test/", L"C:/test/", RTL_UNCHANGED_DOS_PATH, __FILE__, __LINE__ }, + { L"C:\\", L"C:\\", RTL_UNCHANGED_DOS_PATH, __FILE__, __LINE__ }, + { L"C:\\", L"C:\\", RTL_UNCHANGED_DOS_PATH, __FILE__, __LINE__ }, + { L"C:\\\\test", L"C:\\\\test", RTL_UNCHANGED_DOS_PATH, __FILE__, __LINE__ }, + { L"C:\\test", L"C:\\test", RTL_UNCHANGED_DOS_PATH, __FILE__, __LINE__ }, + { L"C:\\test", L"C:\\test", RTL_UNCHANGED_DOS_PATH, __FILE__, __LINE__ }, + { L"C:\\test", L"C:\\test", RTL_UNCHANGED_DOS_PATH, __FILE__, __LINE__ }, + { L"C:\\test\\", L"C:\\test\\", RTL_UNCHANGED_DOS_PATH, __FILE__, __LINE__ }, + { L"C:\\test\\", L"C:\\test\\", RTL_UNCHANGED_DOS_PATH, __FILE__, __LINE__ }, + { L"C:\\test\\", L"C:\\test\\", RTL_UNCHANGED_DOS_PATH, __FILE__, __LINE__ }, + { L"\\.", L"\\.", RTL_UNCHANGED_UNK_PATH, __FILE__, __LINE__ }, + { L"\\.\\", L"\\.\\", RTL_UNCHANGED_UNK_PATH, __FILE__, __LINE__ }, + { L"\\??\\", L"", RTL_CONVERTED_NT_PATH, __FILE__, __LINE__ }, + { L"\\??\\C:", L"C:", RTL_CONVERTED_NT_PATH, __FILE__, __LINE__ }, + { L"\\??\\C:\\", L"C:\\", RTL_CONVERTED_NT_PATH, __FILE__, __LINE__ }, + { L"\\??\\C:\\test", L"C:\\test", RTL_CONVERTED_NT_PATH, __FILE__, __LINE__ }, + { L"\\??\\C:\\test\\", L"C:\\test\\", RTL_CONVERTED_NT_PATH, __FILE__, __LINE__ }, + { L"\\\\.", L"\\\\.", RTL_UNCHANGED_DOS_PATH, __FILE__, __LINE__ }, + { L"\\\\.\\", L"\\\\.\\", RTL_UNCHANGED_DOS_PATH, __FILE__, __LINE__ }, + { L"\\\\.\\", L"\\\\.\\", RTL_UNCHANGED_DOS_PATH, __FILE__, __LINE__ }, + { L"\\\\.\\", L"\\\\.\\", RTL_UNCHANGED_DOS_PATH, __FILE__, __LINE__ }, + { L"\\\\.\\Something\\", L"\\\\.\\Something\\", RTL_UNCHANGED_DOS_PATH, __FILE__, __LINE__ }, + { L"\\\\.\\Something\\", L"\\\\.\\Something\\", RTL_UNCHANGED_DOS_PATH, __FILE__, __LINE__ }, + { L"\\\\??\\", L"\\\\??\\", RTL_UNCHANGED_DOS_PATH, __FILE__, __LINE__ }, + { L"\\\\??\\", L"\\\\??\\", RTL_UNCHANGED_DOS_PATH, __FILE__, __LINE__ }, + { L"\\\\??\\C:", L"\\\\??\\C:", RTL_UNCHANGED_DOS_PATH, __FILE__, __LINE__ }, + { L"\\\\??\\C:", L"\\\\??\\C:", RTL_UNCHANGED_DOS_PATH, __FILE__, __LINE__ }, + { L"\\\\??\\C:\\", L"\\\\??\\C:\\", RTL_UNCHANGED_DOS_PATH, __FILE__, __LINE__ }, + { L"\\\\??\\C:\\", L"\\\\??\\C:\\", RTL_UNCHANGED_DOS_PATH, __FILE__, __LINE__ }, + { L"\\\\??\\C:\\test", L"\\\\??\\C:\\test", RTL_UNCHANGED_DOS_PATH, __FILE__, __LINE__ }, + { L"\\\\??\\C:\\test", L"\\\\??\\C:\\test", RTL_UNCHANGED_DOS_PATH, __FILE__, __LINE__ }, + { L"\\\\??\\C:\\test\\", L"\\\\??\\C:\\test\\", RTL_UNCHANGED_DOS_PATH, __FILE__, __LINE__ }, + { L"\\\\??\\C:\\test\\", L"\\\\??\\C:\\test\\", RTL_UNCHANGED_DOS_PATH, __FILE__, __LINE__ }, + { L"\\test", L"\\test", RTL_UNCHANGED_UNK_PATH, __FILE__, __LINE__ }, + { L"\\test", L"\\test", RTL_UNCHANGED_UNK_PATH, __FILE__, __LINE__ }, + { L"\\test", L"\\test", RTL_UNCHANGED_UNK_PATH, __FILE__, __LINE__ }, + { L"test", L"test", RTL_UNCHANGED_UNK_PATH, __FILE__, __LINE__ }, + { L"test", L"test", RTL_UNCHANGED_UNK_PATH, __FILE__, __LINE__ }, + { L"test", L"test", RTL_UNCHANGED_UNK_PATH, __FILE__, __LINE__ }, + + /* Originally from RtlDetermineDosPathNameType.c (edited) */ + { L"", L"", RTL_UNCHANGED_UNK_PATH, __FILE__, __LINE__ }, + { L" ", L" ", RTL_UNCHANGED_UNK_PATH, __FILE__, __LINE__ }, + { L"xyz", L"xyz", RTL_UNCHANGED_UNK_PATH, __FILE__, __LINE__ }, + { L"CON", L"CON", RTL_UNCHANGED_UNK_PATH, __FILE__, __LINE__ }, + { L"NUL", L"NUL", RTL_UNCHANGED_UNK_PATH, __FILE__, __LINE__ }, + { L":", L":", RTL_UNCHANGED_UNK_PATH, __FILE__, __LINE__ }, + { L"::", L"::", RTL_UNCHANGED_UNK_PATH, __FILE__, __LINE__ }, + { L":::", L":::", RTL_UNCHANGED_UNK_PATH, __FILE__, __LINE__ }, + { L"::::", L"::::", RTL_UNCHANGED_UNK_PATH, __FILE__, __LINE__ }, + { L"::\\", L"::\\", RTL_UNCHANGED_DOS_PATH, __FILE__, __LINE__ }, + { L"\\", L"\\", RTL_UNCHANGED_UNK_PATH, __FILE__, __LINE__ }, + { L"\\:", L"\\:", RTL_UNCHANGED_UNK_PATH, __FILE__, __LINE__ }, + { L"\\C:", L"\\C:", RTL_UNCHANGED_UNK_PATH, __FILE__, __LINE__ }, + { L"\\C:\\", L"\\C:\\", RTL_UNCHANGED_UNK_PATH, __FILE__, __LINE__ }, + { L"/", L"/", RTL_UNCHANGED_UNK_PATH, __FILE__, __LINE__ }, + { L"/:", L"/:", RTL_UNCHANGED_UNK_PATH, __FILE__, __LINE__ }, + { L"/C:", L"/C:", RTL_UNCHANGED_UNK_PATH, __FILE__, __LINE__ }, + { L"/C:/", L"/C:/", RTL_UNCHANGED_UNK_PATH, __FILE__, __LINE__ }, + { L"C", L"C", RTL_UNCHANGED_UNK_PATH, __FILE__, __LINE__ }, + { L"C:", L"C:", RTL_UNCHANGED_UNK_PATH, __FILE__, __LINE__ }, + { L"C:a", L"C:a", RTL_UNCHANGED_UNK_PATH, __FILE__, __LINE__ }, + { L"C:a\\", L"C:a\\", RTL_UNCHANGED_UNK_PATH, __FILE__, __LINE__ }, + { L"C:\\", L"C:\\", RTL_UNCHANGED_DOS_PATH, __FILE__, __LINE__ }, + { L"C:/", L"C:/", RTL_UNCHANGED_DOS_PATH, __FILE__, __LINE__ }, + { L"C:\\a", L"C:\\a", RTL_UNCHANGED_DOS_PATH, __FILE__, __LINE__ }, + { L"C:/a", L"C:/a", RTL_UNCHANGED_DOS_PATH, __FILE__, __LINE__ }, + { L"C:\\\\", L"C:\\\\", RTL_UNCHANGED_DOS_PATH, __FILE__, __LINE__ }, + { L"\\\\", L"\\\\", RTL_UNCHANGED_DOS_PATH, __FILE__, __LINE__ }, + { L"\\\\\\", L"\\\\\\", RTL_UNCHANGED_DOS_PATH, __FILE__, __LINE__ }, + { L"\\\\;", L"\\\\;", RTL_UNCHANGED_DOS_PATH, __FILE__, __LINE__ }, + { L"\\\\f\\b\\", L"\\\\f\\b\\", RTL_UNCHANGED_DOS_PATH, __FILE__, __LINE__ }, + { L"\\\\f\\b", L"\\\\f\\b", RTL_UNCHANGED_DOS_PATH, __FILE__, __LINE__ }, + { L"\\\\f\\", L"\\\\f\\", RTL_UNCHANGED_DOS_PATH, __FILE__, __LINE__ }, + { L"\\\\f", L"\\\\f", RTL_UNCHANGED_DOS_PATH, __FILE__, __LINE__ }, + { L"\\??\\UNC", L"UNC", RTL_CONVERTED_NT_PATH, __FILE__, __LINE__ }, + { L"\\??\\UNC\\", L"\\\\", RTL_CONVERTED_UNC_PATH, __FILE__, __LINE__ }, + { L"\\??\\UNC\\pth1\\pth2", L"\\\\pth1\\pth2", RTL_CONVERTED_UNC_PATH, __FILE__, __LINE__ }, + { L"\\??\\UNC\\path1", L"\\\\path1", RTL_CONVERTED_UNC_PATH, __FILE__, __LINE__ }, + { L"\\?", L"\\?", RTL_UNCHANGED_UNK_PATH, __FILE__, __LINE__ }, + { L"\\?\\", L"\\?\\", RTL_UNCHANGED_UNK_PATH, __FILE__, __LINE__ }, + { L"\\?\\UNC", L"\\?\\UNC", RTL_UNCHANGED_UNK_PATH, __FILE__, __LINE__ }, + { L"\\?\\UNC\\", L"\\?\\UNC\\", RTL_UNCHANGED_UNK_PATH, __FILE__, __LINE__ }, + { L"\\\\?\\UNC\\", L"\\\\?\\UNC\\", RTL_UNCHANGED_DOS_PATH, __FILE__, __LINE__ }, + { L"\\??\\unc", L"unc", RTL_CONVERTED_NT_PATH, __FILE__, __LINE__ }, + { L"\\??\\unc\\", L"\\\\", RTL_CONVERTED_UNC_PATH, __FILE__, __LINE__ }, + { L"\\??\\unc\\pth1\\pth2", L"\\\\pth1\\pth2", RTL_CONVERTED_UNC_PATH, __FILE__, __LINE__ }, + { L"\\??\\unc\\path1", L"\\\\path1", RTL_CONVERTED_UNC_PATH, __FILE__, __LINE__ }, + { L"\\?", L"\\?", RTL_UNCHANGED_UNK_PATH, __FILE__, __LINE__ }, + { L"\\?\\", L"\\?\\", RTL_UNCHANGED_UNK_PATH, __FILE__, __LINE__ }, + { L"\\?\\unc", L"\\?\\unc", RTL_UNCHANGED_UNK_PATH, __FILE__, __LINE__ }, + { L"\\?\\unc\\", L"\\?\\unc\\", RTL_UNCHANGED_UNK_PATH, __FILE__, __LINE__ }, + { L"\\\\?\\unc\\", L"\\\\?\\unc\\", RTL_UNCHANGED_DOS_PATH, __FILE__, __LINE__ }, + { L"\\\\?", L"\\\\?", RTL_UNCHANGED_DOS_PATH, __FILE__, __LINE__ }, + { L"\\\\??", L"\\\\??", RTL_UNCHANGED_DOS_PATH, __FILE__, __LINE__ }, + { L"\\\\??\\", L"\\\\??\\", RTL_UNCHANGED_DOS_PATH, __FILE__, __LINE__ }, + { L"\\\\??\\C:\\", L"\\\\??\\C:\\", RTL_UNCHANGED_DOS_PATH, __FILE__, __LINE__ }, + { L"\\\\.", L"\\\\.", RTL_UNCHANGED_DOS_PATH, __FILE__, __LINE__ }, + { L"\\\\.\\", L"\\\\.\\", RTL_UNCHANGED_DOS_PATH, __FILE__, __LINE__ }, + { L"\\\\.\\C:\\", L"\\\\.\\C:\\", RTL_UNCHANGED_DOS_PATH, __FILE__, __LINE__ }, + { L"\\/", L"\\/", RTL_UNCHANGED_DOS_PATH, __FILE__, __LINE__ }, + { L"/\\", L"/\\", RTL_UNCHANGED_DOS_PATH, __FILE__, __LINE__ }, + { L"//", L"//", RTL_UNCHANGED_DOS_PATH, __FILE__, __LINE__ }, + { L"///", L"///", RTL_UNCHANGED_DOS_PATH, __FILE__, __LINE__ }, + { L"//;", L"//;", RTL_UNCHANGED_DOS_PATH, __FILE__, __LINE__ }, + { L"//?", L"//?", RTL_UNCHANGED_DOS_PATH, __FILE__, __LINE__ }, + { L"/\\?", L"/\\?", RTL_UNCHANGED_DOS_PATH, __FILE__, __LINE__ }, + { L"\\/?", L"\\/?", RTL_UNCHANGED_DOS_PATH, __FILE__, __LINE__ }, + { L"//??", L"//??", RTL_UNCHANGED_DOS_PATH, __FILE__, __LINE__ }, + { L"//?" L"?/", L"//?" L"?/", RTL_UNCHANGED_DOS_PATH, __FILE__, __LINE__ }, + { L"//?" L"?/C:/", L"//?" L"?/C:/", RTL_UNCHANGED_DOS_PATH, __FILE__, __LINE__ }, + { L"//.", L"//.", RTL_UNCHANGED_DOS_PATH, __FILE__, __LINE__ }, + { L"\\/.", L"\\/.", RTL_UNCHANGED_DOS_PATH, __FILE__, __LINE__ }, + { L"/\\.", L"/\\.", RTL_UNCHANGED_DOS_PATH, __FILE__, __LINE__ }, + { L"//./", L"//./", RTL_UNCHANGED_DOS_PATH, __FILE__, __LINE__ }, + { L"//./C:/", L"//./C:/", RTL_UNCHANGED_DOS_PATH, __FILE__, __LINE__ }, + { L"%SystemRoot%", L"%SystemRoot%", RTL_UNCHANGED_UNK_PATH, __FILE__, __LINE__ }, + + + /* Tests from RtlGetLengthWithoutTrailingPathSeperators.c */ + { L"", L"", RTL_UNCHANGED_UNK_PATH, __FILE__, __LINE__ }, + { L"T", L"T", RTL_UNCHANGED_UNK_PATH, __FILE__, __LINE__ }, + { L"Te", L"Te", RTL_UNCHANGED_UNK_PATH, __FILE__, __LINE__ }, + { L"Tes", L"Tes", RTL_UNCHANGED_UNK_PATH, __FILE__, __LINE__ }, + { L"Test", L"Test", RTL_UNCHANGED_UNK_PATH, __FILE__, __LINE__ }, + + /* Separators tests */ + { L"\\.", L"\\.", RTL_UNCHANGED_UNK_PATH, __FILE__, __LINE__ }, + { L"\\.", L"\\.", RTL_UNCHANGED_UNK_PATH, __FILE__, __LINE__ }, + { L"\\.\\", L"\\.\\", RTL_UNCHANGED_UNK_PATH, __FILE__, __LINE__ }, + { L"\\.\\T", L"\\.\\T", RTL_UNCHANGED_UNK_PATH, __FILE__, __LINE__ }, + { L"\\.\\Te", L"\\.\\Te", RTL_UNCHANGED_UNK_PATH, __FILE__, __LINE__ }, + { L"\\.\\Tes", L"\\.\\Tes", RTL_UNCHANGED_UNK_PATH, __FILE__, __LINE__ }, + { L"\\.\\Test", L"\\.\\Test", RTL_UNCHANGED_UNK_PATH, __FILE__, __LINE__ }, + { L"\\.\\Test\\", L"\\.\\Test\\", RTL_UNCHANGED_UNK_PATH, __FILE__, __LINE__ }, + { L"\\.\\Test\\s", L"\\.\\Test\\s", RTL_UNCHANGED_UNK_PATH, __FILE__, __LINE__ }, + { L"\\.\\T\\est", L"\\.\\T\\est", RTL_UNCHANGED_UNK_PATH, __FILE__, __LINE__ }, + { L"\\.\\T\\e\\st", L"\\.\\T\\e\\st", RTL_UNCHANGED_UNK_PATH, __FILE__, __LINE__ }, + { L"\\.\\T\\e\\s\\t", L"\\.\\T\\e\\s\\t", RTL_UNCHANGED_UNK_PATH, __FILE__, __LINE__ }, + { L"\\.\\T\\e\\s\\t\\", L"\\.\\T\\e\\s\\t\\", RTL_UNCHANGED_UNK_PATH, __FILE__, __LINE__ }, + { L"\\Tests\\String\\", L"\\Tests\\String\\", RTL_UNCHANGED_UNK_PATH, __FILE__, __LINE__ }, + { L"\\.\\Test\\String\\", L"\\.\\Test\\String\\", RTL_UNCHANGED_UNK_PATH, __FILE__, __LINE__ }, + { L"\\.\\Tests\\String\\", L"\\.\\Tests\\String\\", RTL_UNCHANGED_UNK_PATH, __FILE__, __LINE__ }, + { L"\\.\\Tests\\String\\s", L"\\.\\Tests\\String\\s", RTL_UNCHANGED_UNK_PATH, __FILE__, __LINE__ }, + + /* Separator-only tests */ + { L"\\", L"\\", RTL_UNCHANGED_UNK_PATH, __FILE__, __LINE__ }, + { L"/", L"/", RTL_UNCHANGED_UNK_PATH, __FILE__, __LINE__ }, + + /* Mixed separators tests */ + { L"/Test/String", L"/Test/String", RTL_UNCHANGED_UNK_PATH, __FILE__, __LINE__ }, + { L"\\Test/String", L"\\Test/String", RTL_UNCHANGED_UNK_PATH, __FILE__, __LINE__ }, + { L"/Test\\String", L"/Test\\String", RTL_UNCHANGED_UNK_PATH, __FILE__, __LINE__ }, + { L"\\Test/String", L"\\Test/String", RTL_UNCHANGED_UNK_PATH, __FILE__, __LINE__ }, + { L"/Test/String\\", L"/Test/String\\", RTL_UNCHANGED_UNK_PATH, __FILE__, __LINE__ }, + { L"\\Test/String\\", L"\\Test/String\\", RTL_UNCHANGED_UNK_PATH, __FILE__, __LINE__ }, + { L"/Test\\String\\", L"/Test\\String\\", RTL_UNCHANGED_UNK_PATH, __FILE__, __LINE__ }, + { L"\\Test/String\\", L"\\Test/String\\", RTL_UNCHANGED_UNK_PATH, __FILE__, __LINE__ }, + { L"/Test/String/", L"/Test/String/", RTL_UNCHANGED_UNK_PATH, __FILE__, __LINE__ }, + { L"\\Test/String/", L"\\Test/String/", RTL_UNCHANGED_UNK_PATH, __FILE__, __LINE__ }, + { L"/Test\\String/", L"/Test\\String/", RTL_UNCHANGED_UNK_PATH, __FILE__, __LINE__ }, + { L"\\Test/String/", L"\\Test/String/", RTL_UNCHANGED_UNK_PATH, __FILE__, __LINE__ }, + { L"\\Test/String/", L"\\Test/String/", RTL_UNCHANGED_UNK_PATH, __FILE__, __LINE__ }, + { L"\\Test\\\\String/", L"\\Test\\\\String/", RTL_UNCHANGED_UNK_PATH, __FILE__, __LINE__ }, + + /* Common path formats tests */ + { L"Test\\String", L"Test\\String", RTL_UNCHANGED_UNK_PATH, __FILE__, __LINE__ }, + { L"\\Test\\String", L"\\Test\\String", RTL_UNCHANGED_UNK_PATH, __FILE__, __LINE__ }, + { L".\\Test\\String", L".\\Test\\String", RTL_UNCHANGED_UNK_PATH, __FILE__, __LINE__ }, + { L"\\.\\Test\\String", L"\\.\\Test\\String", RTL_UNCHANGED_UNK_PATH, __FILE__, __LINE__ }, + { L"\\??\\Test\\String", L"Test\\String", RTL_CONVERTED_NT_PATH, __FILE__, __LINE__ }, + + /* Redundant trailing tests */ + { L"\\??\\Test\\String\\", L"Test\\String\\", RTL_CONVERTED_NT_PATH, __FILE__, __LINE__ }, + { L"\\??\\Test\\String\\\\",L"Test\\String\\\\", RTL_CONVERTED_NT_PATH, __FILE__, __LINE__ }, + { L"\\??\\Test\\String\\\\\\\\\\", L"Test\\String\\\\\\\\\\",RTL_CONVERTED_NT_PATH, __FILE__, __LINE__ }, +}; + + +static void test_specialhandling() +{ + RTL_UNICODE_STRING_BUFFER Buffer; + const WCHAR* TestString = L"\\??\\C:\\Test"; + ULONG Type; + PUCHAR Ptr; + + /* Just initializing the ByteBuffer does not work */ + memset(&Buffer, 0, sizeof(Buffer)); + Buffer.ByteBuffer.Size = wcslen(TestString) * sizeof(WCHAR) + sizeof(UNICODE_NULL); + Buffer.ByteBuffer.Buffer = Ptr = RtlAllocateHeap(RtlGetProcessHeap(), HEAP_ZERO_MEMORY, Buffer.ByteBuffer.Size); + memcpy(Buffer.ByteBuffer.Buffer, TestString, Buffer.ByteBuffer.Size); + Type = 0x12345; + + ok_hex(pRtlNtPathNameToDosPathName(0, &Buffer, &Type, NULL), STATUS_SUCCESS); + ok_hex(Type, RTL_UNCHANGED_UNK_PATH); + ok_ptr(Buffer.String.Buffer, NULL); + ok_int(Buffer.String.Length, 0); + ok_int(Buffer.String.MaximumLength, 0); + ok_ptr(Buffer.ByteBuffer.Buffer, Ptr); + ok_int(Buffer.ByteBuffer.Size, 24); + + RtlFreeHeap(RtlGetProcessHeap(), 0, Buffer.ByteBuffer.Buffer); + + /* Different strings */ + memset(&Buffer, 0, sizeof(Buffer)); + Buffer.ByteBuffer.Size = wcslen(TestString) * sizeof(WCHAR) + sizeof(UNICODE_NULL); + Buffer.ByteBuffer.Buffer = Ptr = RtlAllocateHeap(RtlGetProcessHeap(), HEAP_ZERO_MEMORY, Buffer.ByteBuffer.Size); + memcpy(Buffer.ByteBuffer.Buffer, TestString, Buffer.ByteBuffer.Size); + Type = 0x12345; + + RtlInitUnicodeString(&Buffer.String, L"\\??\\D:\\1234"); + + ok_hex(pRtlNtPathNameToDosPathName(0, &Buffer, &Type, NULL), STATUS_SUCCESS); + ok_hex(Type, RTL_CONVERTED_NT_PATH); + ok_wstr(Buffer.String.Buffer, L"C:\\Test"); + ok_int(Buffer.String.Length, 14); + ok_int(Buffer.String.MaximumLength, 24); + ok_ptr(Buffer.ByteBuffer.Buffer, Ptr); + ok_int(Buffer.ByteBuffer.Size, 24); + + RtlFreeHeap(RtlGetProcessHeap(), 0, Buffer.ByteBuffer.Buffer); + + + /* Different strings, Buffer.String is not prefixed with \??\ */ + memset(&Buffer, 0, sizeof(Buffer)); + Buffer.ByteBuffer.Size = wcslen(TestString) * sizeof(WCHAR) + sizeof(UNICODE_NULL); + Buffer.ByteBuffer.Buffer = Ptr = RtlAllocateHeap(RtlGetProcessHeap(), HEAP_ZERO_MEMORY, Buffer.ByteBuffer.Size); + memcpy(Buffer.ByteBuffer.Buffer, TestString, Buffer.ByteBuffer.Size); + Type = 0x12345; + + RtlInitUnicodeString(&Buffer.String, L"D:\\1234"); + + ok_hex(pRtlNtPathNameToDosPathName(0, &Buffer, &Type, NULL), STATUS_SUCCESS); + ok_hex(Type, RTL_UNCHANGED_DOS_PATH); + ok_wstr(Buffer.String.Buffer, L"D:\\1234"); + ok_int(Buffer.String.Length, 14); + ok_int(Buffer.String.MaximumLength, 16); + ok_ptr(Buffer.ByteBuffer.Buffer, Ptr); + ok_int(Buffer.ByteBuffer.Size, 24); + + RtlFreeHeap(RtlGetProcessHeap(), 0, Buffer.ByteBuffer.Buffer); + + + /* Different strings, smaller ByteBuffer */ + memset(&Buffer, 0, sizeof(Buffer)); + Buffer.ByteBuffer.Size = wcslen(TestString) * sizeof(WCHAR) + sizeof(UNICODE_NULL); + Buffer.ByteBuffer.Buffer = Ptr = RtlAllocateHeap(RtlGetProcessHeap(), HEAP_ZERO_MEMORY, Buffer.ByteBuffer.Size); + memcpy(Buffer.ByteBuffer.Buffer, TestString, Buffer.ByteBuffer.Size); + Type = 0x12345; + + RtlInitUnicodeString(&Buffer.String, L"\\??\\D:\\1234"); + Buffer.ByteBuffer.Size -= 4 * sizeof(WCHAR); + + ok_hex(pRtlNtPathNameToDosPathName(0, &Buffer, &Type, NULL), STATUS_SUCCESS); + ok_hex(Type, RTL_CONVERTED_NT_PATH); + ok_wstr(Buffer.String.Buffer, L"C:\\Test"); + ok_int(Buffer.String.Length, 14); + ok_int(Buffer.String.MaximumLength, 16); + ok_ptr(Buffer.ByteBuffer.Buffer, Ptr); + ok_int(Buffer.ByteBuffer.Size, 16); + + RtlFreeHeap(RtlGetProcessHeap(), 0, Buffer.ByteBuffer.Buffer); + + + /* These tests show that the size of the ByteBuffer should + at least equal the size of the string (minus 4, in case of \??\)! + The results are all over the place, and are most likely the result of implementation details.. */ + +#if 0 + /* Different strings, too small ByteBuffer + --> corrupt buffer, but none of the output params suggests so? */ + memset(&Buffer, 0, sizeof(Buffer)); + Buffer.ByteBuffer.Size = wcslen(TestString) * sizeof(WCHAR) + sizeof(UNICODE_NULL); + Buffer.ByteBuffer.Buffer = Ptr = RtlAllocateHeap(RtlGetProcessHeap(), HEAP_ZERO_MEMORY, Buffer.ByteBuffer.Size); + memcpy(Buffer.ByteBuffer.Buffer, TestString, Buffer.ByteBuffer.Size); + Type = 0x12345; + + RtlInitUnicodeString(&Buffer.String, L"\\??\\D:\\1234"); + Buffer.ByteBuffer.Size -= 5 * sizeof(WCHAR); + + ok_hex(pRtlNtPathNameToDosPathName(0, &Buffer, &Type, NULL), STATUS_SUCCESS); + ok_hex(Type, RTL_CONVERTED_NT_PATH); + //ok_wstr(Buffer.String.Buffer, L"C:\\"); + ok_int(Buffer.String.Length, 14); + ok_int(Buffer.String.MaximumLength, 16); + //ok_ptr(Buffer.ByteBuffer.Buffer, Ptr); // An attempt is made at allocating a buffer, but the move fails because the size of ByteBuffer seems to be used?? + ok_int(Buffer.ByteBuffer.Size, 16); + + RtlFreeHeap(RtlGetProcessHeap(), 0, Buffer.ByteBuffer.Buffer); + + /* Different strings, too small ByteBuffer, different path separators + --> corrupt buffer, but none of the output params suggests so? */ + memset(&Buffer, 0, sizeof(Buffer)); + Buffer.ByteBuffer.Size = wcslen(L"\\??\\C://Test") * sizeof(WCHAR) + sizeof(UNICODE_NULL); + Buffer.ByteBuffer.Buffer = Ptr = RtlAllocateHeap(RtlGetProcessHeap(), HEAP_ZERO_MEMORY, Buffer.ByteBuffer.Size); + memcpy(Buffer.ByteBuffer.Buffer, L"\\??\\C://Test", Buffer.ByteBuffer.Size); + Type = 0x12345; + + RtlInitUnicodeString(&Buffer.String, L"\\??\\D:\\1234"); + Buffer.ByteBuffer.Size -= 5 * sizeof(WCHAR); + + ok_hex(pRtlNtPathNameToDosPathName(0, &Buffer, &Type, NULL), STATUS_SUCCESS); + ok_hex(Type, RTL_CONVERTED_NT_PATH); + //ok_wstr(Buffer.String.Buffer, L"C:\\"); + ok_int(Buffer.String.Length, 14); + ok_int(Buffer.String.MaximumLength, 16); + ok_ptr(Buffer.ByteBuffer.Buffer, Ptr); + ok_int(Buffer.ByteBuffer.Size, 16); + + RtlFreeHeap(RtlGetProcessHeap(), 0, Buffer.ByteBuffer.Buffer); +#endif +} + +static void test_table(struct test_entry* Entry) +{ + RTL_UNICODE_STRING_BUFFER Buffer = { { 0 } }; + ULONG Type = 0x12345; + PUCHAR Ptr; + SIZE_T Size; + + RtlInitUnicodeString(&Buffer.String, Entry->InputPath); + + + Buffer.ByteBuffer.Buffer = Ptr = RtlAllocateHeap(RtlGetProcessHeap(), HEAP_ZERO_MEMORY, Buffer.String.MaximumLength); + Buffer.ByteBuffer.Size = Size = Buffer.String.MaximumLength; + + memcpy(Buffer.ByteBuffer.Buffer, Buffer.String.Buffer, Buffer.String.Length); + + ok_hex_(pRtlNtPathNameToDosPathName(0, &Buffer, &Type, NULL), STATUS_SUCCESS); + + ok_hex_(Type, Entry->Type); + ok_wstr_(Buffer.String.Buffer, Entry->OutputPath); + /* If there is no change in the path, the pointer is unchanged */ + if (!wcscmp(Entry->InputPath, Entry->OutputPath)) + { + ok_ptr_(Buffer.String.Buffer, Entry->InputPath); + } + else + { + /* If there is a change in the path, the 'ByteBuffer' is used */ + winetest_ok((PUCHAR)Buffer.String.Buffer >= Ptr && (PUCHAR)Buffer.String.Buffer <= (Ptr + Size), + "Expected Buffer to point inside ByteBuffer\n"); + } + ok_wstr_((const WCHAR *)Buffer.ByteBuffer.Buffer, Entry->OutputPath); + + ok_hex_(Buffer.MinimumStaticBufferForTerminalNul, 0); + + ok_ptr_(Buffer.ByteBuffer.Buffer, Ptr); + ok_hex_(Buffer.ByteBuffer.Size, Size); + + ok_ptr_(Buffer.ByteBuffer.StaticBuffer, NULL); + ok_hex_(Buffer.ByteBuffer.StaticSize, 0); + ok_hex_(Buffer.ByteBuffer.ReservedForAllocatedSize, 0); + ok_ptr_(Buffer.ByteBuffer.ReservedForIMalloc, NULL); + + RtlFreeHeap(RtlGetProcessHeap(), 0, Buffer.ByteBuffer.Buffer); +} + + +START_TEST(RtlNtPathNameToDosPathName) +{ + RTL_UNICODE_STRING_BUFFER Buffer = { { 0 } }; + ULONG Type; + size_t n; + + HMODULE ntdll = GetModuleHandleW(L"ntdll.dll"); + pRtlNtPathNameToDosPathName = (void *)GetProcAddress(ntdll, "RtlNtPathNameToDosPathName"); + + if (!pRtlNtPathNameToDosPathName) + { + skip("RtlNtPathNameToDosPathName not found?\n"); + return; + } + + ok_ntstatus(pRtlNtPathNameToDosPathName(0, NULL, NULL, NULL), STATUS_INVALID_PARAMETER); + ok_ntstatus(pRtlNtPathNameToDosPathName(0, &Buffer, NULL, NULL), STATUS_SUCCESS); + ok_ntstatus(pRtlNtPathNameToDosPathName(1, &Buffer, NULL, NULL), STATUS_INVALID_PARAMETER); + + Type = 0x12345; + ok_ntstatus(pRtlNtPathNameToDosPathName(0, NULL, &Type, NULL), STATUS_INVALID_PARAMETER); + ok_int(Type, 0); + Type = 0x12345; + ok_ntstatus(pRtlNtPathNameToDosPathName(0, &Buffer, &Type, NULL), STATUS_SUCCESS); + ok_int(Type, RTL_UNCHANGED_UNK_PATH); + Type = 0x12345; + ok_ntstatus(pRtlNtPathNameToDosPathName(1, &Buffer, &Type, NULL), STATUS_INVALID_PARAMETER); + ok_int(Type, 0); + + test_specialhandling(); + + for (n = 0; n < _countof(test_data); ++n) + { + winetest_set_location(test_data[n].File, test_data[n].Line); + test_table(test_data + n); + } +} Index: rostests/apitests/ntdll/testlist.c =================================================================== --- rostests/apitests/ntdll/testlist.c (revision 73897) +++ rostests/apitests/ntdll/testlist.c (working copy) @@ -47,6 +47,7 @@ extern void func_RtlInitializeBitMap(void); extern void func_RtlIsNameLegalDOS8Dot3(void); extern void func_RtlMemoryStream(void); +extern void func_RtlNtPathNameToDosPathName(void); extern void func_RtlReAllocateHeap(void); extern void func_RtlUpcaseUnicodeStringToCountedOemString(void); extern void func_StackOverflow(void); @@ -98,6 +99,7 @@ { "RtlInitializeBitMap", func_RtlInitializeBitMap }, { "RtlIsNameLegalDOS8Dot3", func_RtlIsNameLegalDOS8Dot3 }, { "RtlMemoryStream", func_RtlMemoryStream }, + { "RtlNtPathNameToDosPathName", func_RtlNtPathNameToDosPathName }, { "RtlReAllocateHeap", func_RtlReAllocateHeap }, { "RtlUpcaseUnicodeStringToCountedOemString", func_RtlUpcaseUnicodeStringToCountedOemString }, { "StackOverflow", func_StackOverflow },