d7540f72e019a06a7afb53f10d16c0cd326448a5
[reactos.git] / modules / rostests / kmtests / ntos_cc / CcCopyRead_drv.c
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 NTSTATUS Status;
160 PTEST_FCB Fcb;
161 CACHE_UNINITIALIZE_EVENT CacheUninitEvent;
162
163 PAGED_CODE();
164
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);
169
170 Status = STATUS_NOT_SUPPORTED;
171 Irp->IoStatus.Information = 0;
172
173 if (IoStack->MajorFunction == IRP_MJ_CREATE)
174 {
175 ok(KeGetCurrentIrql() == PASSIVE_LEVEL, "Wrong IRQL: %d\n", KeGetCurrentIrql());
176
177 if (IoStack->FileObject->FileName.Length >= 2 * sizeof(WCHAR))
178 {
179 TestDeviceObject = DeviceObject;
180 TestFileObject = IoStack->FileObject;
181 }
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')
188 {
189 Fcb->Header.AllocationSize.QuadPart = 1000000;
190 Fcb->Header.FileSize.QuadPart = 1000000;
191 Fcb->Header.ValidDataLength.QuadPart = 1000000;
192 }
193 else if (IoStack->FileObject->FileName.Length >= 2 * sizeof(WCHAR) &&
194 IoStack->FileObject->FileName.Buffer[1] == 'S')
195 {
196 Fcb->Header.AllocationSize.QuadPart = 1004;
197 Fcb->Header.FileSize.QuadPart = 1004;
198 Fcb->Header.ValidDataLength.QuadPart = 1004;
199 }
200 else if (IoStack->FileObject->FileName.Length >= 2 * sizeof(WCHAR) &&
201 IoStack->FileObject->FileName.Buffer[1] == 'R')
202 {
203 Fcb->Header.AllocationSize.QuadPart = 62;
204 Fcb->Header.FileSize.QuadPart = 62;
205 Fcb->Header.ValidDataLength.QuadPart = 62;
206 }
207 else
208 {
209 Fcb->Header.AllocationSize.QuadPart = 512;
210 Fcb->Header.FileSize.QuadPart = 512;
211 Fcb->Header.ValidDataLength.QuadPart = 512;
212 }
213 Fcb->Header.IsFastIoPossible = FastIoIsNotPossible;
214 IoStack->FileObject->FsContext = Fcb;
215 IoStack->FileObject->SectionObjectPointer = &Fcb->SectionObjectPointers;
216
217 CcInitializeCacheMap(IoStack->FileObject,
218 (PCC_FILE_SIZES)&Fcb->Header.AllocationSize,
219 FALSE, &Callbacks, NULL);
220
221 Irp->IoStatus.Information = FILE_OPENED;
222 Status = STATUS_SUCCESS;
223 }
224 else if (IoStack->MajorFunction == IRP_MJ_READ)
225 {
226 BOOLEAN Ret;
227 ULONG Length;
228 PVOID Buffer;
229 LARGE_INTEGER Offset;
230
231 Offset = IoStack->Parameters.Read.ByteOffset;
232 Length = IoStack->Parameters.Read.Length;
233 Fcb = IoStack->FileObject->FsContext;
234
235 ok_eq_pointer(DeviceObject, TestDeviceObject);
236 ok_eq_pointer(IoStack->FileObject, TestFileObject);
237
238 if (!FlagOn(Irp->Flags, IRP_NOCACHE))
239 {
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);
243
244 Buffer = Irp->AssociatedIrp.SystemBuffer;
245 ok(Buffer != NULL, "Null pointer!\n");
246
247 _SEH2_TRY
248 {
249 Ret = CcCopyRead(IoStack->FileObject, &Offset, Length, TRUE, Buffer,
250 &Irp->IoStatus);
251 ok_bool_true(Ret, "CcCopyRead");
252 }
253 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
254 {
255 Irp->IoStatus.Status = _SEH2_GetExceptionCode();
256 }
257 _SEH2_END;
258
259 Status = Irp->IoStatus.Status;
260
261 if (NT_SUCCESS(Status))
262 {
263 if (Offset.QuadPart <= 1000LL && Offset.QuadPart + Length > 1000LL)
264 {
265 ok_eq_hex(*(PUSHORT)((ULONG_PTR)Buffer + (ULONG_PTR)(1000LL - Offset.QuadPart)), 0xFFFF);
266 }
267 else
268 {
269 ok_eq_hex(*(PUSHORT)Buffer, 0xBABA);
270 }
271 }
272 }
273 else
274 {
275 PMDL Mdl;
276
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);
280
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);
285
286 Status = STATUS_SUCCESS;
287 if (Offset.QuadPart <= 1000LL && Offset.QuadPart + Length > 1000LL)
288 {
289 *(PUSHORT)((ULONG_PTR)Buffer + (ULONG_PTR)(1000LL - Offset.QuadPart)) = 0xFFFF;
290 }
291
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");
298 }
299
300 if (NT_SUCCESS(Status))
301 {
302 Irp->IoStatus.Information = Length;
303 IoStack->FileObject->CurrentByteOffset.QuadPart = Offset.QuadPart + Length;
304 }
305 }
306 else if (IoStack->MajorFunction == IRP_MJ_CLEANUP)
307 {
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;
316 }
317
318 if (Status == STATUS_PENDING)
319 {
320 IoMarkIrpPending(Irp);
321 IoCompleteRequest(Irp, IO_NO_INCREMENT);
322 Status = STATUS_PENDING;
323 }
324 else
325 {
326 Irp->IoStatus.Status = Status;
327 IoCompleteRequest(Irp, IO_NO_INCREMENT);
328 }
329
330 return Status;
331 }