1 /* 2 * PROJECT: ReactOS kernel-mode tests 3 * LICENSE: LGPLv2.1+ - See COPYING.LIB in the top level directory 4 * PURPOSE: Test driver for NtCreateSection 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 typedef struct _TEST_FCB 14 { 15 FSRTL_ADVANCED_FCB_HEADER Header; 16 SECTION_OBJECT_POINTERS SectionObjectPointers; 17 FAST_MUTEX HeaderMutex; 18 } TEST_FCB, *PTEST_FCB; 19 20 static PFILE_OBJECT TestFileObject; 21 static PDEVICE_OBJECT TestDeviceObject; 22 static KMT_IRP_HANDLER TestIrpHandler; 23 static FAST_IO_DISPATCH TestFastIoDispatch; 24 25 static UNICODE_STRING InitOnCreate = RTL_CONSTANT_STRING(L"\\InitOnCreate"); 26 static UNICODE_STRING InitOnRW = RTL_CONSTANT_STRING(L"\\InitOnRW"); 27 static UNICODE_STRING InvalidInit = RTL_CONSTANT_STRING(L"\\InvalidInit"); 28 29 static 30 BOOLEAN 31 NTAPI 32 FastIoRead( 33 _In_ PFILE_OBJECT FileObject, 34 _In_ PLARGE_INTEGER FileOffset, 35 _In_ ULONG Length, 36 _In_ BOOLEAN Wait, 37 _In_ ULONG LockKey, 38 _Out_ PVOID Buffer, 39 _Out_ PIO_STATUS_BLOCK IoStatus, 40 _In_ PDEVICE_OBJECT DeviceObject) 41 { 42 IoStatus->Status = STATUS_NOT_SUPPORTED; 43 return FALSE; 44 } 45 46 static 47 BOOLEAN 48 NTAPI 49 FastIoWrite( 50 _In_ PFILE_OBJECT FileObject, 51 _In_ PLARGE_INTEGER FileOffset, 52 _In_ ULONG Length, 53 _In_ BOOLEAN Wait, 54 _In_ ULONG LockKey, 55 _Out_ PVOID Buffer, 56 _Out_ PIO_STATUS_BLOCK IoStatus, 57 _In_ PDEVICE_OBJECT DeviceObject) 58 { 59 IoStatus->Status = STATUS_NOT_SUPPORTED; 60 return FALSE; 61 } 62 63 static 64 BOOLEAN 65 NTAPI 66 FastIoQueryStandardInfo( 67 _In_ PFILE_OBJECT FileObject, 68 _In_ BOOLEAN Wait, 69 _Out_ PFILE_STANDARD_INFORMATION Buffer, 70 _Out_ PIO_STATUS_BLOCK IoStatus, 71 _In_ PDEVICE_OBJECT DeviceObject) 72 { 73 IoStatus->Status = STATUS_NOT_SUPPORTED; 74 return FALSE; 75 } 76 77 NTSTATUS 78 TestEntry( 79 _In_ PDRIVER_OBJECT DriverObject, 80 _In_ PCUNICODE_STRING RegistryPath, 81 _Out_ PCWSTR *DeviceName, 82 _Inout_ INT *Flags) 83 { 84 NTSTATUS Status = STATUS_SUCCESS; 85 86 PAGED_CODE(); 87 88 UNREFERENCED_PARAMETER(RegistryPath); 89 90 *DeviceName = L"NtCreateSection"; 91 *Flags = TESTENTRY_NO_EXCLUSIVE_DEVICE | 92 TESTENTRY_BUFFERED_IO_DEVICE | 93 TESTENTRY_NO_READONLY_DEVICE; 94 95 KmtRegisterIrpHandler(IRP_MJ_CLEANUP, NULL, TestIrpHandler); 96 KmtRegisterIrpHandler(IRP_MJ_CREATE, NULL, TestIrpHandler); 97 KmtRegisterIrpHandler(IRP_MJ_READ, NULL, TestIrpHandler); 98 KmtRegisterIrpHandler(IRP_MJ_WRITE, NULL, TestIrpHandler); 99 KmtRegisterIrpHandler(IRP_MJ_QUERY_INFORMATION, NULL, TestIrpHandler); 100 KmtRegisterIrpHandler(IRP_MJ_SET_INFORMATION, NULL, TestIrpHandler); 101 102 TestFastIoDispatch.FastIoRead = FastIoRead; 103 TestFastIoDispatch.FastIoWrite = FastIoWrite; 104 TestFastIoDispatch.FastIoQueryStandardInfo = FastIoQueryStandardInfo; 105 DriverObject->FastIoDispatch = &TestFastIoDispatch; 106 107 108 return Status; 109 } 110 111 VOID 112 TestUnload( 113 _In_ PDRIVER_OBJECT DriverObject) 114 { 115 PAGED_CODE(); 116 } 117 118 BOOLEAN 119 NTAPI 120 AcquireForLazyWrite( 121 _In_ PVOID Context, 122 _In_ BOOLEAN Wait) 123 { 124 return TRUE; 125 } 126 127 VOID 128 NTAPI 129 ReleaseFromLazyWrite( 130 _In_ PVOID Context) 131 { 132 return; 133 } 134 135 BOOLEAN 136 NTAPI 137 AcquireForReadAhead( 138 _In_ PVOID Context, 139 _In_ BOOLEAN Wait) 140 { 141 return TRUE; 142 } 143 144 VOID 145 NTAPI 146 ReleaseFromReadAhead( 147 _In_ PVOID Context) 148 { 149 return; 150 } 151 152 static CACHE_MANAGER_CALLBACKS Callbacks = { 153 AcquireForLazyWrite, 154 ReleaseFromLazyWrite, 155 AcquireForReadAhead, 156 ReleaseFromReadAhead, 157 }; 158 159 static 160 PVOID 161 MapAndLockUserBuffer( 162 _In_ _Out_ PIRP Irp, 163 _In_ ULONG BufferLength) 164 { 165 PMDL Mdl; 166 167 if (Irp->MdlAddress == NULL) 168 { 169 Mdl = IoAllocateMdl(Irp->UserBuffer, BufferLength, FALSE, FALSE, Irp); 170 if (Mdl == NULL) 171 { 172 return NULL; 173 } 174 175 _SEH2_TRY 176 { 177 MmProbeAndLockPages(Mdl, Irp->RequestorMode, IoWriteAccess); 178 } 179 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 180 { 181 IoFreeMdl(Mdl); 182 Irp->MdlAddress = NULL; 183 _SEH2_YIELD(return NULL); 184 } 185 _SEH2_END; 186 } 187 188 return MmGetSystemAddressForMdlSafe(Irp->MdlAddress, NormalPagePriority); 189 } 190 191 192 static 193 NTSTATUS 194 TestIrpHandler( 195 _In_ PDEVICE_OBJECT DeviceObject, 196 _In_ PIRP Irp, 197 _In_ PIO_STACK_LOCATION IoStack) 198 { 199 NTSTATUS Status; 200 PTEST_FCB Fcb; 201 CACHE_UNINITIALIZE_EVENT CacheUninitEvent; 202 203 PAGED_CODE(); 204 205 DPRINT("IRP %x/%x\n", IoStack->MajorFunction, IoStack->MinorFunction); 206 ASSERT(IoStack->MajorFunction == IRP_MJ_CLEANUP || 207 IoStack->MajorFunction == IRP_MJ_CREATE || 208 IoStack->MajorFunction == IRP_MJ_READ || 209 IoStack->MajorFunction == IRP_MJ_WRITE || 210 IoStack->MajorFunction == IRP_MJ_QUERY_INFORMATION || 211 IoStack->MajorFunction == IRP_MJ_SET_INFORMATION); 212 213 Status = STATUS_NOT_SUPPORTED; 214 Irp->IoStatus.Information = 0; 215 216 if (IoStack->MajorFunction == IRP_MJ_CREATE) 217 { 218 ULONG RequestedDisposition = ((IoStack->Parameters.Create.Options >> 24) & 0xff); 219 ok(RequestedDisposition == FILE_CREATE || RequestedDisposition == FILE_OPEN, "Invalid disposition: %lu\n", RequestedDisposition); 220 221 if (IoStack->FileObject->FileName.Length >= 2 * sizeof(WCHAR)) 222 { 223 TestDeviceObject = DeviceObject; 224 TestFileObject = IoStack->FileObject; 225 } 226 Fcb = ExAllocatePoolWithTag(NonPagedPool, sizeof(*Fcb), 'FwrI'); 227 RtlZeroMemory(Fcb, sizeof(*Fcb)); 228 ExInitializeFastMutex(&Fcb->HeaderMutex); 229 FsRtlSetupAdvancedHeader(&Fcb->Header, &Fcb->HeaderMutex); 230 231 /* Consider file/dir doesn't exist */ 232 if (RequestedDisposition == FILE_CREATE) 233 { 234 Fcb->Header.AllocationSize.QuadPart = 0; 235 Fcb->Header.FileSize.QuadPart = 0; 236 Fcb->Header.ValidDataLength.QuadPart = 0; 237 } 238 else 239 { 240 Fcb->Header.AllocationSize.QuadPart = 512; 241 Fcb->Header.FileSize.QuadPart = 512; 242 Fcb->Header.ValidDataLength.QuadPart = 512; 243 } 244 Fcb->Header.IsFastIoPossible = FastIoIsNotPossible; 245 246 DPRINT1("File: %wZ\n", &IoStack->FileObject->FileName); 247 248 IoStack->FileObject->FsContext = Fcb; 249 if (RtlCompareUnicodeString(&IoStack->FileObject->FileName, &InvalidInit, FALSE) != 0) 250 { 251 IoStack->FileObject->SectionObjectPointer = &Fcb->SectionObjectPointers; 252 } 253 254 if (IoStack->FileObject->FileName.Length == 0 || 255 RtlCompareUnicodeString(&IoStack->FileObject->FileName, &InitOnCreate, FALSE) == 0) 256 { 257 DPRINT1("Init\n"); 258 259 CcInitializeCacheMap(IoStack->FileObject, 260 (PCC_FILE_SIZES)&Fcb->Header.AllocationSize, 261 FALSE, &Callbacks, NULL); 262 } 263 264 Irp->IoStatus.Information = (RequestedDisposition == FILE_CREATE) ? FILE_CREATED : FILE_OPENED; 265 Status = STATUS_SUCCESS; 266 } 267 else if (IoStack->MajorFunction == IRP_MJ_READ) 268 { 269 BOOLEAN Ret; 270 ULONG Length; 271 PVOID Buffer; 272 LARGE_INTEGER Offset; 273 274 Offset = IoStack->Parameters.Read.ByteOffset; 275 Length = IoStack->Parameters.Read.Length; 276 Fcb = IoStack->FileObject->FsContext; 277 278 ok_eq_pointer(DeviceObject, TestDeviceObject); 279 ok_eq_pointer(IoStack->FileObject, TestFileObject); 280 281 if (Offset.QuadPart + Length > Fcb->Header.FileSize.QuadPart) 282 { 283 Status = STATUS_END_OF_FILE; 284 } 285 else if (Length == 0) 286 { 287 Status = STATUS_SUCCESS; 288 } 289 else 290 { 291 if (!FlagOn(Irp->Flags, IRP_NOCACHE)) 292 { 293 Buffer = Irp->AssociatedIrp.SystemBuffer; 294 ok(Buffer != NULL, "Null pointer!\n"); 295 296 _SEH2_TRY 297 { 298 if (IoStack->FileObject->PrivateCacheMap == NULL) 299 { 300 DPRINT1("Init\n"); 301 ok_eq_ulong(RtlCompareUnicodeString(&IoStack->FileObject->FileName, &InitOnRW, FALSE), 0); 302 CcInitializeCacheMap(IoStack->FileObject, 303 (PCC_FILE_SIZES)&Fcb->Header.AllocationSize, 304 FALSE, &Callbacks, Fcb); 305 } 306 307 Ret = CcCopyRead(IoStack->FileObject, &Offset, Length, TRUE, Buffer, 308 &Irp->IoStatus); 309 ok_bool_true(Ret, "CcCopyRead"); 310 } 311 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 312 { 313 Irp->IoStatus.Status = _SEH2_GetExceptionCode(); 314 } 315 _SEH2_END; 316 317 Status = Irp->IoStatus.Status; 318 } 319 else 320 { 321 ok(Irp->AssociatedIrp.SystemBuffer == NULL, "A SystemBuffer was allocated!\n"); 322 Buffer = MapAndLockUserBuffer(Irp, Length); 323 ok(Buffer != NULL, "Null pointer!\n"); 324 RtlFillMemory(Buffer, Length, 0xBA); 325 326 Status = STATUS_SUCCESS; 327 } 328 } 329 330 if (NT_SUCCESS(Status)) 331 { 332 Irp->IoStatus.Information = Length; 333 IoStack->FileObject->CurrentByteOffset.QuadPart = Offset.QuadPart + Length; 334 } 335 } 336 else if (IoStack->MajorFunction == IRP_MJ_WRITE) 337 { 338 BOOLEAN Ret; 339 ULONG Length; 340 PVOID Buffer; 341 LARGE_INTEGER Offset; 342 343 Offset = IoStack->Parameters.Write.ByteOffset; 344 Length = IoStack->Parameters.Write.Length; 345 Fcb = IoStack->FileObject->FsContext; 346 347 ok_eq_pointer(DeviceObject, TestDeviceObject); 348 ok_eq_pointer(IoStack->FileObject, TestFileObject); 349 350 if (Length == 0) 351 { 352 Status = STATUS_SUCCESS; 353 } 354 else 355 { 356 if (!FlagOn(Irp->Flags, IRP_NOCACHE)) 357 { 358 Buffer = Irp->AssociatedIrp.SystemBuffer; 359 ok(Buffer != NULL, "Null pointer!\n"); 360 361 _SEH2_TRY 362 { 363 if (IoStack->FileObject->PrivateCacheMap == NULL) 364 { 365 ok_eq_ulong(RtlCompareUnicodeString(&IoStack->FileObject->FileName, &InitOnRW, FALSE), 0); 366 CcInitializeCacheMap(IoStack->FileObject, 367 (PCC_FILE_SIZES)&Fcb->Header.AllocationSize, 368 FALSE, &Callbacks, Fcb); 369 } 370 371 Ret = CcCopyWrite(IoStack->FileObject, &Offset, Length, TRUE, Buffer); 372 ok_bool_true(Ret, "CcCopyWrite"); 373 } 374 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 375 { 376 Irp->IoStatus.Status = _SEH2_GetExceptionCode(); 377 } 378 _SEH2_END; 379 380 Status = Irp->IoStatus.Status; 381 } 382 else 383 { 384 PMDL Mdl; 385 386 Mdl = Irp->MdlAddress; 387 ok(Mdl != NULL, "Null pointer for MDL!\n"); 388 ok((Mdl->MdlFlags & MDL_PAGES_LOCKED) != 0, "MDL not locked\n"); 389 ok((Mdl->MdlFlags & MDL_SOURCE_IS_NONPAGED_POOL) == 0, "MDL from non paged\n"); 390 ok((Mdl->MdlFlags & MDL_IO_PAGE_READ) == 0, "Paging IO for reading\n"); 391 ok((Irp->Flags & IRP_PAGING_IO) != 0, "Non paging IO\n"); 392 393 Status = STATUS_SUCCESS; 394 } 395 396 if (NT_SUCCESS(Status)) 397 { 398 if (Length + Offset.QuadPart > Fcb->Header.FileSize.QuadPart) 399 { 400 Fcb->Header.AllocationSize.QuadPart = Length + Offset.QuadPart; 401 Fcb->Header.FileSize.QuadPart = Length + Offset.QuadPart; 402 Fcb->Header.ValidDataLength.QuadPart = Length + Offset.QuadPart; 403 404 if (CcIsFileCached(IoStack->FileObject)) 405 { 406 CcSetFileSizes(IoStack->FileObject, (PCC_FILE_SIZES)(&(Fcb->Header.AllocationSize))); 407 } 408 } 409 } 410 } 411 } 412 else if (IoStack->MajorFunction == IRP_MJ_CLEANUP) 413 { 414 Fcb = IoStack->FileObject->FsContext; 415 ok(Fcb != NULL, "Null pointer!\n"); 416 if (IoStack->FileObject->SectionObjectPointer != NULL) 417 { 418 LARGE_INTEGER Zero = RTL_CONSTANT_LARGE_INTEGER(0LL); 419 420 if (CcIsFileCached(IoStack->FileObject)) 421 { 422 CcFlushCache(&Fcb->SectionObjectPointers, NULL, 0, NULL); 423 CcPurgeCacheSection(&Fcb->SectionObjectPointers, NULL, 0, FALSE); 424 } 425 426 KeInitializeEvent(&CacheUninitEvent.Event, NotificationEvent, FALSE); 427 CcUninitializeCacheMap(IoStack->FileObject, &Zero, &CacheUninitEvent); 428 KeWaitForSingleObject(&CacheUninitEvent.Event, Executive, KernelMode, FALSE, NULL); 429 } 430 ExFreePoolWithTag(Fcb, 'FwrI'); 431 IoStack->FileObject->FsContext = NULL; 432 Status = STATUS_SUCCESS; 433 } 434 else if (IoStack->MajorFunction == IRP_MJ_QUERY_INFORMATION) 435 { 436 Fcb = IoStack->FileObject->FsContext; 437 438 ok_eq_pointer(DeviceObject, TestDeviceObject); 439 ok_eq_pointer(IoStack->FileObject, TestFileObject); 440 ok_eq_ulong(IoStack->Parameters.QueryFile.FileInformationClass, FileStandardInformation); 441 442 if (IoStack->Parameters.QueryFile.FileInformationClass == FileStandardInformation) 443 { 444 PFILE_STANDARD_INFORMATION StandardInfo = Irp->AssociatedIrp.SystemBuffer; 445 ULONG BufferLength = IoStack->Parameters.QueryFile.Length; 446 447 if (BufferLength < sizeof(FILE_STANDARD_INFORMATION)) 448 { 449 Status = STATUS_BUFFER_OVERFLOW; 450 } 451 else 452 { 453 ok(StandardInfo != NULL, "Null pointer!\n"); 454 ok(Fcb != NULL, "Null pointer!\n"); 455 456 StandardInfo->AllocationSize = Fcb->Header.AllocationSize; 457 StandardInfo->EndOfFile = Fcb->Header.FileSize; 458 StandardInfo->Directory = FALSE; 459 StandardInfo->NumberOfLinks = 1; 460 StandardInfo->DeletePending = FALSE; 461 462 Irp->IoStatus.Information = sizeof(FILE_STANDARD_INFORMATION); 463 Status = STATUS_SUCCESS; 464 } 465 } 466 else 467 { 468 Status = STATUS_NOT_IMPLEMENTED; 469 } 470 } 471 else if (IoStack->MajorFunction == IRP_MJ_SET_INFORMATION) 472 { 473 Fcb = IoStack->FileObject->FsContext; 474 475 ok_eq_pointer(DeviceObject, TestDeviceObject); 476 ok_eq_pointer(IoStack->FileObject, TestFileObject); 477 ok_eq_ulong(IoStack->Parameters.SetFile.FileInformationClass, FileEndOfFileInformation); 478 479 if (IoStack->Parameters.SetFile.FileInformationClass == FileEndOfFileInformation) 480 { 481 PFILE_END_OF_FILE_INFORMATION EOFInfo = Irp->AssociatedIrp.SystemBuffer; 482 ULONG BufferLength = IoStack->Parameters.SetFile.Length; 483 484 if (BufferLength < sizeof(FILE_END_OF_FILE_INFORMATION)) 485 { 486 Status = STATUS_BUFFER_OVERFLOW; 487 } 488 else 489 { 490 ULONG TestSize = 0; 491 492 ok(EOFInfo != NULL, "Null pointer!\n"); 493 ok(Fcb != NULL, "Null pointer!\n"); 494 ok_bool_false(IoStack->Parameters.SetFile.AdvanceOnly, "AdvanceOnly set!\n"); 495 ok(EOFInfo->EndOfFile.QuadPart > Fcb->Header.AllocationSize.QuadPart, "New size smaller\n"); 496 497 if (Fcb->Header.AllocationSize.QuadPart != 0) 498 { 499 TestSize = 512; 500 } 501 502 Fcb->Header.AllocationSize.QuadPart = EOFInfo->EndOfFile.QuadPart; 503 ok_eq_ulong(Fcb->Header.FileSize.QuadPart, TestSize); 504 ok_eq_ulong(Fcb->Header.ValidDataLength.QuadPart, TestSize); 505 506 if (CcIsFileCached(IoStack->FileObject)) 507 { 508 CcSetFileSizes(IoStack->FileObject, (PCC_FILE_SIZES)(&(Fcb->Header.AllocationSize))); 509 } 510 511 ok_eq_ulong(Fcb->Header.FileSize.QuadPart, TestSize); 512 ok_eq_ulong(Fcb->Header.ValidDataLength.QuadPart, TestSize); 513 514 Status = STATUS_SUCCESS; 515 } 516 } 517 else 518 { 519 Status = STATUS_NOT_IMPLEMENTED; 520 } 521 } 522 523 if (Status == STATUS_PENDING) 524 { 525 IoMarkIrpPending(Irp); 526 IoCompleteRequest(Irp, IO_NO_INCREMENT); 527 Status = STATUS_PENDING; 528 } 529 else 530 { 531 Irp->IoStatus.Status = Status; 532 IoCompleteRequest(Irp, IO_NO_INCREMENT); 533 } 534 535 return Status; 536 } 537