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 ULONG Line; 143 PCWSTR FileName; 144 PREFIX_TYPE PrefixType; 145 PCWSTR FullPathName; 146 RTL_PATH_TYPE PathType; 147 PREFIX_TYPE FilePartPrefixType; 148 SIZE_T FilePartSize; 149 } TestCases[] = 150 { 151 { __LINE__, L"C:", PrefixCurrentPath, L"", RtlPathTypeDriveRelative, PrefixCurrentPathWithoutLastPart }, 152 { __LINE__, L"C:\\", PrefixNone, L"C:\\", RtlPathTypeDriveAbsolute }, 153 { __LINE__, L"C:\\test", PrefixNone, L"C:\\test", RtlPathTypeDriveAbsolute, PrefixCurrentDrive }, 154 { __LINE__, L"C:\\test\\", PrefixNone, L"C:\\test\\", RtlPathTypeDriveAbsolute }, 155 { __LINE__, L"C:/test/", PrefixNone, L"C:\\test\\", RtlPathTypeDriveAbsolute }, 156 157 { __LINE__, L"C:\\\\test", PrefixNone, L"C:\\test", RtlPathTypeDriveAbsolute, PrefixCurrentDrive }, 158 { __LINE__, L"test", PrefixCurrentPath, L"\\test", RtlPathTypeRelative, PrefixCurrentPath, sizeof(WCHAR) }, 159 { __LINE__, L"\\test", PrefixCurrentDrive, L"test", RtlPathTypeRooted, PrefixCurrentDrive }, 160 { __LINE__, L"/test", PrefixCurrentDrive, L"test", RtlPathTypeRooted, PrefixCurrentDrive }, 161 { __LINE__, L".\\test", PrefixCurrentPath, L"\\test", RtlPathTypeRelative, PrefixCurrentPath, sizeof(WCHAR) }, 162 163 { __LINE__, L"\\.", PrefixCurrentDrive, L"", RtlPathTypeRooted }, 164 { __LINE__, L"\\.\\", PrefixCurrentDrive, L"", RtlPathTypeRooted }, 165 { __LINE__, L"\\\\.", PrefixNone, L"\\\\.\\", RtlPathTypeRootLocalDevice }, 166 { __LINE__, L"\\\\.\\", PrefixNone, L"\\\\.\\", RtlPathTypeLocalDevice }, 167 { __LINE__, L"\\\\.\\Something\\", PrefixNone, L"\\\\.\\Something\\", RtlPathTypeLocalDevice }, 168 169 { __LINE__, L"\\??\\", PrefixCurrentDrive, L"??\\", RtlPathTypeRooted }, 170 { __LINE__, L"\\??\\C:", PrefixCurrentDrive, L"??\\C:", RtlPathTypeRooted, PrefixCurrentDrive, 3 * sizeof(WCHAR) }, 171 { __LINE__, L"\\??\\C:\\", PrefixCurrentDrive, L"??\\C:\\", RtlPathTypeRooted }, 172 { __LINE__, L"\\??\\C:\\test", PrefixCurrentDrive, L"??\\C:\\test", RtlPathTypeRooted, PrefixCurrentDrive, 6 * sizeof(WCHAR) }, 173 { __LINE__, L"\\??\\C:\\test\\", PrefixCurrentDrive, L"??\\C:\\test\\", RtlPathTypeRooted }, 174 175 { __LINE__, L"\\\\??\\", PrefixNone, L"\\\\??\\", RtlPathTypeUncAbsolute }, 176 { __LINE__, L"\\\\??\\C:", PrefixNone, L"\\\\??\\C:", RtlPathTypeUncAbsolute }, 177 { __LINE__, L"\\\\??\\C:\\", PrefixNone, L"\\\\??\\C:\\", RtlPathTypeUncAbsolute }, 178 { __LINE__, L"\\\\??\\C:\\test", PrefixNone, L"\\\\??\\C:\\test", RtlPathTypeUncAbsolute, PrefixNone, sizeof(L"\\\\??\\C:\\") }, 179 { __LINE__, L"\\\\??\\C:\\test\\", PrefixNone, L"\\\\??\\C:\\test\\", RtlPathTypeUncAbsolute }, 180 }; 181 ULONG Length; 182 UNICODE_STRING FileName; 183 WCHAR FullPathNameBuffer[MAX_PATH]; 184 UNICODE_STRING TempString; 185 const WCHAR *ShortName; 186 BOOLEAN NameInvalid; 187 PATH_TYPE_AND_UNKNOWN PathType; 188 WCHAR ExpectedPathName[MAX_PATH]; 189 SIZE_T ExpectedFilePartSize; 190 const WCHAR *ExpectedShortName; 191 const INT TestCount = sizeof(TestCases) / sizeof(TestCases[0]); 192 INT i; 193 BOOLEAN Okay; 194 195 for (i = 0; i < TestCount; i++) 196 { 197 trace("i = %d\n", i); 198 switch (TestCases[i].PrefixType) 199 { 200 case PrefixNone: 201 ExpectedPathName[0] = UNICODE_NULL; 202 break; 203 case PrefixCurrentDrive: 204 GetCurrentDirectoryW(sizeof(ExpectedPathName) / sizeof(WCHAR), ExpectedPathName); 205 ExpectedPathName[3] = UNICODE_NULL; 206 break; 207 case PrefixCurrentPath: 208 { 209 ULONG Length; 210 Length = GetCurrentDirectoryW(sizeof(ExpectedPathName) / sizeof(WCHAR), ExpectedPathName); 211 if (Length == 3 && TestCases[i].FullPathName[0]) 212 ExpectedPathName[2] = UNICODE_NULL; 213 break; 214 } 215 default: 216 skip("Invalid test!\n"); 217 continue; 218 } 219 wcscat(ExpectedPathName, TestCases[i].FullPathName); 220 RtlInitUnicodeString(&FileName, TestCases[i].FileName); 221 RtlFillMemory(FullPathNameBuffer, sizeof(FullPathNameBuffer), 0xAA); 222 TempString = FileName; 223 PathType.Type = RtlPathTypeNotSet; 224 PathType.Unknown = 1234; 225 ShortName = InvalidPointer; 226 NameInvalid = (BOOLEAN)-1; 227 Length = 1234; 228 StartSeh() 229 Length = RtlGetFullPathName_Ustr(&FileName, 230 sizeof(FullPathNameBuffer), 231 FullPathNameBuffer, 232 &ShortName, 233 &NameInvalid, 234 &PathType); 235 EndSeh(STATUS_SUCCESS); 236 ok_eq_ustr(&FileName, &TempString); 237 Okay = CheckStringBuffer(FullPathNameBuffer, Length, sizeof(FullPathNameBuffer), ExpectedPathName); 238 ok(Okay, "Line %lu: Wrong path name '%S', expected '%S'\n", TestCases[i].Line, FullPathNameBuffer, ExpectedPathName); 239 switch (TestCases[i].FilePartPrefixType) 240 { 241 case PrefixNone: 242 ExpectedFilePartSize = 0; 243 break; 244 case PrefixCurrentDrive: 245 ExpectedFilePartSize = sizeof(L"C:\\"); 246 break; 247 case PrefixCurrentPath: 248 ExpectedFilePartSize = GetCurrentDirectoryW(0, NULL) * sizeof(WCHAR); 249 if (ExpectedFilePartSize == sizeof(L"C:\\")) 250 ExpectedFilePartSize -= sizeof(WCHAR); 251 break; 252 case PrefixCurrentPathWithoutLastPart: 253 { 254 WCHAR CurrentPath[MAX_PATH]; 255 PCWSTR BackSlash; 256 ExpectedFilePartSize = GetCurrentDirectoryW(sizeof(CurrentPath) / sizeof(WCHAR), CurrentPath) * sizeof(WCHAR) + sizeof(UNICODE_NULL); 257 if (ExpectedFilePartSize == sizeof(L"C:\\")) 258 ExpectedFilePartSize = 0; 259 else 260 { 261 BackSlash = wcsrchr(CurrentPath, L'\\'); 262 if (BackSlash) 263 ExpectedFilePartSize -= wcslen(BackSlash + 1) * sizeof(WCHAR); 264 else 265 ok(0, "Line %lu: GetCurrentDirectory returned %S\n", TestCases[i].Line, CurrentPath); 266 } 267 break; 268 } 269 default: 270 skip("Invalid test!\n"); 271 continue; 272 } 273 ExpectedFilePartSize += TestCases[i].FilePartSize; 274 if (ExpectedFilePartSize == 0) 275 { 276 ExpectedShortName = NULL; 277 } 278 else 279 { 280 ExpectedFilePartSize = (ExpectedFilePartSize - sizeof(UNICODE_NULL)) / sizeof(WCHAR); 281 ExpectedShortName = FullPathNameBuffer + ExpectedFilePartSize; 282 } 283 ok(ShortName == ExpectedShortName, 284 "ShortName = %p, expected %p\n", ShortName, ExpectedShortName); 285 ok(NameInvalid == FALSE, "Line %lu: NameInvalid = %u\n", TestCases[i].Line, NameInvalid); 286 ok(PathType.Type == TestCases[i].PathType, "Line %lu: PathType = %d, expected %d\n", TestCases[i].Line, PathType.Type, TestCases[i].PathType); 287 ok(PathType.Unknown == 1234 || 288 broken(PathType.Unknown == 0) || 289 broken(PathType.Unknown == 32), "Line %lu: Unknown = %lu\n", TestCases[i].Line, PathType.Unknown); 290 } 291 } 292 293 START_TEST(RtlGetFullPathName_Ustr) 294 { 295 ULONG Length; 296 UNICODE_STRING FileName; 297 UNICODE_STRING TempString; 298 PCWSTR ShortName; 299 BOOLEAN NameInvalid; 300 BOOLEAN NameInvalidArray[sizeof(ULONGLONG)]; 301 PATH_TYPE_AND_UNKNOWN PathType; 302 BOOLEAN Okay; 303 304 if (!RtlGetFullPathName_Ustr) 305 { 306 RtlGetFullPathName_Ustr = (PVOID)GetProcAddress(GetModuleHandleW(L"ntdll"), "RtlGetFullPathName_Ustr"); 307 if (!RtlGetFullPathName_Ustr) 308 { 309 skip("RtlGetFullPathName_Ustr unavailable\n"); 310 return; 311 } 312 } 313 314 /* NULL parameters */ 315 StartSeh() 316 RtlGetFullPathName_Ustr(NULL, 0, NULL, NULL, NULL, NULL); 317 EndSeh(STATUS_ACCESS_VIOLATION); 318 319 RtlInitUnicodeString(&FileName, NULL); 320 TempString = FileName; 321 StartSeh() 322 RtlGetFullPathName_Ustr(&FileName, 0, NULL, NULL, NULL, NULL); 323 EndSeh(STATUS_ACCESS_VIOLATION); 324 ok_eq_ustr(&FileName, &TempString); 325 326 RtlInitUnicodeString(&FileName, L""); 327 TempString = FileName; 328 StartSeh() 329 RtlGetFullPathName_Ustr(&FileName, 0, NULL, NULL, NULL, NULL); 330 EndSeh(STATUS_ACCESS_VIOLATION); 331 ok_eq_ustr(&FileName, &TempString); 332 333 PathType.Type = RtlPathTypeNotSet; 334 PathType.Unknown = 1234; 335 StartSeh() 336 RtlGetFullPathName_Ustr(NULL, 0, NULL, NULL, NULL, &PathType); 337 EndSeh(STATUS_ACCESS_VIOLATION); 338 ok(PathType.Type == RtlPathTypeUnknown, "PathType = %d\n", PathType.Type); 339 ok(PathType.Unknown == 1234 || 340 broken(PathType.Unknown == 0) /* Win7 */, "Unknown = %lu\n", PathType.Unknown); 341 342 /* check what else is initialized before it crashes */ 343 PathType.Type = RtlPathTypeNotSet; 344 PathType.Unknown = 1234; 345 ShortName = InvalidPointer; 346 NameInvalid = (BOOLEAN)-1; 347 StartSeh() 348 RtlGetFullPathName_Ustr(NULL, 0, NULL, &ShortName, &NameInvalid, &PathType); 349 EndSeh(STATUS_ACCESS_VIOLATION); 350 ok(NameInvalid == FALSE, "NameInvalid = %u\n", NameInvalid); 351 ok(ShortName == InvalidPointer || 352 broken(ShortName == NULL) /* Win7 */, "ShortName = %p\n", ShortName); 353 ok(PathType.Type == RtlPathTypeUnknown, "PathType = %d\n", PathType.Type); 354 ok(PathType.Unknown == 1234 || 355 broken(PathType.Unknown == 0) /* Win7 */, "Unknown = %lu\n", PathType.Unknown); 356 357 RtlInitUnicodeString(&FileName, L""); 358 TempString = FileName; 359 ShortName = InvalidPointer; 360 NameInvalid = (BOOLEAN)-1; 361 StartSeh() 362 RtlGetFullPathName_Ustr(&FileName, 0, NULL, &ShortName, &NameInvalid, NULL); 363 EndSeh(STATUS_ACCESS_VIOLATION); 364 ok_eq_ustr(&FileName, &TempString); 365 ok(ShortName == InvalidPointer || 366 broken(ShortName == NULL) /* Win7 */, "ShortName = %p\n", ShortName); 367 ok(NameInvalid == FALSE, "NameInvalid = %u\n", NameInvalid); 368 369 /* This is the first one that doesn't crash. FileName and PathType cannot be NULL */ 370 RtlInitUnicodeString(&FileName, NULL); 371 TempString = FileName; 372 PathType.Type = RtlPathTypeNotSet; 373 PathType.Unknown = 1234; 374 StartSeh() 375 Length = RtlGetFullPathName_Ustr(&FileName, 0, NULL, NULL, NULL, &PathType); 376 ok(Length == 0, "Length = %lu\n", Length); 377 EndSeh(STATUS_SUCCESS); 378 ok_eq_ustr(&FileName, &TempString); 379 ok(PathType.Type == RtlPathTypeUnknown, "PathType = %d\n", PathType.Type); 380 ok(PathType.Unknown == 1234 || 381 broken(PathType.Unknown == 0) /* Win7 */, "Unknown = %lu\n", PathType.Unknown); 382 383 RtlInitUnicodeString(&FileName, L""); 384 TempString = FileName; 385 PathType.Type = RtlPathTypeNotSet; 386 PathType.Unknown = 1234; 387 StartSeh() 388 Length = RtlGetFullPathName_Ustr(&FileName, 0, NULL, NULL, NULL, &PathType); 389 ok(Length == 0, "Length = %lu\n", Length); 390 EndSeh(STATUS_SUCCESS); 391 ok_eq_ustr(&FileName, &TempString); 392 ok(PathType.Type == RtlPathTypeUnknown, "PathType = %d\n", PathType.Type); 393 ok(PathType.Unknown == 1234 || 394 broken(PathType.Unknown == 0) /* Win7 */, "Unknown = %lu\n", PathType.Unknown); 395 396 /* Show that NameInvalid is indeed BOOLEAN */ 397 RtlInitUnicodeString(&FileName, L""); 398 TempString = FileName; 399 PathType.Type = RtlPathTypeNotSet; 400 PathType.Unknown = 1234; 401 RtlFillMemory(NameInvalidArray, sizeof(NameInvalidArray), 0x55); 402 StartSeh() 403 Length = RtlGetFullPathName_Ustr(&FileName, 0, NULL, NULL, NameInvalidArray, &PathType); 404 ok(Length == 0, "Length = %lu\n", Length); 405 EndSeh(STATUS_SUCCESS); 406 ok_eq_ustr(&FileName, &TempString); 407 ok(PathType.Type == RtlPathTypeUnknown, "PathType = %d\n", PathType.Type); 408 ok(PathType.Unknown == 1234 || 409 broken(PathType.Unknown == 0) /* Win7 */, "Unknown = %lu\n", PathType.Unknown); 410 ok(NameInvalidArray[0] == FALSE, "NameInvalid = %u\n", NameInvalidArray[0]); 411 Okay = CheckBuffer(NameInvalidArray + 1, sizeof(NameInvalidArray) - sizeof(NameInvalidArray[0]), 0x55); 412 ok(Okay, "CheckBuffer failed\n"); 413 414 /* Give it a valid path */ 415 RtlInitUnicodeString(&FileName, L"C:\\test"); 416 TempString = FileName; 417 PathType.Type = RtlPathTypeNotSet; 418 PathType.Unknown = 1234; 419 StartSeh() 420 Length = RtlGetFullPathName_Ustr(&FileName, 0, NULL, NULL, NULL, &PathType); 421 ok(Length == sizeof(L"C:\\test"), "Length = %lu\n", Length); 422 EndSeh(STATUS_SUCCESS); 423 ok_eq_ustr(&FileName, &TempString); 424 ok(PathType.Type == RtlPathTypeDriveAbsolute, "PathType = %d\n", PathType.Type); 425 ok(PathType.Unknown == 1234 || 426 broken(PathType.Unknown == 0) /* Win7 */, "Unknown = %lu\n", PathType.Unknown); 427 428 /* check the actual functionality with different paths */ 429 RunTestCases(); 430 } 431