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