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>
13 typedef struct _TEST_FCB
15 FSRTL_ADVANCED_FCB_HEADER Header
;
16 SECTION_OBJECT_POINTERS SectionObjectPointers
;
17 FAST_MUTEX HeaderMutex
;
18 } TEST_FCB
, *PTEST_FCB
;
20 static PFILE_OBJECT TestFileObject
;
21 static PDEVICE_OBJECT TestDeviceObject
;
22 static KMT_IRP_HANDLER TestIrpHandler
;
23 static FAST_IO_DISPATCH TestFastIoDispatch
;
29 _In_ PFILE_OBJECT FileObject
,
30 _In_ PLARGE_INTEGER FileOffset
,
35 _Out_ PIO_STATUS_BLOCK IoStatus
,
36 _In_ PDEVICE_OBJECT DeviceObject
)
38 IoStatus
->Status
= STATUS_NOT_SUPPORTED
;
44 _In_ PDRIVER_OBJECT DriverObject
,
45 _In_ PCUNICODE_STRING RegistryPath
,
46 _Out_ PCWSTR
*DeviceName
,
49 NTSTATUS Status
= STATUS_SUCCESS
;
53 UNREFERENCED_PARAMETER(RegistryPath
);
55 *DeviceName
= L
"CcCopyRead";
56 *Flags
= TESTENTRY_NO_EXCLUSIVE_DEVICE
|
57 TESTENTRY_BUFFERED_IO_DEVICE
|
58 TESTENTRY_NO_READONLY_DEVICE
;
60 KmtRegisterIrpHandler(IRP_MJ_CLEANUP
, NULL
, TestIrpHandler
);
61 KmtRegisterIrpHandler(IRP_MJ_CREATE
, NULL
, TestIrpHandler
);
62 KmtRegisterIrpHandler(IRP_MJ_READ
, NULL
, TestIrpHandler
);
64 TestFastIoDispatch
.FastIoRead
= FastIoRead
;
65 DriverObject
->FastIoDispatch
= &TestFastIoDispatch
;
73 _In_ PDRIVER_OBJECT DriverObject
)
106 ReleaseFromReadAhead(
112 static CACHE_MANAGER_CALLBACKS Callbacks
= {
114 ReleaseFromLazyWrite
,
116 ReleaseFromReadAhead
,
121 MapAndLockUserBuffer(
123 _In_ ULONG BufferLength
)
127 if (Irp
->MdlAddress
== NULL
)
129 Mdl
= IoAllocateMdl(Irp
->UserBuffer
, BufferLength
, FALSE
, FALSE
, Irp
);
137 MmProbeAndLockPages(Mdl
, Irp
->RequestorMode
, IoWriteAccess
);
139 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
142 Irp
->MdlAddress
= NULL
;
143 _SEH2_YIELD(return NULL
);
148 return MmGetSystemAddressForMdlSafe(Irp
->MdlAddress
, NormalPagePriority
);
155 _In_ PDEVICE_OBJECT DeviceObject
,
157 _In_ PIO_STACK_LOCATION IoStack
)
161 CACHE_UNINITIALIZE_EVENT CacheUninitEvent
;
165 DPRINT("IRP %x/%x\n", IoStack
->MajorFunction
, IoStack
->MinorFunction
);
166 ASSERT(IoStack
->MajorFunction
== IRP_MJ_CLEANUP
||
167 IoStack
->MajorFunction
== IRP_MJ_CREATE
||
168 IoStack
->MajorFunction
== IRP_MJ_READ
);
170 Status
= STATUS_NOT_SUPPORTED
;
171 Irp
->IoStatus
.Information
= 0;
173 if (IoStack
->MajorFunction
== IRP_MJ_CREATE
)
175 ok(KeGetCurrentIrql() == PASSIVE_LEVEL
, "Wrong IRQL: %d\n", KeGetCurrentIrql());
177 if (IoStack
->FileObject
->FileName
.Length
>= 2 * sizeof(WCHAR
))
179 TestDeviceObject
= DeviceObject
;
180 TestFileObject
= IoStack
->FileObject
;
182 Fcb
= ExAllocatePoolWithTag(NonPagedPool
, sizeof(*Fcb
), 'FwrI');
183 RtlZeroMemory(Fcb
, sizeof(*Fcb
));
184 ExInitializeFastMutex(&Fcb
->HeaderMutex
);
185 FsRtlSetupAdvancedHeader(&Fcb
->Header
, &Fcb
->HeaderMutex
);
186 if (IoStack
->FileObject
->FileName
.Length
>= 2 * sizeof(WCHAR
) &&
187 IoStack
->FileObject
->FileName
.Buffer
[1] == 'B')
189 Fcb
->Header
.AllocationSize
.QuadPart
= 1000000;
190 Fcb
->Header
.FileSize
.QuadPart
= 1000000;
191 Fcb
->Header
.ValidDataLength
.QuadPart
= 1000000;
193 else if (IoStack
->FileObject
->FileName
.Length
>= 2 * sizeof(WCHAR
) &&
194 IoStack
->FileObject
->FileName
.Buffer
[1] == 'S')
196 Fcb
->Header
.AllocationSize
.QuadPart
= 1004;
197 Fcb
->Header
.FileSize
.QuadPart
= 1004;
198 Fcb
->Header
.ValidDataLength
.QuadPart
= 1004;
200 else if (IoStack
->FileObject
->FileName
.Length
>= 2 * sizeof(WCHAR
) &&
201 IoStack
->FileObject
->FileName
.Buffer
[1] == 'R')
203 Fcb
->Header
.AllocationSize
.QuadPart
= 62;
204 Fcb
->Header
.FileSize
.QuadPart
= 62;
205 Fcb
->Header
.ValidDataLength
.QuadPart
= 62;
209 Fcb
->Header
.AllocationSize
.QuadPart
= 512;
210 Fcb
->Header
.FileSize
.QuadPart
= 512;
211 Fcb
->Header
.ValidDataLength
.QuadPart
= 512;
213 Fcb
->Header
.IsFastIoPossible
= FastIoIsNotPossible
;
214 IoStack
->FileObject
->FsContext
= Fcb
;
215 IoStack
->FileObject
->SectionObjectPointer
= &Fcb
->SectionObjectPointers
;
217 CcInitializeCacheMap(IoStack
->FileObject
,
218 (PCC_FILE_SIZES
)&Fcb
->Header
.AllocationSize
,
219 FALSE
, &Callbacks
, NULL
);
221 Irp
->IoStatus
.Information
= FILE_OPENED
;
222 Status
= STATUS_SUCCESS
;
224 else if (IoStack
->MajorFunction
== IRP_MJ_READ
)
229 LARGE_INTEGER Offset
;
231 Offset
= IoStack
->Parameters
.Read
.ByteOffset
;
232 Length
= IoStack
->Parameters
.Read
.Length
;
233 Fcb
= IoStack
->FileObject
->FsContext
;
235 ok_eq_pointer(DeviceObject
, TestDeviceObject
);
236 ok_eq_pointer(IoStack
->FileObject
, TestFileObject
);
238 if (!FlagOn(Irp
->Flags
, IRP_NOCACHE
))
240 ok(KeGetCurrentIrql() == PASSIVE_LEVEL
, "Wrong IRQL: %d\n", KeGetCurrentIrql());
241 ok(Offset
.QuadPart
% PAGE_SIZE
!= 0, "Offset is aligned: %I64i\n", Offset
.QuadPart
);
242 ok(Length
% PAGE_SIZE
!= 0, "Length is aligned: %I64i\n", Length
);
244 Buffer
= Irp
->AssociatedIrp
.SystemBuffer
;
245 ok(Buffer
!= NULL
, "Null pointer!\n");
249 Ret
= CcCopyRead(IoStack
->FileObject
, &Offset
, Length
, TRUE
, Buffer
,
251 ok_bool_true(Ret
, "CcCopyRead");
253 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
255 Irp
->IoStatus
.Status
= _SEH2_GetExceptionCode();
259 Status
= Irp
->IoStatus
.Status
;
261 if (NT_SUCCESS(Status
))
263 if (Offset
.QuadPart
<= 1000LL && Offset
.QuadPart
+ Length
> 1000LL)
265 ok_eq_hex(*(PUSHORT
)((ULONG_PTR
)Buffer
+ (ULONG_PTR
)(1000LL - Offset
.QuadPart
)), 0xFFFF);
269 ok_eq_hex(*(PUSHORT
)Buffer
, 0xBABA);
277 ok(KeGetCurrentIrql() == APC_LEVEL
, "Wrong IRQL: %d\n", KeGetCurrentIrql());
278 ok((Offset
.QuadPart
% PAGE_SIZE
== 0 || Offset
.QuadPart
== 0), "Offset is not aligned: %I64i\n", Offset
.QuadPart
);
279 ok(Length
% PAGE_SIZE
== 0, "Length is not aligned: %I64i\n", Length
);
281 ok(Irp
->AssociatedIrp
.SystemBuffer
== NULL
, "A SystemBuffer was allocated!\n");
282 Buffer
= MapAndLockUserBuffer(Irp
, Length
);
283 ok(Buffer
!= NULL
, "Null pointer!\n");
284 RtlFillMemory(Buffer
, Length
, 0xBA);
286 Status
= STATUS_SUCCESS
;
287 if (Offset
.QuadPart
<= 1000LL && Offset
.QuadPart
+ Length
> 1000LL)
289 *(PUSHORT
)((ULONG_PTR
)Buffer
+ (ULONG_PTR
)(1000LL - Offset
.QuadPart
)) = 0xFFFF;
292 Mdl
= Irp
->MdlAddress
;
293 ok(Mdl
!= NULL
, "Null pointer for MDL!\n");
294 ok((Mdl
->MdlFlags
& MDL_PAGES_LOCKED
) != 0, "MDL not locked\n");
295 ok((Mdl
->MdlFlags
& MDL_SOURCE_IS_NONPAGED_POOL
) == 0, "MDL from non paged\n");
296 ok((Mdl
->MdlFlags
& MDL_IO_PAGE_READ
) != 0, "Non paging IO\n");
297 ok((Irp
->Flags
& IRP_PAGING_IO
) != 0, "Non paging IO\n");
300 if (NT_SUCCESS(Status
))
302 Irp
->IoStatus
.Information
= Length
;
303 IoStack
->FileObject
->CurrentByteOffset
.QuadPart
= Offset
.QuadPart
+ Length
;
306 else if (IoStack
->MajorFunction
== IRP_MJ_CLEANUP
)
308 ok(KeGetCurrentIrql() == PASSIVE_LEVEL
, "Wrong IRQL: %d\n", KeGetCurrentIrql());
309 KeInitializeEvent(&CacheUninitEvent
.Event
, NotificationEvent
, FALSE
);
310 CcUninitializeCacheMap(IoStack
->FileObject
, NULL
, &CacheUninitEvent
);
311 KeWaitForSingleObject(&CacheUninitEvent
.Event
, Executive
, KernelMode
, FALSE
, NULL
);
312 Fcb
= IoStack
->FileObject
->FsContext
;
313 ExFreePoolWithTag(Fcb
, 'FwrI');
314 IoStack
->FileObject
->FsContext
= NULL
;
315 Status
= STATUS_SUCCESS
;
318 if (Status
== STATUS_PENDING
)
320 IoMarkIrpPending(Irp
);
321 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
322 Status
= STATUS_PENDING
;
326 Irp
->IoStatus
.Status
= Status
;
327 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);