1 /* 2 * PROJECT: ReactOS kernel-mode tests 3 * LICENSE: LGPLv2.1+ - See COPYING.LIB in the top level directory 4 * PURPOSE: Test driver for CcPinRead function 5 * PROGRAMMER: Pierre Schweitzer <pierre@reactos.org> 6 */ 7 8 #include <kmt_test.h> 9 10 #define NDEBUG 11 #include <debug.h> 12 13 #define IOCTL_START_TEST 1 14 #define IOCTL_FINISH_TEST 2 15 16 typedef struct _TEST_FCB 17 { 18 FSRTL_ADVANCED_FCB_HEADER Header; 19 SECTION_OBJECT_POINTERS SectionObjectPointers; 20 FAST_MUTEX HeaderMutex; 21 } TEST_FCB, *PTEST_FCB; 22 23 typedef struct _TEST_CONTEXT 24 { 25 PVOID Bcb; 26 PVOID Buffer; 27 ULONG Length; 28 } TEST_CONTEXT, *PTEST_CONTEXT; 29 30 static ULONG TestTestId = -1; 31 static PFILE_OBJECT TestFileObject; 32 static PDEVICE_OBJECT TestDeviceObject; 33 static KMT_IRP_HANDLER TestIrpHandler; 34 static KMT_MESSAGE_HANDLER TestMessageHandler; 35 static BOOLEAN TestWriteCalled = FALSE; 36 37 NTSTATUS 38 TestEntry( 39 _In_ PDRIVER_OBJECT DriverObject, 40 _In_ PCUNICODE_STRING RegistryPath, 41 _Out_ PCWSTR *DeviceName, 42 _Inout_ INT *Flags) 43 { 44 NTSTATUS Status = STATUS_SUCCESS; 45 46 PAGED_CODE(); 47 48 UNREFERENCED_PARAMETER(RegistryPath); 49 50 *DeviceName = L"CcPinRead"; 51 *Flags = TESTENTRY_NO_EXCLUSIVE_DEVICE | 52 TESTENTRY_BUFFERED_IO_DEVICE | 53 TESTENTRY_NO_READONLY_DEVICE; 54 55 KmtRegisterIrpHandler(IRP_MJ_READ, NULL, TestIrpHandler); 56 KmtRegisterIrpHandler(IRP_MJ_WRITE, NULL, TestIrpHandler); 57 KmtRegisterMessageHandler(0, NULL, TestMessageHandler); 58 59 60 return Status; 61 } 62 63 VOID 64 TestUnload( 65 _In_ PDRIVER_OBJECT DriverObject) 66 { 67 PAGED_CODE(); 68 } 69 70 BOOLEAN 71 NTAPI 72 AcquireForLazyWrite( 73 _In_ PVOID Context, 74 _In_ BOOLEAN Wait) 75 { 76 return TRUE; 77 } 78 79 VOID 80 NTAPI 81 ReleaseFromLazyWrite( 82 _In_ PVOID Context) 83 { 84 return; 85 } 86 87 BOOLEAN 88 NTAPI 89 AcquireForReadAhead( 90 _In_ PVOID Context, 91 _In_ BOOLEAN Wait) 92 { 93 return TRUE; 94 } 95 96 VOID 97 NTAPI 98 ReleaseFromReadAhead( 99 _In_ PVOID Context) 100 { 101 return; 102 } 103 104 static CACHE_MANAGER_CALLBACKS Callbacks = { 105 AcquireForLazyWrite, 106 ReleaseFromLazyWrite, 107 AcquireForReadAhead, 108 ReleaseFromReadAhead, 109 }; 110 111 static CC_FILE_SIZES FileSizes = { 112 RTL_CONSTANT_LARGE_INTEGER((LONGLONG)0x4000), // .AllocationSize 113 RTL_CONSTANT_LARGE_INTEGER((LONGLONG)0x4000), // .FileSize 114 RTL_CONSTANT_LARGE_INTEGER((LONGLONG)0x4000) // .ValidDataLength 115 }; 116 117 static CC_FILE_SIZES SmallFileSizes = { 118 RTL_CONSTANT_LARGE_INTEGER((LONGLONG)512), // .AllocationSize 119 RTL_CONSTANT_LARGE_INTEGER((LONGLONG)496), // .FileSize 120 RTL_CONSTANT_LARGE_INTEGER((LONGLONG)496) // .ValidDataLength 121 }; 122 123 static 124 PVOID 125 MapAndLockUserBuffer( 126 _In_ _Out_ PIRP Irp, 127 _In_ ULONG BufferLength) 128 { 129 PMDL Mdl; 130 131 if (Irp->MdlAddress == NULL) 132 { 133 Mdl = IoAllocateMdl(Irp->UserBuffer, BufferLength, FALSE, FALSE, Irp); 134 if (Mdl == NULL) 135 { 136 return NULL; 137 } 138 139 _SEH2_TRY 140 { 141 MmProbeAndLockPages(Mdl, Irp->RequestorMode, IoWriteAccess); 142 } 143 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 144 { 145 IoFreeMdl(Mdl); 146 Irp->MdlAddress = NULL; 147 _SEH2_YIELD(return NULL); 148 } 149 _SEH2_END; 150 } 151 152 return MmGetSystemAddressForMdlSafe(Irp->MdlAddress, NormalPagePriority); 153 } 154 155 #define ok_bcb(B, L, O) \ 156 { \ 157 PPUBLIC_BCB public_bcb = (B); \ 158 ok(public_bcb->NodeTypeCode == 0x2FD, "Not a BCB: %x\n", public_bcb->NodeTypeCode); \ 159 ok(public_bcb->NodeByteSize == 0, "Invalid size: %d\n", public_bcb->NodeByteSize); \ 160 ok_eq_ulong(public_bcb->MappedLength, (L)); \ 161 ok_eq_longlong(public_bcb->MappedFileOffset.QuadPart, (O)); \ 162 } 163 164 static 165 VOID 166 NTAPI 167 PinInAnotherThread(IN PVOID Context) 168 { 169 BOOLEAN Ret; 170 PULONG Buffer; 171 PVOID Bcb; 172 LARGE_INTEGER Offset; 173 PTEST_CONTEXT TestContext; 174 175 ok(TestFileObject != NULL, "Called in invalid context!\n"); 176 ok_eq_ulong(TestTestId, 3); 177 178 TestContext = Context; 179 ok(TestContext != NULL, "Called in invalid context!\n"); 180 ok(TestContext->Bcb != NULL, "Called in invalid context!\n"); 181 ok(TestContext->Buffer != NULL, "Called in invalid context!\n"); 182 ok(TestContext->Length != 0, "Called in invalid context!\n"); 183 184 Ret = FALSE; 185 Offset.QuadPart = 0x1000; 186 KmtStartSeh(); 187 Ret = CcPinRead(TestFileObject, &Offset, TestContext->Length, PIN_WAIT, &Bcb, (PVOID *)&Buffer); 188 KmtEndSeh(STATUS_SUCCESS); 189 190 if (!skip(Ret == TRUE, "CcPinRead failed\n")) 191 { 192 ok_bcb(Bcb, 12288, Offset.QuadPart); 193 ok_eq_pointer(Bcb, TestContext->Bcb); 194 ok_eq_pointer(Buffer, TestContext->Buffer); 195 196 CcUnpinData(Bcb); 197 } 198 199 KmtStartSeh(); 200 Ret = CcPinRead(TestFileObject, &Offset, TestContext->Length, PIN_WAIT | PIN_IF_BCB, &Bcb, (PVOID *)&Buffer); 201 KmtEndSeh(STATUS_SUCCESS); 202 203 if (!skip(Ret == TRUE, "CcPinRead failed\n")) 204 { 205 ok_bcb(Bcb, 12288, Offset.QuadPart); 206 ok_eq_pointer(Bcb, TestContext->Bcb); 207 ok_eq_pointer(Buffer, TestContext->Buffer); 208 209 CcUnpinData(Bcb); 210 } 211 212 KmtStartSeh(); 213 Ret = CcPinRead(TestFileObject, &Offset, TestContext->Length, PIN_EXCLUSIVE, &Bcb, (PVOID *)&Buffer); 214 KmtEndSeh(STATUS_SUCCESS); 215 216 if (!skip(Ret == TRUE, "CcPinRead failed\n")) 217 { 218 ok_bcb(Bcb, 12288, Offset.QuadPart); 219 ok_eq_pointer(Bcb, TestContext->Bcb); 220 ok_eq_pointer(Buffer, TestContext->Buffer); 221 222 CcUnpinData(Bcb); 223 } 224 225 KmtStartSeh(); 226 Ret = CcMapData(TestFileObject, &Offset, TestContext->Length, MAP_WAIT, &Bcb, (PVOID *)&Buffer); 227 KmtEndSeh(STATUS_SUCCESS); 228 229 if (!skip(Ret == TRUE, "CcMapData failed\n")) 230 { 231 ok(Bcb != TestContext->Bcb, "Returned same BCB!\n"); 232 ok_eq_pointer(Buffer, TestContext->Buffer); 233 234 CcUnpinData(Bcb); 235 } 236 237 Offset.QuadPart = 0x1500; 238 TestContext->Length -= 0x500; 239 240 KmtStartSeh(); 241 Ret = CcPinRead(TestFileObject, &Offset, TestContext->Length, PIN_WAIT | PIN_IF_BCB, &Bcb, (PVOID *)&Buffer); 242 KmtEndSeh(STATUS_SUCCESS); 243 244 if (!skip(Ret == TRUE, "CcPinRead failed\n")) 245 { 246 ok_bcb(Bcb, 12288, 4096); 247 ok_eq_pointer(Bcb, TestContext->Bcb); 248 ok_eq_pointer(Buffer, (PVOID)((ULONG_PTR)TestContext->Buffer + 0x500)); 249 250 CcUnpinData(Bcb); 251 } 252 253 KmtStartSeh(); 254 Ret = CcPinRead(TestFileObject, &Offset, TestContext->Length, PIN_WAIT, &Bcb, (PVOID *)&Buffer); 255 KmtEndSeh(STATUS_SUCCESS); 256 257 if (!skip(Ret == TRUE, "CcPinRead failed\n")) 258 { 259 ok_bcb(Bcb, 12288, 4096); 260 ok_eq_pointer(Bcb, TestContext->Bcb); 261 ok_eq_pointer(Buffer, (PVOID)((ULONG_PTR)TestContext->Buffer + 0x500)); 262 263 CcUnpinData(Bcb); 264 } 265 266 KmtStartSeh(); 267 Ret = CcPinRead(TestFileObject, &Offset, TestContext->Length, PIN_EXCLUSIVE, &Bcb, (PVOID *)&Buffer); 268 KmtEndSeh(STATUS_SUCCESS); 269 270 if (!skip(Ret == TRUE, "CcPinRead failed\n")) 271 { 272 ok_bcb(Bcb, 12288, 4096); 273 ok_eq_pointer(Bcb, TestContext->Bcb); 274 ok_eq_pointer(Buffer, (PVOID)((ULONG_PTR)TestContext->Buffer + 0x500)); 275 276 CcUnpinData(Bcb); 277 } 278 279 return; 280 } 281 282 static 283 VOID 284 NTAPI 285 PinInAnotherThreadExclusive(IN PVOID Context) 286 { 287 BOOLEAN Ret; 288 PULONG Buffer; 289 PVOID Bcb; 290 LARGE_INTEGER Offset; 291 PTEST_CONTEXT TestContext; 292 293 ok(TestFileObject != NULL, "Called in invalid context!\n"); 294 ok_eq_ulong(TestTestId, 3); 295 296 TestContext = Context; 297 ok(TestContext != NULL, "Called in invalid context!\n"); 298 ok(TestContext->Bcb != NULL, "Called in invalid context!\n"); 299 ok(TestContext->Buffer != NULL, "Called in invalid context!\n"); 300 ok(TestContext->Length != 0, "Called in invalid context!\n"); 301 302 Ret = FALSE; 303 Offset.QuadPart = 0x1000; 304 KmtStartSeh(); 305 Ret = CcPinRead(TestFileObject, &Offset, TestContext->Length, PIN_EXCLUSIVE, &Bcb, (PVOID *)&Buffer); 306 KmtEndSeh(STATUS_SUCCESS); 307 ok(Ret == FALSE, "CcPinRead succeed\n"); 308 309 if (Ret) 310 { 311 CcUnpinData(Bcb); 312 } 313 314 KmtStartSeh(); 315 Ret = CcMapData(TestFileObject, &Offset, TestContext->Length, 0, &Bcb, (PVOID *)&Buffer); 316 KmtEndSeh(STATUS_SUCCESS); 317 318 if (!skip(Ret == TRUE, "CcMapData failed\n")) 319 { 320 ok(Bcb != TestContext->Bcb, "Returned same BCB!\n"); 321 ok_eq_pointer(Buffer, TestContext->Buffer); 322 323 CcUnpinData(Bcb); 324 } 325 326 Offset.QuadPart = 0x1500; 327 TestContext->Length -= 0x500; 328 329 KmtStartSeh(); 330 Ret = CcPinRead(TestFileObject, &Offset, TestContext->Length, PIN_IF_BCB, &Bcb, (PVOID *)&Buffer); 331 KmtEndSeh(STATUS_SUCCESS); 332 ok(Ret == FALSE, "CcPinRead succeed\n"); 333 334 if (Ret) 335 { 336 CcUnpinData(Bcb); 337 } 338 339 KmtStartSeh(); 340 Ret = CcPinRead(TestFileObject, &Offset, TestContext->Length, 0, &Bcb, (PVOID *)&Buffer); 341 KmtEndSeh(STATUS_SUCCESS); 342 ok(Ret == FALSE, "CcPinRead succeed\n"); 343 344 if (Ret) 345 { 346 CcUnpinData(Bcb); 347 } 348 349 KmtStartSeh(); 350 Ret = CcMapData(TestFileObject, &Offset, TestContext->Length, 0, &Bcb, (PVOID *)&Buffer); 351 KmtEndSeh(STATUS_SUCCESS); 352 353 if (!skip(Ret == TRUE, "CcMapData failed\n")) 354 { 355 ok(Bcb != TestContext->Bcb, "Returned same BCB!\n"); 356 ok_eq_pointer(Buffer, (PVOID)((ULONG_PTR)TestContext->Buffer + 0x500)); 357 358 CcUnpinData(Bcb); 359 } 360 361 return; 362 } 363 364 static 365 VOID 366 PerformTest( 367 ULONG TestId, 368 PDEVICE_OBJECT DeviceObject) 369 { 370 PVOID Bcb; 371 BOOLEAN Ret; 372 PULONG Buffer; 373 PTEST_FCB Fcb; 374 LARGE_INTEGER Offset; 375 376 ok_eq_pointer(TestFileObject, NULL); 377 ok_eq_pointer(TestDeviceObject, NULL); 378 ok_eq_ulong(TestTestId, -1); 379 380 TestDeviceObject = DeviceObject; 381 TestTestId = TestId; 382 TestFileObject = IoCreateStreamFileObject(NULL, DeviceObject); 383 if (!skip(TestFileObject != NULL, "Failed to allocate FO\n")) 384 { 385 Fcb = ExAllocatePool(NonPagedPool, sizeof(TEST_FCB)); 386 if (!skip(Fcb != NULL, "ExAllocatePool failed\n")) 387 { 388 BOOLEAN PinAccess = (TestId != 4); 389 390 RtlZeroMemory(Fcb, sizeof(TEST_FCB)); 391 ExInitializeFastMutex(&Fcb->HeaderMutex); 392 FsRtlSetupAdvancedHeader(&Fcb->Header, &Fcb->HeaderMutex); 393 394 TestFileObject->FsContext = Fcb; 395 TestFileObject->SectionObjectPointer = &Fcb->SectionObjectPointers; 396 397 KmtStartSeh(); 398 if (TestId < 6) 399 { 400 CcInitializeCacheMap(TestFileObject, &FileSizes, PinAccess, &Callbacks, NULL); 401 } 402 else 403 { 404 CcInitializeCacheMap(TestFileObject, &SmallFileSizes, PinAccess, &Callbacks, NULL); 405 } 406 KmtEndSeh(STATUS_SUCCESS); 407 408 if (!skip(CcIsFileCached(TestFileObject) == TRUE, "CcInitializeCacheMap failed\n")) 409 { 410 if (TestId < 3) 411 { 412 Ret = FALSE; 413 Offset.QuadPart = TestId * 0x1000; 414 KmtStartSeh(); 415 Ret = CcPinRead(TestFileObject, &Offset, FileSizes.FileSize.QuadPart - Offset.QuadPart, PIN_WAIT, &Bcb, (PVOID *)&Buffer); 416 KmtEndSeh(STATUS_SUCCESS); 417 418 if (!skip(Ret == TRUE, "CcPinRead failed\n")) 419 { 420 ok_bcb(Bcb, ((4 - TestId) * 4096), Offset.QuadPart); 421 ok_eq_ulong(Buffer[(0x3000 - TestId * 0x1000) / sizeof(ULONG)], 0xDEADBABE); 422 423 CcUnpinData(Bcb); 424 } 425 } 426 else if (TestId == 3) 427 { 428 PTEST_CONTEXT TestContext; 429 430 TestContext = ExAllocatePool(NonPagedPool, sizeof(TEST_CONTEXT)); 431 if (!skip(TestContext != NULL, "ExAllocatePool failed\n")) 432 { 433 Ret = FALSE; 434 Offset.QuadPart = 0x1000; 435 436 /* Try enforce BCB first */ 437 KmtStartSeh(); 438 Ret = CcPinRead(TestFileObject, &Offset, FileSizes.FileSize.QuadPart - Offset.QuadPart, PIN_WAIT | PIN_IF_BCB, &Bcb, (PVOID *)&Buffer); 439 KmtEndSeh(STATUS_SUCCESS); 440 ok(Ret == FALSE, "CcPinRead succeed\n"); 441 if (Ret) 442 { 443 CcUnpinData(Bcb); 444 } 445 446 KmtStartSeh(); 447 Ret = CcPinRead(TestFileObject, &Offset, FileSizes.FileSize.QuadPart - Offset.QuadPart, PIN_WAIT, &TestContext->Bcb, &TestContext->Buffer); 448 KmtEndSeh(STATUS_SUCCESS); 449 450 if (!skip(Ret == TRUE, "CcPinRead failed\n")) 451 { 452 PKTHREAD ThreadHandle; 453 454 ok_bcb(TestContext->Bcb, 12288, Offset.QuadPart); 455 456 #ifdef _X86_ 457 /* FIXME: Should be fixed, will fail under certains conditions */ 458 ok(TestContext->Buffer > (PVOID)0xC1000000 && TestContext->Buffer < (PVOID)0xDCFFFFFF, 459 "Buffer %p not mapped in system space\n", TestContext->Buffer); 460 #else 461 #ifdef _M_AMD64 462 ok(TestContext->Buffer > (PVOID)0xFFFFF98000000000 && TestContext->Buffer < (PVOID)0xFFFFFA8000000000, 463 "Buffer %p not mapped in system space\n", TestContext->Buffer); 464 #else 465 skip(FALSE, "System space mapping not defined\n"); 466 #endif 467 #endif 468 TestContext->Length = FileSizes.FileSize.QuadPart - Offset.QuadPart; 469 ThreadHandle = KmtStartThread(PinInAnotherThread, TestContext); 470 KmtFinishThread(ThreadHandle, NULL); 471 472 TestContext->Length = FileSizes.FileSize.QuadPart - 2 * Offset.QuadPart; 473 ThreadHandle = KmtStartThread(PinInAnotherThread, TestContext); 474 KmtFinishThread(ThreadHandle, NULL); 475 476 CcUnpinData(TestContext->Bcb); 477 } 478 479 KmtStartSeh(); 480 Ret = CcPinRead(TestFileObject, &Offset, FileSizes.FileSize.QuadPart - Offset.QuadPart, PIN_WAIT | PIN_EXCLUSIVE, &TestContext->Bcb, &TestContext->Buffer); 481 KmtEndSeh(STATUS_SUCCESS); 482 483 if (!skip(Ret == TRUE, "CcPinRead failed\n")) 484 { 485 PKTHREAD ThreadHandle; 486 487 ok_bcb(TestContext->Bcb, 12288, Offset.QuadPart); 488 489 TestContext->Length = FileSizes.FileSize.QuadPart - Offset.QuadPart; 490 ThreadHandle = KmtStartThread(PinInAnotherThreadExclusive, TestContext); 491 KmtFinishThread(ThreadHandle, NULL); 492 493 CcUnpinData(TestContext->Bcb); 494 } 495 496 ExFreePool(TestContext); 497 } 498 } 499 else if (TestId == 4) 500 { 501 Ret = FALSE; 502 Offset.QuadPart = 0x1000; 503 KmtStartSeh(); 504 Ret = CcPinRead(TestFileObject, &Offset, FileSizes.FileSize.QuadPart - Offset.QuadPart, PIN_WAIT, &Bcb, (PVOID *)&Buffer); 505 KmtEndSeh(STATUS_SUCCESS); 506 507 if (!skip(Ret == TRUE, "CcPinRead failed\n")) 508 { 509 ok_bcb(Bcb, 12288, Offset.QuadPart); 510 ok_eq_ulong(Buffer[0x2000 / sizeof(ULONG)], 0); 511 512 CcUnpinData(Bcb); 513 } 514 } 515 else if (TestId == 5) 516 { 517 /* Pin after EOF */ 518 Ret = FALSE; 519 Offset.QuadPart = FileSizes.FileSize.QuadPart + 0x1000; 520 521 KmtStartSeh(); 522 Ret = CcPinRead(TestFileObject, &Offset, 0x1000, 0, &Bcb, (PVOID *)&Buffer); 523 KmtEndSeh(STATUS_SUCCESS); 524 ok(Ret == FALSE, "CcPinRead succeed\n"); 525 526 if (Ret) 527 { 528 CcUnpinData(Bcb); 529 } 530 531 /* Pin a VACB after EOF */ 532 Ret = FALSE; 533 Offset.QuadPart = FileSizes.FileSize.QuadPart + 0x1000 + VACB_MAPPING_GRANULARITY; 534 535 KmtStartSeh(); 536 Ret = CcPinRead(TestFileObject, &Offset, 0x1000, 0, &Bcb, (PVOID *)&Buffer); 537 KmtEndSeh(STATUS_ACCESS_VIOLATION); 538 ok(Ret == FALSE, "CcPinRead succeed\n"); 539 540 if (Ret) 541 { 542 CcUnpinData(Bcb); 543 } 544 545 /* Pin more than a VACB */ 546 Ret = FALSE; 547 Offset.QuadPart = 0x0; 548 549 KmtStartSeh(); 550 Ret = CcPinRead(TestFileObject, &Offset, 0x1000 + VACB_MAPPING_GRANULARITY, 0, &Bcb, (PVOID *)&Buffer); 551 KmtEndSeh(STATUS_SUCCESS); 552 ok(Ret == FALSE, "CcPinRead succeed\n"); 553 554 if (Ret) 555 { 556 CcUnpinData(Bcb); 557 } 558 } 559 else if (TestId == 6) 560 { 561 Ret = FALSE; 562 Offset.QuadPart = 0; 563 564 KmtStartSeh(); 565 Ret = CcPinRead(TestFileObject, &Offset, FileSizes.FileSize.QuadPart, PIN_WAIT, &Bcb, (PVOID *)&Buffer); 566 KmtEndSeh(STATUS_SUCCESS); 567 568 if (!skip(Ret == TRUE, "CcPinRead failed\n")) 569 { 570 ok_bcb(Bcb, PAGE_SIZE * 4, Offset.QuadPart); 571 RtlFillMemory(Buffer, 0xbd, FileSizes.FileSize.LowPart); 572 CcSetDirtyPinnedData(Bcb, NULL); 573 574 CcUnpinData(Bcb); 575 } 576 } 577 } 578 } 579 } 580 } 581 582 583 static 584 VOID 585 CleanupTest( 586 ULONG TestId, 587 PDEVICE_OBJECT DeviceObject) 588 { 589 LARGE_INTEGER Zero = RTL_CONSTANT_LARGE_INTEGER(0LL); 590 CACHE_UNINITIALIZE_EVENT CacheUninitEvent; 591 592 ok_eq_pointer(TestDeviceObject, DeviceObject); 593 ok_eq_ulong(TestTestId, TestId); 594 595 if (!skip(TestFileObject != NULL, "No test FO\n")) 596 { 597 if (CcIsFileCached(TestFileObject)) 598 { 599 KeInitializeEvent(&CacheUninitEvent.Event, NotificationEvent, FALSE); 600 CcUninitializeCacheMap(TestFileObject, &Zero, &CacheUninitEvent); 601 KeWaitForSingleObject(&CacheUninitEvent.Event, Executive, KernelMode, FALSE, NULL); 602 } 603 604 if (TestFileObject->FsContext != NULL) 605 { 606 ExFreePool(TestFileObject->FsContext); 607 TestFileObject->FsContext = NULL; 608 TestFileObject->SectionObjectPointer = NULL; 609 } 610 611 if (TestTestId == 6) 612 { 613 ok_bool_true(TestWriteCalled, "Write was not called!\n"); 614 } 615 else 616 { 617 ok_bool_false(TestWriteCalled, "Write was unexpectedly called\n"); 618 } 619 620 ObDereferenceObject(TestFileObject); 621 } 622 623 TestFileObject = NULL; 624 TestDeviceObject = NULL; 625 TestTestId = -1; 626 TestWriteCalled = FALSE; 627 } 628 629 630 static 631 NTSTATUS 632 TestMessageHandler( 633 _In_ PDEVICE_OBJECT DeviceObject, 634 _In_ ULONG ControlCode, 635 _In_opt_ PVOID Buffer, 636 _In_ SIZE_T InLength, 637 _Inout_ PSIZE_T OutLength) 638 { 639 NTSTATUS Status = STATUS_SUCCESS; 640 641 FsRtlEnterFileSystem(); 642 643 switch (ControlCode) 644 { 645 case IOCTL_START_TEST: 646 ok_eq_ulong((ULONG)InLength, sizeof(ULONG)); 647 PerformTest(*(PULONG)Buffer, DeviceObject); 648 break; 649 650 case IOCTL_FINISH_TEST: 651 ok_eq_ulong((ULONG)InLength, sizeof(ULONG)); 652 CleanupTest(*(PULONG)Buffer, DeviceObject); 653 break; 654 655 default: 656 Status = STATUS_NOT_IMPLEMENTED; 657 break; 658 } 659 660 FsRtlExitFileSystem(); 661 662 return Status; 663 } 664 665 static 666 NTSTATUS 667 TestIrpHandler( 668 _In_ PDEVICE_OBJECT DeviceObject, 669 _In_ PIRP Irp, 670 _In_ PIO_STACK_LOCATION IoStack) 671 { 672 NTSTATUS Status; 673 674 PAGED_CODE(); 675 676 DPRINT("IRP %x/%x\n", IoStack->MajorFunction, IoStack->MinorFunction); 677 ASSERT(IoStack->MajorFunction == IRP_MJ_READ || 678 IoStack->MajorFunction == IRP_MJ_WRITE); 679 680 FsRtlEnterFileSystem(); 681 682 Status = STATUS_NOT_SUPPORTED; 683 Irp->IoStatus.Information = 0; 684 685 if (IoStack->MajorFunction == IRP_MJ_READ) 686 { 687 PMDL Mdl; 688 ULONG Length; 689 PVOID Buffer; 690 LARGE_INTEGER Offset; 691 692 Offset = IoStack->Parameters.Read.ByteOffset; 693 Length = IoStack->Parameters.Read.Length; 694 695 ok_eq_pointer(DeviceObject, TestDeviceObject); 696 ok_eq_pointer(IoStack->FileObject, TestFileObject); 697 698 ok(FlagOn(Irp->Flags, IRP_NOCACHE), "Not coming from Cc\n"); 699 700 ok_irql(APC_LEVEL); 701 ok((Offset.QuadPart % PAGE_SIZE == 0 || Offset.QuadPart == 0), "Offset is not aligned: %I64i\n", Offset.QuadPart); 702 ok(Length % PAGE_SIZE == 0, "Length is not aligned: %I64i\n", Length); 703 704 ok(Irp->AssociatedIrp.SystemBuffer == NULL, "A SystemBuffer was allocated!\n"); 705 Buffer = MapAndLockUserBuffer(Irp, Length); 706 ok(Buffer != NULL, "Null pointer!\n"); 707 RtlFillMemory(Buffer, Length, 0xBA); 708 709 Status = STATUS_SUCCESS; 710 if (Offset.QuadPart <= 0x3000 && Offset.QuadPart + Length > 0x3000) 711 { 712 *(PULONG)((ULONG_PTR)Buffer + (ULONG_PTR)(0x3000 - Offset.QuadPart)) = 0xDEADBABE; 713 } 714 715 Mdl = Irp->MdlAddress; 716 ok(Mdl != NULL, "Null pointer for MDL!\n"); 717 ok((Mdl->MdlFlags & MDL_PAGES_LOCKED) != 0, "MDL not locked\n"); 718 ok((Mdl->MdlFlags & MDL_SOURCE_IS_NONPAGED_POOL) == 0, "MDL from non paged\n"); 719 ok((Mdl->MdlFlags & MDL_IO_PAGE_READ) != 0, "Non paging IO\n"); 720 ok((Irp->Flags & IRP_PAGING_IO) != 0, "Non paging IO\n"); 721 722 Irp->IoStatus.Information = Length; 723 } 724 else if (IoStack->MajorFunction == IRP_MJ_WRITE) 725 { 726 PMDL Mdl; 727 ULONG Length; 728 PVOID Buffer; 729 LARGE_INTEGER Offset; 730 731 Offset = IoStack->Parameters.Write.ByteOffset; 732 Length = IoStack->Parameters.Write.Length; 733 734 ok(TestTestId == 6, "Unexpected test id: %d\n", TestTestId); 735 ok_eq_pointer(DeviceObject, TestDeviceObject); 736 ok_eq_pointer(IoStack->FileObject, TestFileObject); 737 738 ok(FlagOn(Irp->Flags, IRP_NOCACHE), "Not coming from Cc\n"); 739 740 ok_irql(PASSIVE_LEVEL); 741 ok(Offset.QuadPart == 0, "Offset is not null: %I64i\n", Offset.QuadPart); 742 ok(Length % PAGE_SIZE == 0, "Length is not aligned: %I64i\n", Length); 743 ok(Length == PAGE_SIZE * 4, "Length is not MappedLength-sized: %I64i\n", Length); 744 745 Buffer = MapAndLockUserBuffer(Irp, Length); 746 ok(Buffer != NULL, "Null pointer!\n"); 747 748 Mdl = Irp->MdlAddress; 749 ok(Mdl != NULL, "Null pointer for MDL!\n"); 750 ok((Mdl->MdlFlags & MDL_PAGES_LOCKED) != 0, "MDL not locked\n"); 751 ok((Mdl->MdlFlags & MDL_SOURCE_IS_NONPAGED_POOL) == 0, "MDL from non paged\n"); 752 ok((Irp->Flags & IRP_PAGING_IO) != 0, "Non paging IO\n"); 753 754 ok_bool_false(TestWriteCalled, "Write has been unexpectedly called twice!\n"); 755 TestWriteCalled = TRUE; 756 757 Status = STATUS_SUCCESS; 758 Irp->IoStatus.Information = Length; 759 } 760 761 if (Status == STATUS_PENDING) 762 { 763 IoMarkIrpPending(Irp); 764 IoCompleteRequest(Irp, IO_NO_INCREMENT); 765 Status = STATUS_PENDING; 766 } 767 else 768 { 769 Irp->IoStatus.Status = Status; 770 IoCompleteRequest(Irp, IO_NO_INCREMENT); 771 } 772 773 FsRtlExitFileSystem(); 774 775 return Status; 776 } 777