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