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,64 @@ } /* - * @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 RTL_PATH_TYPE* PathType, + ULONG* Unknown) { - DPRINT1("RtlNtPathNameToDosPathName: stub\n"); - return STATUS_NOT_IMPLEMENTED; + if (PathType) + *PathType = RtlPathTypeUnknown; + + 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; + } + else if (RtlPrefixUnicodeString(&RtlpDosDevicesPrefix, &Path->String, TRUE)) + UsePrefix = &RtlpDosDevicesPrefix; + + 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; + } + } + + if (PathType) + { + *PathType = Path->String.Buffer ? RtlDetermineDosPathNameType_U(Path->String.Buffer) : RtlPathTypeUncAbsolute; + } + } + + 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,476 @@ +/* + * 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, RTL_PATH_TYPE* 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; + RTL_PATH_TYPE Type; + + const char* File; + int Line; +}; + + +static struct test_entry test_data[] = +{ + /* Originally from RtlGetFullPathName_*.c (edited) */ + { L"", L"", RtlPathTypeUncAbsolute, __FILE__, __LINE__ }, + { L".\\test", L".\\test", RtlPathTypeUncAbsolute, __FILE__, __LINE__ }, + { L"/test", L"/test", RtlPathTypeUncAbsolute, __FILE__, __LINE__ }, + { L"??\\", L"??\\", RtlPathTypeUncAbsolute, __FILE__, __LINE__ }, + { L"??\\C:", L"??\\C:", RtlPathTypeUncAbsolute, __FILE__, __LINE__ }, + { L"??\\C:\\", L"??\\C:\\", RtlPathTypeUncAbsolute, __FILE__, __LINE__ }, + { L"??\\C:\\test", L"??\\C:\\test", RtlPathTypeUncAbsolute, __FILE__, __LINE__ }, + { L"??\\C:\\test\\", L"??\\C:\\test\\", RtlPathTypeUncAbsolute, __FILE__, __LINE__ }, + { L"C:", L"C:", RtlPathTypeUncAbsolute, __FILE__, __LINE__ }, + { L"C:/test/", L"C:/test/", RtlPathTypeRooted, __FILE__, __LINE__ }, + { L"C:\\", L"C:\\", RtlPathTypeRooted, __FILE__, __LINE__ }, + { L"C:\\", L"C:\\", RtlPathTypeRooted, __FILE__, __LINE__ }, + { L"C:\\\\test", L"C:\\\\test", RtlPathTypeRooted, __FILE__, __LINE__ }, + { L"C:\\test", L"C:\\test", RtlPathTypeRooted, __FILE__, __LINE__ }, + { L"C:\\test", L"C:\\test", RtlPathTypeRooted, __FILE__, __LINE__ }, + { L"C:\\test", L"C:\\test", RtlPathTypeRooted, __FILE__, __LINE__ }, + { L"C:\\test\\", L"C:\\test\\", RtlPathTypeRooted, __FILE__, __LINE__ }, + { L"C:\\test\\", L"C:\\test\\", RtlPathTypeRooted, __FILE__, __LINE__ }, + { L"C:\\test\\", L"C:\\test\\", RtlPathTypeRooted, __FILE__, __LINE__ }, + { L"\\.", L"\\.", RtlPathTypeUncAbsolute, __FILE__, __LINE__ }, + { L"\\.\\", L"\\.\\", RtlPathTypeUncAbsolute, __FILE__, __LINE__ }, + { L"\\??\\", L"", RtlPathTypeDriveRelative, __FILE__, __LINE__ }, + { L"\\??\\C:", L"C:", RtlPathTypeDriveRelative, __FILE__, __LINE__ }, + { L"\\??\\C:\\", L"C:\\", RtlPathTypeDriveRelative, __FILE__, __LINE__ }, + { L"\\??\\C:\\test", L"C:\\test", RtlPathTypeDriveRelative, __FILE__, __LINE__ }, + { L"\\??\\C:\\test\\", L"C:\\test\\", RtlPathTypeDriveRelative, __FILE__, __LINE__ }, + { L"\\\\.", L"\\\\.", RtlPathTypeRooted, __FILE__, __LINE__ }, + { L"\\\\.\\", L"\\\\.\\", RtlPathTypeRooted, __FILE__, __LINE__ }, + { L"\\\\.\\", L"\\\\.\\", RtlPathTypeRooted, __FILE__, __LINE__ }, + { L"\\\\.\\", L"\\\\.\\", RtlPathTypeRooted, __FILE__, __LINE__ }, + { L"\\\\.\\Something\\", L"\\\\.\\Something\\", RtlPathTypeRooted, __FILE__, __LINE__ }, + { L"\\\\.\\Something\\", L"\\\\.\\Something\\", RtlPathTypeRooted, __FILE__, __LINE__ }, + { L"\\\\??\\", L"\\\\??\\", RtlPathTypeRooted, __FILE__, __LINE__ }, + { L"\\\\??\\", L"\\\\??\\", RtlPathTypeRooted, __FILE__, __LINE__ }, + { L"\\\\??\\C:", L"\\\\??\\C:", RtlPathTypeRooted, __FILE__, __LINE__ }, + { L"\\\\??\\C:", L"\\\\??\\C:", RtlPathTypeRooted, __FILE__, __LINE__ }, + { L"\\\\??\\C:\\", L"\\\\??\\C:\\", RtlPathTypeRooted, __FILE__, __LINE__ }, + { L"\\\\??\\C:\\", L"\\\\??\\C:\\", RtlPathTypeRooted, __FILE__, __LINE__ }, + { L"\\\\??\\C:\\test", L"\\\\??\\C:\\test", RtlPathTypeRooted, __FILE__, __LINE__ }, + { L"\\\\??\\C:\\test", L"\\\\??\\C:\\test", RtlPathTypeRooted, __FILE__, __LINE__ }, + { L"\\\\??\\C:\\test\\", L"\\\\??\\C:\\test\\", RtlPathTypeRooted, __FILE__, __LINE__ }, + { L"\\\\??\\C:\\test\\", L"\\\\??\\C:\\test\\", RtlPathTypeRooted, __FILE__, __LINE__ }, + { L"\\test", L"\\test", RtlPathTypeUncAbsolute, __FILE__, __LINE__ }, + { L"\\test", L"\\test", RtlPathTypeUncAbsolute, __FILE__, __LINE__ }, + { L"\\test", L"\\test", RtlPathTypeUncAbsolute, __FILE__, __LINE__ }, + { L"test", L"test", RtlPathTypeUncAbsolute, __FILE__, __LINE__ }, + { L"test", L"test", RtlPathTypeUncAbsolute, __FILE__, __LINE__ }, + { L"test", L"test", RtlPathTypeUncAbsolute, __FILE__, __LINE__ }, + + /* Originally from RtlDetermineDosPathNameType.c (edited) */ + { L"", L"", RtlPathTypeUncAbsolute, __FILE__, __LINE__ }, + { L" ", L" ", RtlPathTypeUncAbsolute, __FILE__, __LINE__ }, + { L"xyz", L"xyz", RtlPathTypeUncAbsolute, __FILE__, __LINE__ }, + { L"CON", L"CON", RtlPathTypeUncAbsolute, __FILE__, __LINE__ }, + { L"NUL", L"NUL", RtlPathTypeUncAbsolute, __FILE__, __LINE__ }, + { L":", L":", RtlPathTypeUncAbsolute, __FILE__, __LINE__ }, + { L"::", L"::", RtlPathTypeUncAbsolute, __FILE__, __LINE__ }, + { L":::", L":::", RtlPathTypeUncAbsolute, __FILE__, __LINE__ }, + { L"::::", L"::::", RtlPathTypeUncAbsolute, __FILE__, __LINE__ }, + { L"::\\", L"::\\", RtlPathTypeRooted, __FILE__, __LINE__ }, + { L"\\", L"\\", RtlPathTypeUncAbsolute, __FILE__, __LINE__ }, + { L"\\:", L"\\:", RtlPathTypeUncAbsolute, __FILE__, __LINE__ }, + { L"\\C:", L"\\C:", RtlPathTypeUncAbsolute, __FILE__, __LINE__ }, + { L"\\C:\\", L"\\C:\\", RtlPathTypeUncAbsolute, __FILE__, __LINE__ }, + { L"/", L"/", RtlPathTypeUncAbsolute, __FILE__, __LINE__ }, + { L"/:", L"/:", RtlPathTypeUncAbsolute, __FILE__, __LINE__ }, + { L"/C:", L"/C:", RtlPathTypeUncAbsolute, __FILE__, __LINE__ }, + { L"/C:/", L"/C:/", RtlPathTypeUncAbsolute, __FILE__, __LINE__ }, + { L"C", L"C", RtlPathTypeUncAbsolute, __FILE__, __LINE__ }, + { L"C:", L"C:", RtlPathTypeUncAbsolute, __FILE__, __LINE__ }, + { L"C:a", L"C:a", RtlPathTypeUncAbsolute, __FILE__, __LINE__ }, + { L"C:a\\", L"C:a\\", RtlPathTypeUncAbsolute, __FILE__, __LINE__ }, + { L"C:\\", L"C:\\", RtlPathTypeRooted, __FILE__, __LINE__ }, + { L"C:/", L"C:/", RtlPathTypeRooted, __FILE__, __LINE__ }, + { L"C:\\a", L"C:\\a", RtlPathTypeRooted, __FILE__, __LINE__ }, + { L"C:/a", L"C:/a", RtlPathTypeRooted, __FILE__, __LINE__ }, + { L"C:\\\\", L"C:\\\\", RtlPathTypeRooted, __FILE__, __LINE__ }, + { L"\\\\", L"\\\\", RtlPathTypeRooted, __FILE__, __LINE__ }, + { L"\\\\\\", L"\\\\\\", RtlPathTypeRooted, __FILE__, __LINE__ }, + { L"\\\\;", L"\\\\;", RtlPathTypeRooted, __FILE__, __LINE__ }, + { L"\\\\f\\b\\", L"\\\\f\\b\\", RtlPathTypeRooted, __FILE__, __LINE__ }, + { L"\\\\f\\b", L"\\\\f\\b", RtlPathTypeRooted, __FILE__, __LINE__ }, + { L"\\\\f\\", L"\\\\f\\", RtlPathTypeRooted, __FILE__, __LINE__ }, + { L"\\\\f", L"\\\\f", RtlPathTypeRooted, __FILE__, __LINE__ }, + { L"\\??\\UNC", L"UNC", RtlPathTypeDriveRelative, __FILE__, __LINE__ }, + { L"\\??\\UNC\\", L"\\\\", RtlPathTypeDriveAbsolute, __FILE__, __LINE__ }, + { L"\\??\\UNC\\pth1\\pth2", L"\\\\pth1\\pth2", RtlPathTypeDriveAbsolute, __FILE__, __LINE__ }, + { L"\\??\\UNC\\path1", L"\\\\path1", RtlPathTypeDriveAbsolute, __FILE__, __LINE__ }, + { L"\\?", L"\\?", RtlPathTypeUncAbsolute, __FILE__, __LINE__ }, + { L"\\?\\", L"\\?\\", RtlPathTypeUncAbsolute, __FILE__, __LINE__ }, + { L"\\?\\UNC", L"\\?\\UNC", RtlPathTypeUncAbsolute, __FILE__, __LINE__ }, + { L"\\?\\UNC\\", L"\\?\\UNC\\", RtlPathTypeUncAbsolute, __FILE__, __LINE__ }, + { L"\\\\?\\UNC\\", L"\\\\?\\UNC\\", RtlPathTypeRooted, __FILE__, __LINE__ }, + { L"\\??\\unc", L"unc", RtlPathTypeDriveRelative, __FILE__, __LINE__ }, + { L"\\??\\unc\\", L"\\\\", RtlPathTypeDriveAbsolute, __FILE__, __LINE__ }, + { L"\\??\\unc\\pth1\\pth2", L"\\\\pth1\\pth2", RtlPathTypeDriveAbsolute, __FILE__, __LINE__ }, + { L"\\??\\unc\\path1", L"\\\\path1", RtlPathTypeDriveAbsolute, __FILE__, __LINE__ }, + { L"\\?", L"\\?", RtlPathTypeUncAbsolute, __FILE__, __LINE__ }, + { L"\\?\\", L"\\?\\", RtlPathTypeUncAbsolute, __FILE__, __LINE__ }, + { L"\\?\\unc", L"\\?\\unc", RtlPathTypeUncAbsolute, __FILE__, __LINE__ }, + { L"\\?\\unc\\", L"\\?\\unc\\", RtlPathTypeUncAbsolute, __FILE__, __LINE__ }, + { L"\\\\?\\unc\\", L"\\\\?\\unc\\", RtlPathTypeRooted, __FILE__, __LINE__ }, + { L"\\\\?", L"\\\\?", RtlPathTypeRooted, __FILE__, __LINE__ }, + { L"\\\\??", L"\\\\??", RtlPathTypeRooted, __FILE__, __LINE__ }, + { L"\\\\??\\", L"\\\\??\\", RtlPathTypeRooted, __FILE__, __LINE__ }, + { L"\\\\??\\C:\\", L"\\\\??\\C:\\", RtlPathTypeRooted, __FILE__, __LINE__ }, + { L"\\\\.", L"\\\\.", RtlPathTypeRooted, __FILE__, __LINE__ }, + { L"\\\\.\\", L"\\\\.\\", RtlPathTypeRooted, __FILE__, __LINE__ }, + { L"\\\\.\\C:\\", L"\\\\.\\C:\\", RtlPathTypeRooted, __FILE__, __LINE__ }, + { L"\\/", L"\\/", RtlPathTypeRooted, __FILE__, __LINE__ }, + { L"/\\", L"/\\", RtlPathTypeRooted, __FILE__, __LINE__ }, + { L"//", L"//", RtlPathTypeRooted, __FILE__, __LINE__ }, + { L"///", L"///", RtlPathTypeRooted, __FILE__, __LINE__ }, + { L"//;", L"//;", RtlPathTypeRooted, __FILE__, __LINE__ }, + { L"//?", L"//?", RtlPathTypeRooted, __FILE__, __LINE__ }, + { L"/\\?", L"/\\?", RtlPathTypeRooted, __FILE__, __LINE__ }, + { L"\\/?", L"\\/?", RtlPathTypeRooted, __FILE__, __LINE__ }, + { L"//??", L"//??", RtlPathTypeRooted, __FILE__, __LINE__ }, + { L"//?" L"?/", L"//?" L"?/", RtlPathTypeRooted, __FILE__, __LINE__ }, + { L"//?" L"?/C:/", L"//?" L"?/C:/", RtlPathTypeRooted, __FILE__, __LINE__ }, + { L"//.", L"//.", RtlPathTypeRooted, __FILE__, __LINE__ }, + { L"\\/.", L"\\/.", RtlPathTypeRooted, __FILE__, __LINE__ }, + { L"/\\.", L"/\\.", RtlPathTypeRooted, __FILE__, __LINE__ }, + { L"//./", L"//./", RtlPathTypeRooted, __FILE__, __LINE__ }, + { L"//./C:/", L"//./C:/", RtlPathTypeRooted, __FILE__, __LINE__ }, + { L"%SystemRoot%", L"%SystemRoot%", RtlPathTypeUncAbsolute, __FILE__, __LINE__ }, + + + /* Tests from RtlGetLengthWithoutTrailingPathSeperators.c */ + { L"", L"", RtlPathTypeUncAbsolute, __FILE__, __LINE__ }, + { L"T", L"T", RtlPathTypeUncAbsolute, __FILE__, __LINE__ }, + { L"Te", L"Te", RtlPathTypeUncAbsolute, __FILE__, __LINE__ }, + { L"Tes", L"Tes", RtlPathTypeUncAbsolute, __FILE__, __LINE__ }, + { L"Test", L"Test", RtlPathTypeUncAbsolute, __FILE__, __LINE__ }, + + /* Separators tests */ + { L"\\.", L"\\.", RtlPathTypeUncAbsolute, __FILE__, __LINE__ }, + { L"\\.", L"\\.", RtlPathTypeUncAbsolute, __FILE__, __LINE__ }, + { L"\\.\\", L"\\.\\", RtlPathTypeUncAbsolute, __FILE__, __LINE__ }, + { L"\\.\\T", L"\\.\\T", RtlPathTypeUncAbsolute, __FILE__, __LINE__ }, + { L"\\.\\Te", L"\\.\\Te", RtlPathTypeUncAbsolute, __FILE__, __LINE__ }, + { L"\\.\\Tes", L"\\.\\Tes", RtlPathTypeUncAbsolute, __FILE__, __LINE__ }, + { L"\\.\\Test", L"\\.\\Test", RtlPathTypeUncAbsolute, __FILE__, __LINE__ }, + { L"\\.\\Test\\", L"\\.\\Test\\", RtlPathTypeUncAbsolute, __FILE__, __LINE__ }, + { L"\\.\\Test\\s", L"\\.\\Test\\s", RtlPathTypeUncAbsolute, __FILE__, __LINE__ }, + { L"\\.\\T\\est", L"\\.\\T\\est", RtlPathTypeUncAbsolute, __FILE__, __LINE__ }, + { L"\\.\\T\\e\\st", L"\\.\\T\\e\\st", RtlPathTypeUncAbsolute, __FILE__, __LINE__ }, + { L"\\.\\T\\e\\s\\t", L"\\.\\T\\e\\s\\t", RtlPathTypeUncAbsolute, __FILE__, __LINE__ }, + { L"\\.\\T\\e\\s\\t\\", L"\\.\\T\\e\\s\\t\\", RtlPathTypeUncAbsolute, __FILE__, __LINE__ }, + { L"\\Tests\\String\\", L"\\Tests\\String\\", RtlPathTypeUncAbsolute, __FILE__, __LINE__ }, + { L"\\.\\Test\\String\\", L"\\.\\Test\\String\\", RtlPathTypeUncAbsolute, __FILE__, __LINE__ }, + { L"\\.\\Tests\\String\\", L"\\.\\Tests\\String\\", RtlPathTypeUncAbsolute, __FILE__, __LINE__ }, + { L"\\.\\Tests\\String\\s", L"\\.\\Tests\\String\\s", RtlPathTypeUncAbsolute, __FILE__, __LINE__ }, + + /* Separator-only tests */ + { L"\\", L"\\", RtlPathTypeUncAbsolute, __FILE__, __LINE__ }, + { L"/", L"/", RtlPathTypeUncAbsolute, __FILE__, __LINE__ }, + + /* Mixed separators tests */ + { L"/Test/String", L"/Test/String", RtlPathTypeUncAbsolute, __FILE__, __LINE__ }, + { L"\\Test/String", L"\\Test/String", RtlPathTypeUncAbsolute, __FILE__, __LINE__ }, + { L"/Test\\String", L"/Test\\String", RtlPathTypeUncAbsolute, __FILE__, __LINE__ }, + { L"\\Test/String", L"\\Test/String", RtlPathTypeUncAbsolute, __FILE__, __LINE__ }, + { L"/Test/String\\", L"/Test/String\\", RtlPathTypeUncAbsolute, __FILE__, __LINE__ }, + { L"\\Test/String\\", L"\\Test/String\\", RtlPathTypeUncAbsolute, __FILE__, __LINE__ }, + { L"/Test\\String\\", L"/Test\\String\\", RtlPathTypeUncAbsolute, __FILE__, __LINE__ }, + { L"\\Test/String\\", L"\\Test/String\\", RtlPathTypeUncAbsolute, __FILE__, __LINE__ }, + { L"/Test/String/", L"/Test/String/", RtlPathTypeUncAbsolute, __FILE__, __LINE__ }, + { L"\\Test/String/", L"\\Test/String/", RtlPathTypeUncAbsolute, __FILE__, __LINE__ }, + { L"/Test\\String/", L"/Test\\String/", RtlPathTypeUncAbsolute, __FILE__, __LINE__ }, + { L"\\Test/String/", L"\\Test/String/", RtlPathTypeUncAbsolute, __FILE__, __LINE__ }, + { L"\\Test/String/", L"\\Test/String/", RtlPathTypeUncAbsolute, __FILE__, __LINE__ }, + { L"\\Test\\\\String/", L"\\Test\\\\String/", RtlPathTypeUncAbsolute, __FILE__, __LINE__ }, + + /* Common path formats tests */ + { L"Test\\String", L"Test\\String", RtlPathTypeUncAbsolute, __FILE__, __LINE__ }, + { L"\\Test\\String", L"\\Test\\String", RtlPathTypeUncAbsolute, __FILE__, __LINE__ }, + { L".\\Test\\String", L".\\Test\\String", RtlPathTypeUncAbsolute, __FILE__, __LINE__ }, + { L"\\.\\Test\\String", L"\\.\\Test\\String", RtlPathTypeUncAbsolute, __FILE__, __LINE__ }, + { L"\\??\\Test\\String", L"Test\\String", RtlPathTypeDriveRelative, __FILE__, __LINE__ }, + + /* Redundant trailing tests */ + { L"\\??\\Test\\String\\", L"Test\\String\\", RtlPathTypeDriveRelative, __FILE__, __LINE__ }, + { L"\\??\\Test\\String\\\\",L"Test\\String\\\\", RtlPathTypeDriveRelative, __FILE__, __LINE__ }, + { L"\\??\\Test\\String\\\\\\\\\\", L"Test\\String\\\\\\\\\\",RtlPathTypeDriveRelative, __FILE__, __LINE__ }, +}; + + +static void test_specialhandling() +{ + RTL_UNICODE_STRING_BUFFER Buffer; + const WCHAR* TestString = L"\\??\\C:\\Test"; + RTL_PATH_TYPE Type = 0x12345; + 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); + + ok_hex(pRtlNtPathNameToDosPathName(0, &Buffer, &Type, NULL), STATUS_SUCCESS); + 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); + + RtlInitUnicodeString(&Buffer.String, L"\\??\\D:\\1234"); + + ok_hex(pRtlNtPathNameToDosPathName(0, &Buffer, &Type, NULL), STATUS_SUCCESS); + 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); + + RtlInitUnicodeString(&Buffer.String, L"D:\\1234"); + + ok_hex(pRtlNtPathNameToDosPathName(0, &Buffer, &Type, NULL), STATUS_SUCCESS); + 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); + + RtlInitUnicodeString(&Buffer.String, L"\\??\\D:\\1234"); + Buffer.ByteBuffer.Size -= 4 * sizeof(WCHAR); + + ok_hex(pRtlNtPathNameToDosPathName(0, &Buffer, &Type, NULL), STATUS_SUCCESS); + 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); + + RtlInitUnicodeString(&Buffer.String, L"\\??\\D:\\1234"); + Buffer.ByteBuffer.Size -= 5 * sizeof(WCHAR); + + ok_hex(pRtlNtPathNameToDosPathName(0, &Buffer, &Type, NULL), STATUS_SUCCESS); + //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); + + RtlInitUnicodeString(&Buffer.String, L"\\??\\D:\\1234"); + Buffer.ByteBuffer.Size -= 5 * sizeof(WCHAR); + + ok_hex(pRtlNtPathNameToDosPathName(0, &Buffer, &Type, NULL), STATUS_SUCCESS); + //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 } }; + RTL_PATH_TYPE 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); +} + +#define IS_PATH_SEPARATOR(x) (((x)==L'\\')||((x)==L'/')) + +RTL_PATH_TYPE +NTAPI +RtlDetermineDosPathNameType_Ustr(IN PCUNICODE_STRING PathString) +{ + PWCHAR Path; + ULONG Chars; + + Path = PathString->Buffer; + Chars = PathString->Length / sizeof(WCHAR); + + /* Return if there are no characters */ + if (!Chars) return RtlPathTypeRelative; + + /* + * The algorithm is similar to RtlDetermineDosPathNameType_U but here we + * actually check for the path length before touching the characters + */ + if (IS_PATH_SEPARATOR(Path[0])) + { + if ((Chars < 2) || !(IS_PATH_SEPARATOR(Path[1]))) return RtlPathTypeRooted; /* \x */ + if ((Chars < 3) || ((Path[2] != L'.') && (Path[2] != L'?'))) return RtlPathTypeUncAbsolute;/* \\x */ + if ((Chars >= 4) && (IS_PATH_SEPARATOR(Path[3]))) return RtlPathTypeLocalDevice; /* \\.\x or \\?\x */ + if (Chars != 3) return RtlPathTypeUncAbsolute; /* \\.x or \\?x */ + return RtlPathTypeRootLocalDevice; /* \\. or \\? */ + } + else + { + if ((Chars < 2) || (Path[1] != L':')) return RtlPathTypeRelative; /* x */ + if ((Chars < 3) || !(IS_PATH_SEPARATOR(Path[2]))) return RtlPathTypeDriveRelative; /* x: */ + return RtlPathTypeDriveAbsolute; /* x:\ */ + } +} + + +START_TEST(RtlNtPathNameToDosPathName) +{ + RTL_UNICODE_STRING_BUFFER Buffer = { { 0 } }; + RTL_PATH_TYPE 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, RtlPathTypeUnknown); + Type = 0x12345; + ok_ntstatus(pRtlNtPathNameToDosPathName(0, &Buffer, &Type, NULL), STATUS_SUCCESS); + ok_int(Type, RtlPathTypeUncAbsolute); + Type = 0x12345; + ok_ntstatus(pRtlNtPathNameToDosPathName(1, &Buffer, &Type, NULL), STATUS_INVALID_PARAMETER); + ok_int(Type, RtlPathTypeUnknown); + + 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 },