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