1 /* 2 * PROJECT: ReactOS kernel-mode tests 3 * LICENSE: LGPLv2.1+ - See COPYING.LIB in the top level directory 4 * PURPOSE: Test driver for CcCopyWrite 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 ULONG WriteLength; 19 } TEST_FCB, *PTEST_FCB; 20 21 static PFILE_OBJECT TestFileObject; 22 static PDEVICE_OBJECT TestDeviceObject; 23 static KMT_IRP_HANDLER TestIrpHandler; 24 static FAST_IO_DISPATCH TestFastIoDispatch; 25 26 static 27 BOOLEAN 28 NTAPI 29 FastIoRead( 30 _In_ PFILE_OBJECT FileObject, 31 _In_ PLARGE_INTEGER FileOffset, 32 _In_ ULONG Length, 33 _In_ BOOLEAN Wait, 34 _In_ ULONG LockKey, 35 _Out_ PVOID Buffer, 36 _Out_ PIO_STATUS_BLOCK IoStatus, 37 _In_ PDEVICE_OBJECT DeviceObject) 38 { 39 IoStatus->Status = STATUS_NOT_SUPPORTED; 40 return FALSE; 41 } 42 43 static 44 BOOLEAN 45 NTAPI 46 FastIoWrite( 47 _In_ PFILE_OBJECT FileObject, 48 _In_ PLARGE_INTEGER FileOffset, 49 _In_ ULONG Length, 50 _In_ BOOLEAN Wait, 51 _In_ ULONG LockKey, 52 _Out_ PVOID Buffer, 53 _Out_ PIO_STATUS_BLOCK IoStatus, 54 _In_ PDEVICE_OBJECT DeviceObject) 55 { 56 IoStatus->Status = STATUS_NOT_SUPPORTED; 57 return FALSE; 58 } 59 60 NTSTATUS 61 TestEntry( 62 _In_ PDRIVER_OBJECT DriverObject, 63 _In_ PCUNICODE_STRING RegistryPath, 64 _Out_ PCWSTR *DeviceName, 65 _Inout_ INT *Flags) 66 { 67 NTSTATUS Status = STATUS_SUCCESS; 68 69 PAGED_CODE(); 70 71 UNREFERENCED_PARAMETER(RegistryPath); 72 73 *DeviceName = L"CcCopyWrite"; 74 *Flags = TESTENTRY_NO_EXCLUSIVE_DEVICE | 75 TESTENTRY_BUFFERED_IO_DEVICE | 76 TESTENTRY_NO_READONLY_DEVICE; 77 78 KmtRegisterIrpHandler(IRP_MJ_CLEANUP, NULL, TestIrpHandler); 79 KmtRegisterIrpHandler(IRP_MJ_CREATE, NULL, TestIrpHandler); 80 KmtRegisterIrpHandler(IRP_MJ_READ, NULL, TestIrpHandler); 81 KmtRegisterIrpHandler(IRP_MJ_WRITE, NULL, TestIrpHandler); 82 KmtRegisterIrpHandler(IRP_MJ_FLUSH_BUFFERS, NULL, TestIrpHandler); 83 84 TestFastIoDispatch.FastIoRead = FastIoRead; 85 TestFastIoDispatch.FastIoWrite = FastIoWrite; 86 DriverObject->FastIoDispatch = &TestFastIoDispatch; 87 88 89 return Status; 90 } 91 92 VOID 93 TestUnload( 94 _In_ PDRIVER_OBJECT DriverObject) 95 { 96 PAGED_CODE(); 97 } 98 99 BOOLEAN 100 NTAPI 101 AcquireForLazyWrite( 102 _In_ PVOID Context, 103 _In_ BOOLEAN Wait) 104 { 105 return TRUE; 106 } 107 108 VOID 109 NTAPI 110 ReleaseFromLazyWrite( 111 _In_ PVOID Context) 112 { 113 return; 114 } 115 116 BOOLEAN 117 NTAPI 118 AcquireForReadAhead( 119 _In_ PVOID Context, 120 _In_ BOOLEAN Wait) 121 { 122 return TRUE; 123 } 124 125 VOID 126 NTAPI 127 ReleaseFromReadAhead( 128 _In_ PVOID Context) 129 { 130 return; 131 } 132 133 static CACHE_MANAGER_CALLBACKS Callbacks = { 134 AcquireForLazyWrite, 135 ReleaseFromLazyWrite, 136 AcquireForReadAhead, 137 ReleaseFromReadAhead, 138 }; 139 140 static 141 PVOID 142 MapAndLockUserBuffer( 143 _In_ _Out_ PIRP Irp, 144 _In_ ULONG BufferLength) 145 { 146 PMDL Mdl; 147 148 if (Irp->MdlAddress == NULL) 149 { 150 Mdl = IoAllocateMdl(Irp->UserBuffer, BufferLength, FALSE, FALSE, Irp); 151 if (Mdl == NULL) 152 { 153 return NULL; 154 } 155 156 _SEH2_TRY 157 { 158 MmProbeAndLockPages(Mdl, Irp->RequestorMode, IoWriteAccess); 159 } 160 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 161 { 162 IoFreeMdl(Mdl); 163 Irp->MdlAddress = NULL; 164 _SEH2_YIELD(return NULL); 165 } 166 _SEH2_END; 167 } 168 169 return MmGetSystemAddressForMdlSafe(Irp->MdlAddress, NormalPagePriority); 170 } 171 172 173 static 174 NTSTATUS 175 TestIrpHandler( 176 _In_ PDEVICE_OBJECT DeviceObject, 177 _In_ PIRP Irp, 178 _In_ PIO_STACK_LOCATION IoStack) 179 { 180 LARGE_INTEGER Zero = RTL_CONSTANT_LARGE_INTEGER(0LL); 181 NTSTATUS Status; 182 PTEST_FCB Fcb; 183 CACHE_UNINITIALIZE_EVENT CacheUninitEvent; 184 185 PAGED_CODE(); 186 187 DPRINT("IRP %x/%x\n", IoStack->MajorFunction, IoStack->MinorFunction); 188 ASSERT(IoStack->MajorFunction == IRP_MJ_CLEANUP || 189 IoStack->MajorFunction == IRP_MJ_CREATE || 190 IoStack->MajorFunction == IRP_MJ_READ || 191 IoStack->MajorFunction == IRP_MJ_WRITE || 192 IoStack->MajorFunction == IRP_MJ_FLUSH_BUFFERS); 193 194 Status = STATUS_NOT_SUPPORTED; 195 Irp->IoStatus.Information = 0; 196 197 if (IoStack->MajorFunction == IRP_MJ_CREATE) 198 { 199 ok_irql(PASSIVE_LEVEL); 200 201 if (IoStack->FileObject->FileName.Length >= 2 * sizeof(WCHAR)) 202 { 203 TestDeviceObject = DeviceObject; 204 TestFileObject = IoStack->FileObject; 205 } 206 Fcb = ExAllocatePoolWithTag(NonPagedPool, sizeof(*Fcb), 'FwrI'); 207 RtlZeroMemory(Fcb, sizeof(*Fcb)); 208 ExInitializeFastMutex(&Fcb->HeaderMutex); 209 FsRtlSetupAdvancedHeader(&Fcb->Header, &Fcb->HeaderMutex); 210 if (IoStack->FileObject->FileName.Length >= 2 * sizeof(WCHAR) && 211 IoStack->FileObject->FileName.Buffer[1] == 'B') 212 { 213 Fcb->Header.AllocationSize.QuadPart = 1000000; 214 Fcb->Header.FileSize.QuadPart = 1000000; 215 Fcb->Header.ValidDataLength.QuadPart = 1000000; 216 } 217 else if (IoStack->FileObject->FileName.Length >= 2 * sizeof(WCHAR) && 218 IoStack->FileObject->FileName.Buffer[1] == 'S') 219 { 220 Fcb->Header.AllocationSize.QuadPart = 512; 221 Fcb->Header.FileSize.QuadPart = 512; 222 Fcb->Header.ValidDataLength.QuadPart = 512; 223 } 224 else if (IoStack->FileObject->FileName.Length >= 2 * sizeof(WCHAR) && 225 IoStack->FileObject->FileName.Buffer[1] == 'V') 226 { 227 Fcb->Header.AllocationSize.QuadPart = 62; 228 Fcb->Header.FileSize.QuadPart = 62; 229 Fcb->Header.ValidDataLength.QuadPart = 62; 230 } 231 else 232 { 233 Fcb->Header.AllocationSize.QuadPart = 1004; 234 Fcb->Header.FileSize.QuadPart = 1004; 235 Fcb->Header.ValidDataLength.QuadPart = 1004; 236 } 237 Fcb->Header.IsFastIoPossible = FastIoIsNotPossible; 238 IoStack->FileObject->FsContext = Fcb; 239 IoStack->FileObject->SectionObjectPointer = &Fcb->SectionObjectPointers; 240 241 CcInitializeCacheMap(IoStack->FileObject, 242 (PCC_FILE_SIZES)&Fcb->Header.AllocationSize, 243 FALSE, &Callbacks, NULL); 244 245 Irp->IoStatus.Information = FILE_OPENED; 246 Status = STATUS_SUCCESS; 247 } 248 else if (IoStack->MajorFunction == IRP_MJ_READ) 249 { 250 PMDL Mdl; 251 ULONG Length; 252 PVOID Buffer; 253 LARGE_INTEGER Offset; 254 255 Offset = IoStack->Parameters.Read.ByteOffset; 256 Length = IoStack->Parameters.Read.Length; 257 Fcb = IoStack->FileObject->FsContext; 258 259 ok_eq_pointer(DeviceObject, TestDeviceObject); 260 ok_eq_pointer(IoStack->FileObject, TestFileObject); 261 262 ok(BooleanFlagOn(Irp->Flags, IRP_NOCACHE), "IRP not coming from Cc!\n"); 263 ok_irql(APC_LEVEL); 264 ok((Offset.QuadPart == 0 || Offset.QuadPart == 4096 || Offset.QuadPart == 8192), "Unexpected offset: %I64i\n", Offset.QuadPart); 265 ok(Length % PAGE_SIZE == 0, "Length is not aligned: %I64i\n", Length); 266 267 ok(Irp->AssociatedIrp.SystemBuffer == NULL, "A SystemBuffer was allocated!\n"); 268 Buffer = MapAndLockUserBuffer(Irp, Length); 269 ok(Buffer != NULL, "Null pointer!\n"); 270 RtlFillMemory(Buffer, Length, 0xBA); 271 272 Status = STATUS_SUCCESS; 273 274 Mdl = Irp->MdlAddress; 275 ok(Mdl != NULL, "Null pointer for MDL!\n"); 276 ok((Mdl->MdlFlags & MDL_PAGES_LOCKED) != 0, "MDL not locked\n"); 277 ok((Mdl->MdlFlags & MDL_SOURCE_IS_NONPAGED_POOL) == 0, "MDL from non paged\n"); 278 ok((Mdl->MdlFlags & MDL_IO_PAGE_READ) != 0, "Non paging IO\n"); 279 ok((Irp->Flags & IRP_PAGING_IO) != 0, "Non paging IO\n"); 280 281 Irp->IoStatus.Information = Length; 282 IoStack->FileObject->CurrentByteOffset.QuadPart = Offset.QuadPart + Length; 283 } 284 else if (IoStack->MajorFunction == IRP_MJ_WRITE) 285 { 286 PMDL Mdl; 287 ULONG Length; 288 PVOID Buffer; 289 LARGE_INTEGER Offset; 290 291 Offset = IoStack->Parameters.Read.ByteOffset; 292 Length = IoStack->Parameters.Read.Length; 293 Fcb = IoStack->FileObject->FsContext; 294 295 if (!FlagOn(Irp->Flags, IRP_NOCACHE)) 296 { 297 BOOLEAN Ret; 298 299 ok_irql(PASSIVE_LEVEL); 300 301 Buffer = Irp->AssociatedIrp.SystemBuffer; 302 ok(Buffer != NULL, "Null pointer!\n"); 303 304 Fcb->WriteLength = Length; 305 306 _SEH2_TRY 307 { 308 Ret = CcCopyWrite(IoStack->FileObject, &Offset, Length, TRUE, Buffer); 309 ok_bool_true(Ret, "CcCopyWrite"); 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_irql(PASSIVE_LEVEL); 322 ok((Offset.QuadPart == 0 || Offset.QuadPart == 4096), "Unexpected offset: %I64i\n", Offset.QuadPart); 323 ok_eq_ulong(Length, ROUND_TO_PAGES(Fcb->WriteLength)); 324 325 ok(Irp->AssociatedIrp.SystemBuffer == NULL, "A SystemBuffer was allocated!\n"); 326 Buffer = MapAndLockUserBuffer(Irp, Length); 327 ok(Buffer != NULL, "Null pointer!\n"); 328 329 Status = STATUS_SUCCESS; 330 331 Mdl = Irp->MdlAddress; 332 ok(Mdl != NULL, "Null pointer for MDL!\n"); 333 ok((Mdl->MdlFlags & MDL_PAGES_LOCKED) != 0, "MDL not locked\n"); 334 ok((Mdl->MdlFlags & MDL_SOURCE_IS_NONPAGED_POOL) == 0, "MDL from non paged\n"); 335 ok((Mdl->MdlFlags & MDL_IO_PAGE_READ) == 0, "MDL for read paging IO\n"); 336 ok((Irp->Flags & IRP_PAGING_IO) != 0, "Non paging IO\n"); 337 } 338 } 339 else if (IoStack->MajorFunction == IRP_MJ_FLUSH_BUFFERS) 340 { 341 IO_STATUS_BLOCK IoStatus; 342 343 Fcb = IoStack->FileObject->FsContext; 344 CcFlushCache(&Fcb->SectionObjectPointers, NULL, 0, &IoStatus); 345 346 Status = STATUS_SUCCESS; 347 } 348 else if (IoStack->MajorFunction == IRP_MJ_CLEANUP) 349 { 350 ok_irql(PASSIVE_LEVEL); 351 KeInitializeEvent(&CacheUninitEvent.Event, NotificationEvent, FALSE); 352 CcUninitializeCacheMap(IoStack->FileObject, &Zero, &CacheUninitEvent); 353 KeWaitForSingleObject(&CacheUninitEvent.Event, Executive, KernelMode, FALSE, NULL); 354 Fcb = IoStack->FileObject->FsContext; 355 ExFreePoolWithTag(Fcb, 'FwrI'); 356 IoStack->FileObject->FsContext = NULL; 357 Status = STATUS_SUCCESS; 358 } 359 360 if (Status == STATUS_PENDING) 361 { 362 IoMarkIrpPending(Irp); 363 IoCompleteRequest(Irp, IO_NO_INCREMENT); 364 Status = STATUS_PENDING; 365 } 366 else 367 { 368 Irp->IoStatus.Status = Status; 369 IoCompleteRequest(Irp, IO_NO_INCREMENT); 370 } 371 372 return Status; 373 } 374