1 /* 2 * PROJECT: ReactOS kernel-mode tests 3 * LICENSE: LGPLv2.1+ - See COPYING.LIB in the top level directory 4 * PURPOSE: Kernel-Mode Test Suite File System test 5 * PROGRAMMER: Thomas Faber <thomas.faber@reactos.org> 6 */ 7 8 #include <kmt_test.h> 9 10 /* FIXME: Test this stuff on non-FAT volumes */ 11 12 static 13 NTSTATUS 14 QueryFileInfo( 15 _In_ HANDLE FileHandle, 16 _Out_ PVOID *Info, 17 _Inout_ PSIZE_T Length, 18 _In_ FILE_INFORMATION_CLASS FileInformationClass) 19 { 20 NTSTATUS Status; 21 IO_STATUS_BLOCK IoStatus; 22 PVOID Buffer; 23 24 *Info = NULL; 25 if (*Length) 26 { 27 Buffer = KmtAllocateGuarded(*Length); 28 if (skip(Buffer != NULL, "Failed to allocate %Iu bytes\n", *Length)) 29 return STATUS_INSUFFICIENT_RESOURCES; 30 31 RtlFillMemory(Buffer, *Length, 0xdd); 32 } 33 else 34 { 35 Buffer = NULL; 36 } 37 RtlFillMemory(&IoStatus, sizeof(IoStatus), 0x55); 38 _SEH2_TRY 39 { 40 Status = ZwQueryInformationFile(FileHandle, 41 &IoStatus, 42 Buffer, 43 *Length, 44 FileInformationClass); 45 } 46 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 47 { 48 Status = _SEH2_GetExceptionCode(); 49 ok(0, "Exception %lx querying class %d with length %Iu\n", 50 Status, FileInformationClass, *Length); 51 } 52 _SEH2_END; 53 if (Status == STATUS_PENDING) 54 { 55 Status = ZwWaitForSingleObject(FileHandle, FALSE, NULL); 56 ok_eq_hex(Status, STATUS_SUCCESS); 57 Status = IoStatus.Status; 58 } 59 60 *Length = IoStatus.Information; 61 if (NT_SUCCESS(Status)) 62 { 63 *Info = Buffer; 64 } 65 else if (Buffer) 66 { 67 KmtFreeGuarded(Buffer); 68 } 69 return Status; 70 } 71 72 static 73 VOID 74 TestAllInformation(VOID) 75 { 76 NTSTATUS Status; 77 UNICODE_STRING FileName = RTL_CONSTANT_STRING(L"\\SystemRoot\\system32\\ntoskrnl.exe"); 78 UNICODE_STRING Ntoskrnl = RTL_CONSTANT_STRING(L"ntoskrnl.exe"); 79 OBJECT_ATTRIBUTES ObjectAttributes; 80 HANDLE FileHandle; 81 IO_STATUS_BLOCK IoStatus; 82 PFILE_ALL_INFORMATION FileAllInfo; 83 SIZE_T Length; 84 ULONG NameLength; 85 PWCHAR Name; 86 UNICODE_STRING NamePart; 87 88 InitializeObjectAttributes(&ObjectAttributes, 89 &FileName, 90 OBJ_KERNEL_HANDLE | OBJ_CASE_INSENSITIVE, 91 NULL, 92 NULL); 93 Status = ZwOpenFile(&FileHandle, 94 SYNCHRONIZE | FILE_READ_ATTRIBUTES, 95 &ObjectAttributes, 96 &IoStatus, 97 FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, 98 FILE_NON_DIRECTORY_FILE); 99 if (Status == STATUS_PENDING) 100 { 101 Status = ZwWaitForSingleObject(FileHandle, FALSE, NULL); 102 ok_eq_hex(Status, STATUS_SUCCESS); 103 Status = IoStatus.Status; 104 } 105 ok_eq_hex(Status, STATUS_SUCCESS); 106 if (skip(NT_SUCCESS(Status), "No file handle, %lx\n", Status)) 107 return; 108 109 /* NtQueryInformationFile doesn't do length checks for kernel callers in a free build */ 110 if (KmtIsCheckedBuild) 111 { 112 /* Zero length */ 113 Length = 0; 114 Status = QueryFileInfo(FileHandle, (PVOID*)&FileAllInfo, &Length, FileAllInformation); 115 ok_eq_hex(Status, STATUS_INFO_LENGTH_MISMATCH); 116 ok_eq_size(Length, (ULONG_PTR)0x5555555555555555); 117 if (FileAllInfo) 118 KmtFreeGuarded(FileAllInfo); 119 120 /* One less than the minimum */ 121 Length = FIELD_OFFSET(FILE_ALL_INFORMATION, NameInformation.FileName) - 1; 122 Status = QueryFileInfo(FileHandle, (PVOID*)&FileAllInfo, &Length, FileAllInformation); 123 ok_eq_hex(Status, STATUS_INFO_LENGTH_MISMATCH); 124 ok_eq_size(Length, (ULONG_PTR)0x5555555555555555); 125 if (FileAllInfo) 126 KmtFreeGuarded(FileAllInfo); 127 128 /* No space for the name -- fastfat handles this gracefully, ntfs doesn't. 129 * But the Io manager makes it fail on checked builds, so it's 130 * technically illegal 131 */ 132 Length = FIELD_OFFSET(FILE_ALL_INFORMATION, NameInformation.FileName); 133 Status = QueryFileInfo(FileHandle, (PVOID*)&FileAllInfo, &Length, FileAllInformation); 134 ok_eq_hex(Status, STATUS_INFO_LENGTH_MISMATCH); 135 ok_eq_size(Length, (ULONG_PTR)0x5555555555555555); 136 if (FileAllInfo) 137 KmtFreeGuarded(FileAllInfo); 138 } 139 140 /* The minimum allowed */ 141 Length = sizeof(FILE_ALL_INFORMATION); 142 Status = QueryFileInfo(FileHandle, (PVOID*)&FileAllInfo, &Length, FileAllInformation); 143 ok_eq_hex(Status, STATUS_BUFFER_OVERFLOW); 144 ok_eq_size(Length, sizeof(FILE_ALL_INFORMATION)); 145 if (FileAllInfo) 146 KmtFreeGuarded(FileAllInfo); 147 148 /* Plenty of space -- determine NameLength and copy the name */ 149 Length = FIELD_OFFSET(FILE_ALL_INFORMATION, NameInformation.FileName) + MAX_PATH * sizeof(WCHAR); 150 Status = QueryFileInfo(FileHandle, (PVOID*)&FileAllInfo, &Length, FileAllInformation); 151 ok_eq_hex(Status, STATUS_SUCCESS); 152 if (skip(NT_SUCCESS(Status) && FileAllInfo != NULL, "No info\n")) 153 { 154 goto NoInfo; 155 } 156 157 NameLength = FileAllInfo->NameInformation.FileNameLength; 158 ok_eq_size(Length, FIELD_OFFSET(FILE_ALL_INFORMATION, NameInformation.FileName) + NameLength); 159 Name = ExAllocatePoolWithTag(PagedPool, NameLength + sizeof(UNICODE_NULL), 'sFmK'); 160 if (!skip(Name != NULL, "Could not allocate %lu bytes\n", NameLength + (ULONG)sizeof(UNICODE_NULL))) 161 { 162 RtlCopyMemory(Name, 163 FileAllInfo->NameInformation.FileName, 164 NameLength); 165 Name[NameLength / sizeof(WCHAR)] = UNICODE_NULL; 166 ok(Name[0] == L'\\', "Name is %ls, expected first char to be \\\n", Name); 167 ok(NameLength >= Ntoskrnl.Length + sizeof(WCHAR), "NameLength %lu too short\n", NameLength); 168 if (NameLength >= Ntoskrnl.Length) 169 { 170 NamePart.Buffer = Name + (NameLength - Ntoskrnl.Length) / sizeof(WCHAR); 171 NamePart.Length = Ntoskrnl.Length; 172 NamePart.MaximumLength = NamePart.Length; 173 ok(RtlEqualUnicodeString(&NamePart, &Ntoskrnl, TRUE), 174 "Name ends in '%wZ', expected %wZ\n", &NamePart, &Ntoskrnl); 175 } 176 ExFreePoolWithTag(Name, 'sFmK'); 177 } 178 ok(FileAllInfo->NameInformation.FileName[NameLength / sizeof(WCHAR)] == 0xdddd, 179 "Char past FileName is %x\n", 180 FileAllInfo->NameInformation.FileName[NameLength / sizeof(WCHAR)]); 181 if (FileAllInfo) 182 KmtFreeGuarded(FileAllInfo); 183 184 /* One char less than needed */ 185 Length = FIELD_OFFSET(FILE_ALL_INFORMATION, NameInformation.FileName) + NameLength - sizeof(WCHAR); 186 Status = QueryFileInfo(FileHandle, (PVOID*)&FileAllInfo, &Length, FileAllInformation); 187 ok_eq_hex(Status, STATUS_BUFFER_OVERFLOW); 188 ok_eq_size(Length, FIELD_OFFSET(FILE_ALL_INFORMATION, NameInformation.FileName) + NameLength - sizeof(WCHAR)); 189 if (FileAllInfo) 190 KmtFreeGuarded(FileAllInfo); 191 192 /* One byte less than needed */ 193 Length = FIELD_OFFSET(FILE_ALL_INFORMATION, NameInformation.FileName) + NameLength - 1; 194 Status = QueryFileInfo(FileHandle, (PVOID*)&FileAllInfo, &Length, FileAllInformation); 195 ok_eq_hex(Status, STATUS_BUFFER_OVERFLOW); 196 ok_eq_size(Length, FIELD_OFFSET(FILE_ALL_INFORMATION, NameInformation.FileName) + NameLength - 1); 197 if (FileAllInfo) 198 KmtFreeGuarded(FileAllInfo); 199 200 /* Exactly the required size */ 201 Length = FIELD_OFFSET(FILE_ALL_INFORMATION, NameInformation.FileName) + NameLength; 202 Status = QueryFileInfo(FileHandle, (PVOID*)&FileAllInfo, &Length, FileAllInformation); 203 ok_eq_hex(Status, STATUS_SUCCESS); 204 ok_eq_size(Length, FIELD_OFFSET(FILE_ALL_INFORMATION, NameInformation.FileName) + NameLength); 205 if (FileAllInfo) 206 KmtFreeGuarded(FileAllInfo); 207 208 /* One byte more than needed */ 209 Length = FIELD_OFFSET(FILE_ALL_INFORMATION, NameInformation.FileName) + NameLength + 1; 210 Status = QueryFileInfo(FileHandle, (PVOID*)&FileAllInfo, &Length, FileAllInformation); 211 ok_eq_hex(Status, STATUS_SUCCESS); 212 ok_eq_size(Length, FIELD_OFFSET(FILE_ALL_INFORMATION, NameInformation.FileName) + NameLength); 213 if (FileAllInfo) 214 KmtFreeGuarded(FileAllInfo); 215 216 /* One char more than needed */ 217 Length = FIELD_OFFSET(FILE_ALL_INFORMATION, NameInformation.FileName) + NameLength + sizeof(WCHAR); 218 Status = QueryFileInfo(FileHandle, (PVOID*)&FileAllInfo, &Length, FileAllInformation); 219 ok_eq_hex(Status, STATUS_SUCCESS); 220 ok_eq_size(Length, FIELD_OFFSET(FILE_ALL_INFORMATION, NameInformation.FileName) + NameLength); 221 if (FileAllInfo) 222 KmtFreeGuarded(FileAllInfo); 223 224 PFILE_END_OF_FILE_INFORMATION FileEofInfo; 225 Length = sizeof(*FileEofInfo); 226 Status = QueryFileInfo(FileHandle, (PVOID*)&FileEofInfo, &Length, FileEndOfFileInformation); 227 // Checked build: STATUS_INVALID_INFO_CLASS, Free build: STATUS_INVALID_PARAMETER 228 ok(Status == STATUS_INVALID_PARAMETER || Status == STATUS_INVALID_INFO_CLASS, "Wrong Status = %lx\n", Status); 229 ok_eq_size(Length, (SIZE_T)0x5555555555555555ULL); 230 if (FileEofInfo) 231 KmtFreeGuarded(FileEofInfo); 232 233 NoInfo: 234 Status = ObCloseHandle(FileHandle, KernelMode); 235 ok_eq_hex(Status, STATUS_SUCCESS); 236 } 237 238 static 239 VOID 240 Substitute( 241 _Out_writes_bytes_(BufferSize) PWCHAR Buffer, 242 _In_ ULONG BufferSize, 243 _In_ PCWSTR Template, 244 _In_ PCWSTR SystemDriveName, 245 _In_ PCWSTR SystemRootName) 246 { 247 UNICODE_STRING SystemDriveTemplate = RTL_CONSTANT_STRING(L"C:"); 248 UNICODE_STRING SystemRootTemplate = RTL_CONSTANT_STRING(L"ReactOS"); 249 ULONG SystemDriveLength; 250 ULONG SystemRootLength; 251 PWCHAR Dest = Buffer; 252 UNICODE_STRING String; 253 254 SystemDriveLength = (ULONG)wcslen(SystemDriveName) * sizeof(WCHAR); 255 SystemRootLength = (ULONG)wcslen(SystemRootName) * sizeof(WCHAR); 256 257 RtlInitUnicodeString(&String, Template); 258 ASSERT(String.Length % sizeof(WCHAR) == 0); 259 while (String.Length) 260 { 261 if (RtlPrefixUnicodeString(&SystemDriveTemplate, &String, TRUE)) 262 { 263 ASSERT((Dest - Buffer) * sizeof(WCHAR) + SystemDriveLength < BufferSize); 264 RtlCopyMemory(Dest, 265 SystemDriveName, 266 SystemDriveLength); 267 Dest += SystemDriveLength / sizeof(WCHAR); 268 269 String.Buffer += SystemDriveTemplate.Length / sizeof(WCHAR); 270 String.Length -= SystemDriveTemplate.Length; 271 String.MaximumLength -= SystemDriveTemplate.Length; 272 continue; 273 } 274 275 if (RtlPrefixUnicodeString(&SystemRootTemplate, &String, TRUE)) 276 { 277 ASSERT((Dest - Buffer) * sizeof(WCHAR) + SystemRootLength < BufferSize); 278 RtlCopyMemory(Dest, 279 SystemRootName, 280 SystemRootLength); 281 Dest += SystemRootLength / sizeof(WCHAR); 282 283 String.Buffer += SystemRootTemplate.Length / sizeof(WCHAR); 284 String.Length -= SystemRootTemplate.Length; 285 String.MaximumLength -= SystemRootTemplate.Length; 286 continue; 287 } 288 289 ASSERT(Dest - Buffer < BufferSize / sizeof(WCHAR)); 290 *Dest++ = String.Buffer[0]; 291 292 String.Buffer++; 293 String.Length -= sizeof(WCHAR); 294 String.MaximumLength -= sizeof(WCHAR); 295 } 296 ASSERT(Dest - Buffer < BufferSize / sizeof(WCHAR)); 297 *Dest = UNICODE_NULL; 298 } 299 300 static 301 VOID 302 TestRelativeNames(VOID) 303 { 304 NTSTATUS Status; 305 struct 306 { 307 PCWSTR ParentPathTemplate; 308 PCWSTR RelativePathTemplate; 309 BOOLEAN IsDirectory; 310 NTSTATUS Status; 311 BOOLEAN IsDrive; 312 } Tests[] = 313 { 314 { NULL, L"C:\\", TRUE, STATUS_SUCCESS, TRUE }, 315 { NULL, L"C:\\\\", TRUE, STATUS_SUCCESS, TRUE }, 316 { NULL, L"C:\\\\\\", TRUE, STATUS_OBJECT_NAME_INVALID, TRUE }, 317 { NULL, L"C:\\ReactOS", TRUE, STATUS_SUCCESS }, 318 { NULL, L"C:\\ReactOS\\", TRUE, STATUS_SUCCESS }, 319 { NULL, L"C:\\ReactOS\\\\", TRUE, STATUS_SUCCESS }, 320 { NULL, L"C:\\ReactOS\\\\\\", TRUE, STATUS_OBJECT_NAME_INVALID }, 321 { NULL, L"C:\\\\ReactOS", TRUE, STATUS_SUCCESS }, 322 { NULL, L"C:\\\\ReactOS\\", TRUE, STATUS_SUCCESS }, 323 { NULL, L"C:\\ReactOS\\explorer.exe", FALSE, STATUS_SUCCESS }, 324 { NULL, L"C:\\ReactOS\\\\explorer.exe", FALSE, STATUS_OBJECT_NAME_INVALID }, 325 { NULL, L"C:\\ReactOS\\explorer.exe\\", FALSE, STATUS_OBJECT_NAME_INVALID }, 326 { NULL, L"C:\\ReactOS\\explorer.exe\\file", FALSE, STATUS_OBJECT_PATH_NOT_FOUND }, 327 { NULL, L"C:\\ReactOS\\explorer.exe\\\\", FALSE, STATUS_OBJECT_NAME_INVALID }, 328 /* This will never return STATUS_NOT_A_DIRECTORY. IsDirectory=TRUE is a little hacky but achieves that without special handling */ 329 { NULL, L"C:\\ReactOS\\explorer.exe\\\\\\", TRUE, STATUS_OBJECT_NAME_INVALID }, 330 { L"C:\\", L"", TRUE, STATUS_SUCCESS }, 331 { L"C:\\", L"\\", TRUE, STATUS_OBJECT_NAME_INVALID }, 332 { L"C:\\", L"ReactOS", TRUE, STATUS_SUCCESS }, 333 { L"C:\\", L"\\ReactOS", TRUE, STATUS_OBJECT_NAME_INVALID }, 334 { L"C:\\", L"ReactOS\\", TRUE, STATUS_SUCCESS }, 335 { L"C:\\", L"\\ReactOS\\", TRUE, STATUS_OBJECT_NAME_INVALID }, 336 { L"C:\\ReactOS", L"", TRUE, STATUS_SUCCESS }, 337 { L"C:\\ReactOS", L"explorer.exe", FALSE, STATUS_SUCCESS }, 338 { L"C:\\ReactOS\\explorer.exe", L"", FALSE, STATUS_SUCCESS }, 339 { L"C:\\ReactOS\\explorer.exe", L"file", FALSE, STATUS_OBJECT_PATH_NOT_FOUND }, 340 /* Let's try some nonexistent things */ 341 { NULL, L"C:\\ReactOS\\IDoNotExist", FALSE, STATUS_OBJECT_NAME_NOT_FOUND }, 342 { NULL, L"C:\\ReactOS\\IDoNotExist\\file", FALSE, STATUS_OBJECT_PATH_NOT_FOUND }, 343 { NULL, L"C:\\ReactOS\\IDoNotExist\\file?", FALSE, STATUS_OBJECT_PATH_NOT_FOUND }, 344 { NULL, L"C:\\ReactOS\\IDoNotExist\\file\\\\",TRUE,STATUS_OBJECT_PATH_NOT_FOUND }, 345 { NULL, L"C:\\ReactOS\\IDoNotExist\\file\\\\\\",TRUE,STATUS_OBJECT_PATH_NOT_FOUND }, 346 { NULL, L"C:\\ReactOS\\AmIInvalid?", FALSE, STATUS_OBJECT_NAME_INVALID }, 347 { NULL, L"C:\\ReactOS\\.", TRUE, STATUS_OBJECT_NAME_NOT_FOUND }, 348 { NULL, L"C:\\ReactOS\\..", TRUE, STATUS_OBJECT_NAME_NOT_FOUND }, 349 { NULL, L"C:\\ReactOS\\...", TRUE, STATUS_OBJECT_NAME_NOT_FOUND }, 350 { NULL, L"C:\\ReactOS\\.\\system32", TRUE, STATUS_OBJECT_PATH_NOT_FOUND }, 351 { NULL, L"C:\\ReactOS\\..\\ReactOS", TRUE, STATUS_OBJECT_PATH_NOT_FOUND }, 352 { L"C:\\", L".", TRUE, STATUS_OBJECT_NAME_NOT_FOUND }, 353 { L"C:\\", L"..", TRUE, STATUS_OBJECT_NAME_NOT_FOUND }, 354 { L"C:\\", L"...", TRUE, STATUS_OBJECT_NAME_NOT_FOUND }, 355 { L"C:\\", L".\\ReactOS", TRUE, STATUS_OBJECT_PATH_NOT_FOUND }, 356 { L"C:\\", L"..\\ReactOS", TRUE, STATUS_OBJECT_PATH_NOT_FOUND }, 357 { L"C:\\ReactOS", L".", TRUE, STATUS_OBJECT_NAME_NOT_FOUND }, 358 { L"C:\\ReactOS", L"..", TRUE, STATUS_OBJECT_NAME_NOT_FOUND }, 359 { L"C:\\ReactOS", L"...", TRUE, STATUS_OBJECT_NAME_NOT_FOUND }, 360 { L"C:\\ReactOS", L".\\system32", TRUE, STATUS_OBJECT_PATH_NOT_FOUND }, 361 { L"C:\\ReactOS", L"..\\ReactOS", TRUE, STATUS_OBJECT_PATH_NOT_FOUND }, 362 /* Volume open */ 363 { NULL, L"C:", FALSE, STATUS_SUCCESS, TRUE }, 364 { L"C:", L"", FALSE, STATUS_SUCCESS, TRUE }, 365 { L"C:", L"\\", TRUE, STATUS_OBJECT_PATH_NOT_FOUND }, 366 { L"C:", L"file", TRUE, STATUS_OBJECT_PATH_NOT_FOUND }, 367 }; 368 ULONG i; 369 OBJECT_ATTRIBUTES ObjectAttributes; 370 IO_STATUS_BLOCK IoStatus; 371 UNICODE_STRING ParentPath; 372 UNICODE_STRING RelativePath; 373 HANDLE ParentHandle; 374 HANDLE FileHandle; 375 UNICODE_STRING SystemRoot = RTL_CONSTANT_STRING(L"\\SystemRoot"); 376 HANDLE SymbolicLinkHandle = NULL; 377 WCHAR LinkNameBuffer[128]; 378 UNICODE_STRING SymbolicLinkName; 379 PWSTR SystemDriveName; 380 PWSTR SystemRootName; 381 PWCHAR Buffer = NULL; 382 BOOLEAN TrailingBackslash; 383 LARGE_INTEGER AllocationSize; 384 FILE_DISPOSITION_INFORMATION DispositionInfo; 385 386 /* Query \SystemRoot */ 387 InitializeObjectAttributes(&ObjectAttributes, 388 &SystemRoot, 389 OBJ_KERNEL_HANDLE | OBJ_CASE_INSENSITIVE, 390 NULL, 391 NULL); 392 Status = ZwOpenSymbolicLinkObject(&SymbolicLinkHandle, 393 GENERIC_READ, 394 &ObjectAttributes); 395 if (skip(NT_SUCCESS(Status), "Failed to open SystemRoot, %lx\n", Status)) 396 return; 397 398 RtlInitEmptyUnicodeString(&SymbolicLinkName, 399 LinkNameBuffer, 400 sizeof(LinkNameBuffer)); 401 Status = ZwQuerySymbolicLinkObject(SymbolicLinkHandle, 402 &SymbolicLinkName, 403 NULL); 404 ObCloseHandle(SymbolicLinkHandle, KernelMode); 405 if (skip(NT_SUCCESS(Status), "Failed to query SystemRoot, %lx\n", Status)) 406 return; 407 408 /* Split SymbolicLinkName into drive and path */ 409 SystemDriveName = SymbolicLinkName.Buffer; 410 SystemRootName = SymbolicLinkName.Buffer + SymbolicLinkName.Length / sizeof(WCHAR); 411 *SystemRootName-- = UNICODE_NULL; 412 while (*SystemRootName != L'\\') 413 { 414 ASSERT(SystemRootName > SymbolicLinkName.Buffer); 415 SystemRootName--; 416 } 417 *SystemRootName++ = UNICODE_NULL; 418 trace("System Drive: '%ls'\n", SystemDriveName); 419 trace("System Root: '%ls'\n", SystemRootName); 420 421 /* Allocate path buffer */ 422 Buffer = ExAllocatePoolWithTag(PagedPool, MAXUSHORT, 'sFmK'); 423 if (skip(Buffer != NULL, "No buffer\n")) 424 return; 425 426 /* Finally run some tests! */ 427 for (i = 0; i < RTL_NUMBER_OF(Tests); i++) 428 { 429 /* Open parent directory first */ 430 ParentHandle = NULL; 431 if (Tests[i].ParentPathTemplate) 432 { 433 Substitute(Buffer, 434 MAXUSHORT, 435 Tests[i].ParentPathTemplate, 436 SystemDriveName, 437 SystemRootName); 438 RtlInitUnicodeString(&ParentPath, Buffer); 439 InitializeObjectAttributes(&ObjectAttributes, 440 &ParentPath, 441 OBJ_KERNEL_HANDLE | OBJ_CASE_INSENSITIVE, 442 NULL, 443 NULL); 444 Status = ZwOpenFile(&ParentHandle, 445 GENERIC_READ, 446 &ObjectAttributes, 447 &IoStatus, 448 FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, 449 0); 450 ok(Status == STATUS_SUCCESS, 451 "[%lu] Status = %lx, expected STATUS_SUCCESS\n", i, Status); 452 if (skip(NT_SUCCESS(Status), "No parent handle %lu\n", i)) 453 continue; 454 } 455 456 /* Now open the relative file: */ 457 Substitute(Buffer, 458 MAXUSHORT, 459 Tests[i].RelativePathTemplate, 460 SystemDriveName, 461 SystemRootName); 462 RtlInitUnicodeString(&RelativePath, Buffer); 463 InitializeObjectAttributes(&ObjectAttributes, 464 &RelativePath, 465 OBJ_KERNEL_HANDLE | OBJ_CASE_INSENSITIVE, 466 ParentHandle, 467 NULL); 468 TrailingBackslash = FALSE; 469 if (wcslen(Buffer) && Buffer[wcslen(Buffer) - 1] == L'\\') 470 TrailingBackslash = TRUE; 471 472 /* (1) No flags */ 473 Status = ZwOpenFile(&FileHandle, 474 GENERIC_READ, 475 &ObjectAttributes, 476 &IoStatus, 477 FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, 478 0); 479 ok(Status == Tests[i].Status, 480 "[%lu] Status = %lx, expected %lx\n", i, Status, Tests[i].Status); 481 if (NT_SUCCESS(Status)) 482 ObCloseHandle(FileHandle, KernelMode); 483 484 /* (2) Directory File */ 485 Status = ZwOpenFile(&FileHandle, 486 GENERIC_READ, 487 &ObjectAttributes, 488 &IoStatus, 489 FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, 490 FILE_DIRECTORY_FILE); 491 if (Tests[i].IsDirectory || (!TrailingBackslash && !NT_SUCCESS(Tests[i].Status))) 492 ok(Status == Tests[i].Status, 493 "[%lu] Status = %lx, expected %lx\n", i, Status, Tests[i].Status); 494 else 495 ok(Status == STATUS_NOT_A_DIRECTORY, 496 "[%lu] Status = %lx, expected STATUS_NOT_A_DIRECTORY\n", i, Status); 497 if (NT_SUCCESS(Status)) 498 ObCloseHandle(FileHandle, KernelMode); 499 500 /* (3) Non-Directory File */ 501 Status = ZwOpenFile(&FileHandle, 502 GENERIC_READ, 503 &ObjectAttributes, 504 &IoStatus, 505 FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, 506 FILE_NON_DIRECTORY_FILE); 507 if (Tests[i].IsDirectory && NT_SUCCESS(Tests[i].Status)) 508 ok(Status == STATUS_FILE_IS_A_DIRECTORY, 509 "[%lu] Status = %lx, expected STATUS_FILE_IS_A_DIRECTORY\n", i, Status); 510 else 511 ok(Status == Tests[i].Status, 512 "[%lu] Status = %lx, expected %lx\n", i, Status, Tests[i].Status); 513 if (NT_SUCCESS(Status)) 514 ObCloseHandle(FileHandle, KernelMode); 515 516 /* (4) Directory + Non-Directory */ 517 Status = ZwOpenFile(&FileHandle, 518 GENERIC_READ, 519 &ObjectAttributes, 520 &IoStatus, 521 FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, 522 FILE_DIRECTORY_FILE | FILE_NON_DIRECTORY_FILE); 523 if (Tests[i].Status == STATUS_OBJECT_NAME_INVALID && Tests[i].IsDrive) 524 ok(Status == STATUS_OBJECT_NAME_INVALID, 525 "[%lu] Status = %lx, expected STATUS_OBJECT_NAME_INVALID\n", i, Status); 526 else 527 ok(Status == STATUS_INVALID_PARAMETER, 528 "[%lu] Status = %lx, expected STATUS_INVALID_PARAMETER\n", i, Status); 529 if (NT_SUCCESS(Status)) 530 ObCloseHandle(FileHandle, KernelMode); 531 532 /* (5) Try to create it */ 533 AllocationSize.QuadPart = 0; 534 Status = ZwCreateFile(&FileHandle, 535 GENERIC_READ | DELETE, 536 &ObjectAttributes, 537 &IoStatus, 538 &AllocationSize, 539 FILE_ATTRIBUTE_NORMAL, 540 FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, 541 FILE_CREATE, 542 0, 543 NULL, 544 0); 545 if (Tests[i].Status == STATUS_OBJECT_NAME_NOT_FOUND) 546 ok(Status == STATUS_SUCCESS, 547 "[%lu] Status = %lx, expected STATUS_SUCCESS\n", i, Status); 548 else if (Tests[i].Status == STATUS_OBJECT_NAME_INVALID && Tests[i].IsDrive) 549 ok(Status == STATUS_OBJECT_NAME_INVALID, 550 "[%lu] Status = %lx, expected STATUS_OBJECT_NAME_INVALID\n", i, Status); 551 else if (Tests[i].IsDrive) 552 ok(Status == STATUS_ACCESS_DENIED, 553 "[%lu] Status = %lx, expected STATUS_ACCESS_DENIED\n", i, Status); 554 else if (Tests[i].Status == STATUS_SUCCESS) 555 ok(Status == STATUS_OBJECT_NAME_COLLISION, 556 "[%lu] Status = %lx, expected STATUS_OBJECT_NAME_COLLISION\n", i, Status); 557 else 558 ok(Status == Tests[i].Status, 559 "[%lu] Status = %lx, expected %lx; %ls -- %ls\n", i, Status, Tests[i].Status, Tests[i].ParentPathTemplate, Tests[i].RelativePathTemplate); 560 if (NT_SUCCESS(Status)) 561 { 562 if (IoStatus.Information == FILE_CREATED) 563 { 564 DispositionInfo.DeleteFile = TRUE; 565 Status = ZwSetInformationFile(FileHandle, 566 &IoStatus, 567 &DispositionInfo, 568 sizeof(DispositionInfo), 569 FileDispositionInformation); 570 ok(Status == STATUS_SUCCESS, 571 "[%lu] Status = %lx, expected STATUS_SUCCESS\n", i, Status); 572 } 573 ObCloseHandle(FileHandle, KernelMode); 574 } 575 576 /* And close */ 577 ObCloseHandle(ParentHandle, KernelMode); 578 } 579 580 ExFreePoolWithTag(Buffer, 'sFmK'); 581 } 582 583 static 584 VOID 585 TestSharedCacheMap(VOID) 586 { 587 NTSTATUS Status; 588 struct 589 { 590 PCWSTR ParentPath; 591 PCWSTR RelativePath; 592 } Tests[] = 593 { 594 { 0, L"\\SystemRoot\\system32\\drivers\\etc\\hosts" }, 595 { L"\\SystemRoot", L"system32\\drivers\\etc\\hosts" }, 596 { L"\\SystemRoot\\system32", L"drivers\\etc\\hosts" }, 597 { L"\\SystemRoot\\system32\\drivers", L"etc\\hosts" }, 598 { L"\\SystemRoot\\system32\\drivers\\etc", L"hosts" }, 599 }; 600 OBJECT_ATTRIBUTES ObjectAttributes; 601 IO_STATUS_BLOCK IoStatus; 602 UNICODE_STRING ParentPath; 603 UNICODE_STRING RelativePath; 604 HANDLE ParentHandle[RTL_NUMBER_OF(Tests)] = { NULL }; 605 HANDLE FileHandle[RTL_NUMBER_OF(Tests)] = { NULL }; 606 PFILE_OBJECT FileObject[RTL_NUMBER_OF(Tests)] = { NULL }; 607 PFILE_OBJECT SystemRootObject = NULL; 608 UCHAR Buffer[32]; 609 HANDLE EventHandle; 610 LARGE_INTEGER FileOffset; 611 ULONG i; 612 613 /* We need an event for ZwReadFile */ 614 InitializeObjectAttributes(&ObjectAttributes, 615 NULL, 616 OBJ_KERNEL_HANDLE, 617 NULL, 618 NULL); 619 Status = ZwCreateEvent(&EventHandle, 620 SYNCHRONIZE, 621 &ObjectAttributes, 622 NotificationEvent, 623 FALSE); 624 if (skip(NT_SUCCESS(Status), "No event\n")) 625 goto Cleanup; 626 627 /* Open all test files and get their FILE_OBJECT pointers */ 628 for (i = 0; i < RTL_NUMBER_OF(Tests); i++) 629 { 630 if (Tests[i].ParentPath) 631 { 632 RtlInitUnicodeString(&ParentPath, Tests[i].ParentPath); 633 InitializeObjectAttributes(&ObjectAttributes, 634 &ParentPath, 635 OBJ_KERNEL_HANDLE | OBJ_CASE_INSENSITIVE, 636 NULL, 637 NULL); 638 Status = ZwOpenFile(&ParentHandle[i], 639 GENERIC_READ, 640 &ObjectAttributes, 641 &IoStatus, 642 FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, 643 0); 644 ok_eq_hex(Status, STATUS_SUCCESS); 645 if (skip(NT_SUCCESS(Status), "No parent handle %lu\n", i)) 646 goto Cleanup; 647 } 648 649 RtlInitUnicodeString(&RelativePath, Tests[i].RelativePath); 650 InitializeObjectAttributes(&ObjectAttributes, 651 &RelativePath, 652 OBJ_KERNEL_HANDLE | OBJ_CASE_INSENSITIVE, 653 ParentHandle[i], 654 NULL); 655 Status = ZwOpenFile(&FileHandle[i], 656 FILE_ALL_ACCESS, 657 &ObjectAttributes, 658 &IoStatus, 659 FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, 660 0); 661 ok_eq_hex(Status, STATUS_SUCCESS); 662 if (skip(NT_SUCCESS(Status), "No file handle %lu\n", i)) 663 goto Cleanup; 664 665 Status = ObReferenceObjectByHandle(FileHandle[i], 666 FILE_ALL_ACCESS, 667 *IoFileObjectType, 668 KernelMode, 669 (PVOID*)&FileObject[i], 670 NULL); 671 ok_eq_hex(Status, STATUS_SUCCESS); 672 if (skip(NT_SUCCESS(Status), "No file object %lu\n", i)) 673 goto Cleanup; 674 } 675 676 /* Also get a file object for the SystemRoot directory */ 677 Status = ObReferenceObjectByHandle(ParentHandle[1], 678 GENERIC_READ, 679 *IoFileObjectType, 680 KernelMode, 681 (PVOID*)&SystemRootObject, 682 NULL); 683 ok_eq_hex(Status, STATUS_SUCCESS); 684 if (skip(NT_SUCCESS(Status), "No SystemRoot object\n")) 685 goto Cleanup; 686 687 /* Before read, caching is not initialized */ 688 ok_eq_pointer(SystemRootObject->SectionObjectPointer, NULL); 689 for (i = 0; i < RTL_NUMBER_OF(Tests); i++) 690 { 691 ok(FileObject[i]->SectionObjectPointer != NULL, "FileObject[%lu]->SectionObjectPointer = NULL\n", i); 692 ok(FileObject[i]->SectionObjectPointer == FileObject[0]->SectionObjectPointer, 693 "FileObject[%lu]->SectionObjectPointer = %p, expected %p\n", 694 i, FileObject[i]->SectionObjectPointer, FileObject[0]->SectionObjectPointer); 695 } 696 if (!skip(FileObject[0]->SectionObjectPointer != NULL, "No section object pointers\n")) 697 ok_eq_pointer(FileObject[0]->SectionObjectPointer->SharedCacheMap, NULL); 698 699 /* Perform a read on one handle to initialize caching */ 700 FileOffset.QuadPart = 0; 701 Status = ZwReadFile(FileHandle[0], 702 EventHandle, 703 NULL, 704 NULL, 705 &IoStatus, 706 Buffer, 707 sizeof(Buffer), 708 &FileOffset, 709 NULL); 710 if (Status == STATUS_PENDING) 711 { 712 Status = ZwWaitForSingleObject(EventHandle, FALSE, NULL); 713 ok_eq_hex(Status, STATUS_SUCCESS); 714 Status = IoStatus.Status; 715 } 716 ok_eq_hex(Status, STATUS_SUCCESS); 717 718 /* Now we see a SharedCacheMap for the file */ 719 ok_eq_pointer(SystemRootObject->SectionObjectPointer, NULL); 720 for (i = 0; i < RTL_NUMBER_OF(Tests); i++) 721 { 722 ok(FileObject[i]->SectionObjectPointer != NULL, "FileObject[%lu]->SectionObjectPointer = NULL\n", i); 723 ok(FileObject[i]->SectionObjectPointer == FileObject[0]->SectionObjectPointer, 724 "FileObject[%lu]->SectionObjectPointer = %p, expected %p\n", 725 i, FileObject[i]->SectionObjectPointer, FileObject[0]->SectionObjectPointer); 726 } 727 if (!skip(FileObject[0]->SectionObjectPointer != NULL, "No section object pointers\n")) 728 ok(FileObject[0]->SectionObjectPointer->SharedCacheMap != NULL, "SharedCacheMap is NULL\n"); 729 730 Cleanup: 731 if (SystemRootObject) 732 ObDereferenceObject(SystemRootObject); 733 if (EventHandle) 734 ObCloseHandle(EventHandle, KernelMode); 735 for (i = 0; i < RTL_NUMBER_OF(Tests); i++) 736 { 737 if (FileObject[i]) 738 ObDereferenceObject(FileObject[i]); 739 if (FileHandle[i]) 740 ObCloseHandle(FileHandle[i], KernelMode); 741 if (ParentHandle[i]) 742 ObCloseHandle(ParentHandle[i], KernelMode); 743 } 744 } 745 746 START_TEST(IoFilesystem) 747 { 748 TestAllInformation(); 749 TestRelativeNames(); 750 TestSharedCacheMap(); 751 } 752