1 /* 2 * PROJECT: ReactOS api tests 3 * LICENSE: GPLv2+ - See COPYING in the top level directory 4 * PURPOSE: Test for RtlGetFullPathName_UstrEx 5 * PROGRAMMER: Thomas Faber <thomas.faber@reactos.org> 6 */ 7 8 #include "precomp.h" 9 10 /* 11 NTSTATUS 12 NTAPI 13 RtlGetFullPathName_UstrEx( 14 IN PUNICODE_STRING FileName, 15 IN PUNICODE_STRING StaticString, 16 IN PUNICODE_STRING DynamicString, 17 IN PUNICODE_STRING *StringUsed, 18 IN PSIZE_T FilePartSize OPTIONAL, 19 OUT PBOOLEAN NameInvalid, 20 OUT RTL_PATH_TYPE* PathType, 21 OUT PSIZE_T LengthNeeded OPTIONAL 22 ); 23 */ 24 25 NTSTATUS 26 (NTAPI 27 *pRtlGetFullPathName_UstrEx)( 28 IN PUNICODE_STRING FileName, 29 IN PUNICODE_STRING StaticString, 30 IN PUNICODE_STRING DynamicString, 31 IN PUNICODE_STRING *StringUsed, 32 IN PSIZE_T FilePartSize OPTIONAL, 33 OUT PBOOLEAN NameInvalid, 34 OUT RTL_PATH_TYPE* PathType, 35 OUT PSIZE_T LengthNeeded OPTIONAL 36 ); 37 38 #define ok_eq_ustr(str1, str2) do { \ 39 ok((str1)->Buffer == (str2)->Buffer, "Buffer modified\n"); \ 40 ok((str1)->Length == (str2)->Length, "Length modified\n"); \ 41 ok((str1)->MaximumLength == (str2)->MaximumLength, "MaximumLength modified\n"); \ 42 } while (0) 43 44 static 45 BOOLEAN 46 CheckStringBuffer( 47 PCUNICODE_STRING String, 48 PCWSTR Expected) 49 { 50 SIZE_T ExpectedLength = wcslen(Expected) * sizeof(WCHAR); 51 SIZE_T EqualLength; 52 BOOLEAN Result = TRUE; 53 SIZE_T i; 54 55 if (String->Length != ExpectedLength) 56 { 57 ok(0, "String length is %u, expected %lu\n", String->Length, (ULONG)ExpectedLength); 58 Result = FALSE; 59 } 60 61 EqualLength = RtlCompareMemory(String->Buffer, Expected, ExpectedLength); 62 if (EqualLength != ExpectedLength) 63 { 64 ok(0, "String is '%wZ', expected '%S'\n", String, Expected); 65 Result = FALSE; 66 } 67 68 if (String->Buffer[String->Length / sizeof(WCHAR)] != UNICODE_NULL) 69 { 70 ok(0, "Not null terminated\n"); 71 Result = FALSE; 72 } 73 74 /* the function nulls the rest of the buffer! */ 75 for (i = String->Length + sizeof(UNICODE_NULL); i < String->MaximumLength; i++) 76 { 77 UCHAR Char = ((PUCHAR)String->Buffer)[i]; 78 if (Char != 0) 79 { 80 ok(0, "Found 0x%x at offset %lu, expected 0x%x\n", Char, (ULONG)i, 0); 81 /* don't count this as a failure unless the string was actually wrong */ 82 //Result = FALSE; 83 /* don't flood the log */ 84 break; 85 } 86 } 87 88 return Result; 89 } 90 91 static 92 BOOLEAN 93 CheckBuffer( 94 PVOID Buffer, 95 SIZE_T Size, 96 UCHAR Value) 97 { 98 PUCHAR Array = Buffer; 99 SIZE_T i; 100 101 for (i = 0; i < Size; i++) 102 { 103 if (Array[i] != Value) 104 { 105 trace("Expected %x, found %x at offset %lu\n", Value, Array[i], (ULONG)i); 106 return FALSE; 107 } 108 } 109 return TRUE; 110 } 111 112 #define RtlPathTypeNotSet 123 113 114 /* winetest_platform is "windows" for us, so broken() doesn't do what it should :( */ 115 #undef broken 116 #define broken(x) 0 117 118 typedef enum 119 { 120 PrefixNone, 121 PrefixCurrentDrive, 122 PrefixCurrentPath, 123 PrefixCurrentPathWithoutLastPart 124 } PREFIX_TYPE; 125 126 static 127 VOID 128 RunTestCases(VOID) 129 { 130 /* TODO: don't duplicate this in the other tests */ 131 /* TODO: Drive Relative tests don't work yet if the current drive isn't C: */ 132 struct 133 { 134 PCWSTR FileName; 135 PREFIX_TYPE PrefixType; 136 PCWSTR FullPathName; 137 RTL_PATH_TYPE PathType; 138 PREFIX_TYPE FilePartPrefixType; 139 SIZE_T FilePartSize; 140 } TestCases[] = 141 { 142 { L"C:", PrefixCurrentPath, L"", RtlPathTypeDriveRelative, PrefixCurrentPathWithoutLastPart }, 143 { L"C:\\", PrefixNone, L"C:\\", RtlPathTypeDriveAbsolute }, 144 { L"C:\\test", PrefixNone, L"C:\\test", RtlPathTypeDriveAbsolute, PrefixCurrentDrive }, 145 { L"C:\\test\\", PrefixNone, L"C:\\test\\", RtlPathTypeDriveAbsolute }, 146 { L"C:/test/", PrefixNone, L"C:\\test\\", RtlPathTypeDriveAbsolute }, 147 148 { L"C:\\\\test", PrefixNone, L"C:\\test", RtlPathTypeDriveAbsolute, PrefixCurrentDrive }, 149 { L"test", PrefixCurrentPath, L"\\test", RtlPathTypeRelative, PrefixCurrentPath, sizeof(WCHAR) }, 150 { L"\\test", PrefixCurrentDrive, L"test", RtlPathTypeRooted, PrefixCurrentDrive }, 151 { L"/test", PrefixCurrentDrive, L"test", RtlPathTypeRooted, PrefixCurrentDrive }, 152 { L".\\test", PrefixCurrentPath, L"\\test", RtlPathTypeRelative, PrefixCurrentPath, sizeof(WCHAR) }, 153 154 { L"\\.", PrefixCurrentDrive, L"", RtlPathTypeRooted }, 155 { L"\\.\\", PrefixCurrentDrive, L"", RtlPathTypeRooted }, 156 { L"\\\\.", PrefixNone, L"\\\\.\\", RtlPathTypeRootLocalDevice }, 157 { L"\\\\.\\", PrefixNone, L"\\\\.\\", RtlPathTypeLocalDevice }, 158 { L"\\\\.\\Something\\", PrefixNone, L"\\\\.\\Something\\", RtlPathTypeLocalDevice }, 159 160 { L"\\??\\", PrefixCurrentDrive, L"??\\", RtlPathTypeRooted }, 161 { L"\\??\\C:", PrefixCurrentDrive, L"??\\C:", RtlPathTypeRooted, PrefixCurrentDrive, 3 * sizeof(WCHAR) }, 162 { L"\\??\\C:\\", PrefixCurrentDrive, L"??\\C:\\", RtlPathTypeRooted }, 163 { L"\\??\\C:\\test", PrefixCurrentDrive, L"??\\C:\\test", RtlPathTypeRooted, PrefixCurrentDrive, 6 * sizeof(WCHAR) }, 164 { L"\\??\\C:\\test\\", PrefixCurrentDrive, L"??\\C:\\test\\", RtlPathTypeRooted }, 165 166 { L"\\\\??\\", PrefixNone, L"\\\\??\\", RtlPathTypeUncAbsolute }, 167 { L"\\\\??\\C:", PrefixNone, L"\\\\??\\C:", RtlPathTypeUncAbsolute }, 168 { L"\\\\??\\C:\\", PrefixNone, L"\\\\??\\C:\\", RtlPathTypeUncAbsolute }, 169 { L"\\\\??\\C:\\test", PrefixNone, L"\\\\??\\C:\\test", RtlPathTypeUncAbsolute, PrefixNone, sizeof(L"\\\\??\\C:\\") }, 170 { L"\\\\??\\C:\\test\\", PrefixNone, L"\\\\??\\C:\\test\\", RtlPathTypeUncAbsolute }, 171 }; 172 NTSTATUS Status; 173 UNICODE_STRING FileName; 174 UNICODE_STRING FullPathName; 175 WCHAR FullPathNameBuffer[MAX_PATH]; 176 UNICODE_STRING TempString; 177 PUNICODE_STRING StringUsed; 178 SIZE_T FilePartSize; 179 BOOLEAN NameInvalid; 180 RTL_PATH_TYPE PathType; 181 SIZE_T LengthNeeded; 182 WCHAR ExpectedPathName[MAX_PATH]; 183 SIZE_T ExpectedFilePartSize; 184 const INT TestCount = sizeof(TestCases) / sizeof(TestCases[0]); 185 INT i; 186 BOOLEAN Okay; 187 188 for (i = 0; i < TestCount; i++) 189 { 190 switch (TestCases[i].PrefixType) 191 { 192 case PrefixNone: 193 ExpectedPathName[0] = UNICODE_NULL; 194 break; 195 case PrefixCurrentDrive: 196 GetCurrentDirectoryW(sizeof(ExpectedPathName) / sizeof(WCHAR), ExpectedPathName); 197 ExpectedPathName[3] = UNICODE_NULL; 198 break; 199 case PrefixCurrentPath: 200 { 201 ULONG Length; 202 Length = GetCurrentDirectoryW(sizeof(ExpectedPathName) / sizeof(WCHAR), ExpectedPathName); 203 if (Length == 3 && TestCases[i].FullPathName[0]) 204 ExpectedPathName[2] = UNICODE_NULL; 205 break; 206 } 207 default: 208 skip("Invalid test!\n"); 209 continue; 210 } 211 wcscat(ExpectedPathName, TestCases[i].FullPathName); 212 RtlInitUnicodeString(&FileName, TestCases[i].FileName); 213 RtlInitEmptyUnicodeString(&FullPathName, FullPathNameBuffer, sizeof(FullPathNameBuffer)); 214 RtlFillMemory(FullPathName.Buffer, FullPathName.MaximumLength, 0xAA); 215 TempString = FileName; 216 PathType = RtlPathTypeNotSet; 217 StringUsed = InvalidPointer; 218 FilePartSize = 1234; 219 NameInvalid = (BOOLEAN)-1; 220 LengthNeeded = 1234; 221 StartSeh() 222 Status = pRtlGetFullPathName_UstrEx(&FileName, 223 &FullPathName, 224 NULL, 225 &StringUsed, 226 &FilePartSize, 227 &NameInvalid, 228 &PathType, 229 &LengthNeeded); 230 ok(Status == STATUS_SUCCESS, "status = %lx\n", Status); 231 EndSeh(STATUS_SUCCESS); 232 ok_eq_ustr(&FileName, &TempString); 233 ok(FullPathName.Buffer == FullPathNameBuffer, "Buffer modified\n"); 234 ok(FullPathName.MaximumLength == sizeof(FullPathNameBuffer), "MaximumLength modified\n"); 235 Okay = CheckStringBuffer(&FullPathName, ExpectedPathName); 236 ok(Okay, "Wrong path name '%wZ', expected '%S'\n", &FullPathName, ExpectedPathName); 237 ok(StringUsed == &FullPathName, "StringUsed = %p, expected %p\n", StringUsed, &FullPathName); 238 switch (TestCases[i].FilePartPrefixType) 239 { 240 case PrefixNone: 241 ExpectedFilePartSize = 0; 242 break; 243 case PrefixCurrentDrive: 244 ExpectedFilePartSize = sizeof(L"C:\\"); 245 break; 246 case PrefixCurrentPath: 247 ExpectedFilePartSize = GetCurrentDirectoryW(0, NULL) * sizeof(WCHAR); 248 if (ExpectedFilePartSize == sizeof(L"C:\\")) 249 ExpectedFilePartSize -= sizeof(WCHAR); 250 break; 251 case PrefixCurrentPathWithoutLastPart: 252 { 253 WCHAR CurrentPath[MAX_PATH]; 254 PCWSTR BackSlash; 255 ExpectedFilePartSize = GetCurrentDirectoryW(sizeof(CurrentPath) / sizeof(WCHAR), CurrentPath) * sizeof(WCHAR) + sizeof(UNICODE_NULL); 256 if (ExpectedFilePartSize == sizeof(L"C:\\")) 257 ExpectedFilePartSize = 0; 258 else 259 { 260 BackSlash = wcsrchr(CurrentPath, L'\\'); 261 if (BackSlash) 262 ExpectedFilePartSize -= wcslen(BackSlash + 1) * sizeof(WCHAR); 263 else 264 ok(0, "GetCurrentDirectory returned %S\n", CurrentPath); 265 } 266 break; 267 } 268 default: 269 skip("Invalid test!\n"); 270 continue; 271 } 272 ExpectedFilePartSize += TestCases[i].FilePartSize; 273 if (ExpectedFilePartSize != 0) 274 ExpectedFilePartSize = (ExpectedFilePartSize - sizeof(UNICODE_NULL)) / sizeof(WCHAR); 275 ok(FilePartSize == ExpectedFilePartSize, 276 "FilePartSize = %lu, expected %lu\n", (ULONG)FilePartSize, (ULONG)ExpectedFilePartSize); 277 ok(NameInvalid == FALSE, "NameInvalid = %u\n", NameInvalid); 278 ok(PathType == TestCases[i].PathType, "PathType = %d, expected %d\n", PathType, TestCases[i].PathType); 279 ok(LengthNeeded == 0, "LengthNeeded = %lu\n", (ULONG)LengthNeeded); 280 } 281 } 282 283 START_TEST(RtlGetFullPathName_UstrEx) 284 { 285 NTSTATUS Status; 286 UNICODE_STRING FileName; 287 UNICODE_STRING TempString; 288 UNICODE_STRING StaticString; 289 PUNICODE_STRING StringUsed; 290 SIZE_T FilePartSize; 291 BOOLEAN NameInvalid; 292 BOOLEAN NameInvalidArray[sizeof(ULONGLONG)]; 293 RTL_PATH_TYPE PathType; 294 SIZE_T LengthNeeded; 295 BOOLEAN Okay; 296 297 pRtlGetFullPathName_UstrEx = (PVOID)GetProcAddress(GetModuleHandleW(L"ntdll"), "RtlGetFullPathName_UstrEx"); 298 if (!pRtlGetFullPathName_UstrEx) 299 { 300 skip("RtlGetFullPathName_UstrEx unavailable\n"); 301 return; 302 } 303 304 /* NULL parameters */ 305 StartSeh() 306 pRtlGetFullPathName_UstrEx(NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL); 307 EndSeh(STATUS_ACCESS_VIOLATION); 308 309 RtlInitUnicodeString(&FileName, NULL); 310 TempString = FileName; 311 StartSeh() 312 pRtlGetFullPathName_UstrEx(&FileName, NULL, NULL, NULL, NULL, NULL, NULL, NULL); 313 EndSeh(STATUS_ACCESS_VIOLATION); 314 ok_eq_ustr(&FileName, &TempString); 315 316 RtlInitUnicodeString(&FileName, L""); 317 TempString = FileName; 318 StartSeh() 319 pRtlGetFullPathName_UstrEx(&FileName, NULL, NULL, NULL, NULL, NULL, NULL, NULL); 320 EndSeh(STATUS_ACCESS_VIOLATION); 321 ok_eq_ustr(&FileName, &TempString); 322 323 PathType = RtlPathTypeNotSet; 324 StartSeh() 325 pRtlGetFullPathName_UstrEx(NULL, NULL, NULL, NULL, NULL, NULL, &PathType, NULL); 326 EndSeh(STATUS_ACCESS_VIOLATION); 327 ok(PathType == RtlPathTypeUnknown || 328 broken(PathType == RtlPathTypeNotSet) /* Win7 */, "PathType = %d\n", PathType); 329 330 /* Check what else is initialized before it crashes */ 331 PathType = RtlPathTypeNotSet; 332 StringUsed = InvalidPointer; 333 FilePartSize = 1234; 334 NameInvalid = (BOOLEAN)-1; 335 LengthNeeded = 1234; 336 StartSeh() 337 pRtlGetFullPathName_UstrEx(NULL, NULL, NULL, &StringUsed, &FilePartSize, &NameInvalid, &PathType, &LengthNeeded); 338 EndSeh(STATUS_ACCESS_VIOLATION); 339 ok(StringUsed == NULL, "StringUsed = %p\n", StringUsed); 340 ok(FilePartSize == 0, "FilePartSize = %lu\n", (ULONG)FilePartSize); 341 ok(NameInvalid == FALSE, "NameInvalid = %u\n", NameInvalid); 342 ok(PathType == RtlPathTypeUnknown || 343 broken(PathType == RtlPathTypeNotSet) /* Win7 */, "PathType = %d\n", PathType); 344 ok(LengthNeeded == 0, "LengthNeeded = %lu\n", (ULONG)LengthNeeded); 345 346 RtlInitUnicodeString(&FileName, L""); 347 TempString = FileName; 348 StringUsed = InvalidPointer; 349 FilePartSize = 1234; 350 NameInvalid = (BOOLEAN)-1; 351 LengthNeeded = 1234; 352 StartSeh() 353 pRtlGetFullPathName_UstrEx(&FileName, NULL, NULL, &StringUsed, &FilePartSize, &NameInvalid, NULL, &LengthNeeded); 354 EndSeh(STATUS_ACCESS_VIOLATION); 355 ok_eq_ustr(&FileName, &TempString); 356 ok(StringUsed == NULL, "StringUsed = %p\n", StringUsed); 357 ok(FilePartSize == 0, "FilePartSize = %lu\n", (ULONG)FilePartSize); 358 ok(NameInvalid == FALSE || 359 broken(NameInvalid == (BOOLEAN)-1) /* Win7 */, "NameInvalid = %u\n", NameInvalid); 360 ok(LengthNeeded == 0, "LengthNeeded = %lu\n", (ULONG)LengthNeeded); 361 362 /* This is the first one that doesn't crash. FileName and PathType cannot be NULL */ 363 RtlInitUnicodeString(&FileName, NULL); 364 TempString = FileName; 365 PathType = RtlPathTypeNotSet; 366 StartSeh() 367 Status = pRtlGetFullPathName_UstrEx(&FileName, NULL, NULL, NULL, NULL, NULL, &PathType, NULL); 368 ok(Status == STATUS_OBJECT_NAME_INVALID, "status = %lx\n", Status); 369 EndSeh(STATUS_SUCCESS); 370 ok_eq_ustr(&FileName, &TempString); 371 ok(PathType == RtlPathTypeUnknown, "PathType = %d\n", PathType); 372 373 RtlInitUnicodeString(&FileName, L""); 374 TempString = FileName; 375 PathType = RtlPathTypeNotSet; 376 StartSeh() 377 Status = pRtlGetFullPathName_UstrEx(&FileName, NULL, NULL, NULL, NULL, NULL, &PathType, NULL); 378 ok(Status == STATUS_OBJECT_NAME_INVALID, "status = %lx\n", Status); 379 EndSeh(STATUS_SUCCESS); 380 ok_eq_ustr(&FileName, &TempString); 381 ok(PathType == RtlPathTypeUnknown, "PathType = %d\n", PathType); 382 383 /* Show that NameInvalid is indeed BOOLEAN */ 384 RtlInitUnicodeString(&FileName, L""); 385 TempString = FileName; 386 PathType = RtlPathTypeNotSet; 387 RtlFillMemory(NameInvalidArray, sizeof(NameInvalidArray), 0x55); 388 StartSeh() 389 Status = pRtlGetFullPathName_UstrEx(&FileName, NULL, NULL, NULL, NULL, NameInvalidArray, &PathType, NULL); 390 ok(Status == STATUS_OBJECT_NAME_INVALID, "status = %lx\n", Status); 391 EndSeh(STATUS_SUCCESS); 392 ok_eq_ustr(&FileName, &TempString); 393 ok(PathType == RtlPathTypeUnknown, "PathType = %d\n", PathType); 394 ok(NameInvalidArray[0] == FALSE, "NameInvalid = %u\n", NameInvalidArray[0]); 395 Okay = CheckBuffer(NameInvalidArray + 1, sizeof(NameInvalidArray) - sizeof(NameInvalidArray[0]), 0x55); 396 ok(Okay, "CheckBuffer failed\n"); 397 398 /* Give it a valid path */ 399 RtlInitUnicodeString(&FileName, L"C:\\test"); 400 TempString = FileName; 401 PathType = RtlPathTypeNotSet; 402 StartSeh() 403 Status = pRtlGetFullPathName_UstrEx(&FileName, NULL, NULL, NULL, NULL, NULL, &PathType, NULL); 404 ok(Status == STATUS_BUFFER_TOO_SMALL, "status = %lx\n", Status); 405 EndSeh(STATUS_SUCCESS); 406 ok_eq_ustr(&FileName, &TempString); 407 ok(PathType == RtlPathTypeDriveAbsolute, "PathType = %d\n", PathType); 408 409 /* Zero-length static string */ 410 RtlInitUnicodeString(&FileName, L"C:\\test"); 411 TempString = FileName; 412 RtlInitUnicodeString(&StaticString, NULL); 413 PathType = RtlPathTypeNotSet; 414 StartSeh() 415 Status = pRtlGetFullPathName_UstrEx(&FileName, &StaticString, NULL, NULL, NULL, NULL, &PathType, NULL); 416 ok(Status == STATUS_BUFFER_TOO_SMALL, "status = %lx\n", Status); 417 EndSeh(STATUS_SUCCESS); 418 ok_eq_ustr(&FileName, &TempString); 419 ok(PathType == RtlPathTypeDriveAbsolute, "PathType = %d\n", PathType); 420 421 /* TODO: play around with StaticString and DynamicString */ 422 423 /* Check the actual functionality with different paths */ 424 RunTestCases(); 425 } 426