[KMTESTS:CC]
[reactos.git] / rostests / kmtests / ntos_io / IoReadWrite_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 Read/Write operations
5 * PROGRAMMER: Thomas Faber <thomas.faber@reactos.org>
6 */
7
8 #include <kmt_test.h>
9 #include "IoReadWrite.h"
10
11 #define NDEBUG
12 #include <debug.h>
13
14 typedef struct _TEST_FCB
15 {
16 FSRTL_ADVANCED_FCB_HEADER Header;
17 SECTION_OBJECT_POINTERS SectionObjectPointers;
18 FAST_MUTEX HeaderMutex;
19 BOOLEAN Cached;
20 } TEST_FCB, *PTEST_FCB;
21
22 static KMT_IRP_HANDLER TestIrpHandler;
23 static FAST_IO_READ TestFastIoRead;
24 static FAST_IO_WRITE TestFastIoWrite;
25
26 static FAST_IO_DISPATCH TestFastIoDispatch;
27 static ULONG TestLastFastReadKey;
28 static ULONG TestLastFastWriteKey;
29 static PFILE_OBJECT TestFileObject;
30 static PDEVICE_OBJECT TestDeviceObject;
31
32 NTSTATUS
33 TestEntry(
34 _In_ PDRIVER_OBJECT DriverObject,
35 _In_ PCUNICODE_STRING RegistryPath,
36 _Out_ PCWSTR *DeviceName,
37 _Inout_ INT *Flags)
38 {
39 NTSTATUS Status = STATUS_SUCCESS;
40
41 PAGED_CODE();
42
43 UNREFERENCED_PARAMETER(RegistryPath);
44
45 *DeviceName = L"IoReadWrite";
46 *Flags = TESTENTRY_NO_EXCLUSIVE_DEVICE |
47 TESTENTRY_BUFFERED_IO_DEVICE |
48 TESTENTRY_NO_READONLY_DEVICE;
49
50 TestFastIoDispatch.FastIoRead = TestFastIoRead;
51 TestFastIoDispatch.FastIoWrite = TestFastIoWrite;
52 DriverObject->FastIoDispatch = &TestFastIoDispatch;
53
54 KmtRegisterIrpHandler(IRP_MJ_CREATE, NULL, TestIrpHandler);
55 KmtRegisterIrpHandler(IRP_MJ_CLEANUP, NULL, TestIrpHandler);
56 KmtRegisterIrpHandler(IRP_MJ_READ, NULL, TestIrpHandler);
57 KmtRegisterIrpHandler(IRP_MJ_WRITE, NULL, TestIrpHandler);
58
59 return Status;
60 }
61
62 VOID
63 TestUnload(
64 _In_ PDRIVER_OBJECT DriverObject)
65 {
66 PAGED_CODE();
67 }
68
69 static
70 BOOLEAN
71 NTAPI
72 TestAcquireForLazyWrite(
73 _In_ PVOID Context,
74 _In_ BOOLEAN Wait)
75 {
76 ok_eq_pointer(Context, NULL);
77 ok(0, "Unexpected call to AcquireForLazyWrite\n");
78 return TRUE;
79 }
80
81 static
82 VOID
83 NTAPI
84 TestReleaseFromLazyWrite(
85 _In_ PVOID Context)
86 {
87 ok_eq_pointer(Context, NULL);
88 ok(0, "Unexpected call to ReleaseFromLazyWrite\n");
89 }
90
91 static
92 BOOLEAN
93 NTAPI
94 TestAcquireForReadAhead(
95 _In_ PVOID Context,
96 _In_ BOOLEAN Wait)
97 {
98 ok_eq_pointer(Context, NULL);
99 ok(0, "Unexpected call to AcquireForReadAhead\n");
100 return TRUE;
101 }
102
103 static
104 VOID
105 NTAPI
106 TestReleaseFromReadAhead(
107 _In_ PVOID Context)
108 {
109 ok_eq_pointer(Context, NULL);
110 ok(0, "Unexpected call to ReleaseFromReadAhead\n");
111 }
112
113 static
114 NTSTATUS
115 TestCommonRead(
116 _In_ PVOID Buffer,
117 _In_ ULONG Length,
118 _In_ LONGLONG FileOffset,
119 _In_ ULONG LockKey,
120 _Out_ PIO_STATUS_BLOCK IoStatus)
121 {
122 if (FileOffset >= TEST_FILE_SIZE)
123 {
124 trace("FileOffset %I64d > file size\n", FileOffset);
125 IoStatus->Status = STATUS_END_OF_FILE;
126 IoStatus->Information = 0;
127 }
128 else if (Length == 0 || Buffer == NULL)
129 {
130 IoStatus->Status = STATUS_BUFFER_OVERFLOW;
131 IoStatus->Information = TEST_FILE_SIZE - FileOffset;
132 }
133 else
134 {
135 Length = min(Length, TEST_FILE_SIZE - FileOffset);
136 RtlFillMemory(Buffer, Length, KEY_GET_DATA(LockKey));
137 IoStatus->Status = TestGetReturnStatus(LockKey);
138 IoStatus->Information = Length;
139 }
140 if (LockKey & KEY_RETURN_PENDING)
141 return STATUS_PENDING;
142 return IoStatus->Status;
143 }
144
145 static
146 BOOLEAN
147 NTAPI
148 TestFastIoRead(
149 _In_ PFILE_OBJECT FileObject,
150 _In_ PLARGE_INTEGER FileOffset,
151 _In_ ULONG Length,
152 _In_ BOOLEAN Wait,
153 _In_ ULONG LockKey,
154 _Out_ PVOID Buffer,
155 _Out_ PIO_STATUS_BLOCK IoStatus,
156 _In_ PDEVICE_OBJECT DeviceObject)
157 {
158 PTEST_FCB Fcb;
159 NTSTATUS Status;
160
161 //trace("FastIoRead: %p %lx %I64d+%lu -> %p\n", FileObject, LockKey, FileOffset->QuadPart, Length, Buffer);
162 ok_eq_pointer(FileObject, TestFileObject);
163 ok_bool_true(Wait, "Wait is");
164 ok_eq_pointer(DeviceObject, TestDeviceObject);
165 Fcb = FileObject->FsContext;
166 ok_bool_true(Fcb->Cached, "Cached is");
167
168 TestLastFastReadKey = LockKey;
169 ok((ULONG_PTR)Buffer < MM_USER_PROBE_ADDRESS, "Buffer is %p\n", Buffer);
170 ok((ULONG_PTR)FileOffset > MM_USER_PROBE_ADDRESS, "FileOffset is %p\n", FileOffset);
171 ok((ULONG_PTR)IoStatus > MM_USER_PROBE_ADDRESS, "IoStatus is %p\n", IoStatus);
172 _SEH2_TRY
173 {
174 Status = TestCommonRead(Buffer, Length, FileOffset->QuadPart, LockKey, IoStatus);
175 }
176 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
177 {
178 IoStatus->Status = _SEH2_GetExceptionCode();
179 return FALSE;
180 }
181 _SEH2_END;
182
183 if (Status == STATUS_PENDING)
184 return FALSE;
185
186 if (LockKey & KEY_USE_FASTIO)
187 return TRUE;
188 else
189 return FALSE;
190 }
191
192 static
193 NTSTATUS
194 TestCommonWrite(
195 _In_ PVOID Buffer,
196 _In_ ULONG Length,
197 _In_ LONGLONG FileOffset,
198 _In_ ULONG LockKey,
199 _Out_ PIO_STATUS_BLOCK IoStatus)
200 {
201 ULONG i;
202 PUCHAR BufferBytes = Buffer;
203
204 for (i = 0; i < Length; i++)
205 ok(BufferBytes[i] == KEY_GET_DATA(LockKey), "Buffer[%lu] = 0x%x, expected 0x%x\n", i, BufferBytes[i], KEY_GET_DATA(LockKey));
206 IoStatus->Status = TestGetReturnStatus(LockKey);
207 IoStatus->Information = Length;
208
209 if (LockKey & KEY_RETURN_PENDING)
210 return STATUS_PENDING;
211 return IoStatus->Status;
212 }
213
214 static
215 BOOLEAN
216 NTAPI
217 TestFastIoWrite(
218 _In_ PFILE_OBJECT FileObject,
219 _In_ PLARGE_INTEGER FileOffset,
220 _In_ ULONG Length,
221 _In_ BOOLEAN Wait,
222 _In_ ULONG LockKey,
223 _In_ PVOID Buffer,
224 _Out_ PIO_STATUS_BLOCK IoStatus,
225 _In_ PDEVICE_OBJECT DeviceObject)
226 {
227 PTEST_FCB Fcb;
228 NTSTATUS Status;
229
230 //trace("FastIoWrite: %p %lx %p -> %I64d+%lu\n", FileObject, LockKey, Buffer, FileOffset->QuadPart, Length);
231 ok_eq_pointer(FileObject, TestFileObject);
232 ok_bool_true(Wait, "Wait is");
233 ok_eq_pointer(DeviceObject, TestDeviceObject);
234 Fcb = FileObject->FsContext;
235 ok_bool_true(Fcb->Cached, "Cached is");
236
237 TestLastFastWriteKey = LockKey;
238 ok((ULONG_PTR)Buffer < MM_USER_PROBE_ADDRESS, "Buffer is %p\n", Buffer);
239 ok((ULONG_PTR)FileOffset > MM_USER_PROBE_ADDRESS, "FileOffset is %p\n", FileOffset);
240 ok((ULONG_PTR)IoStatus > MM_USER_PROBE_ADDRESS, "IoStatus is %p\n", IoStatus);
241 _SEH2_TRY
242 {
243 Status = TestCommonWrite(Buffer, Length, FileOffset->QuadPart, LockKey, IoStatus);
244 }
245 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
246 {
247 IoStatus->Status = _SEH2_GetExceptionCode();
248 return FALSE;
249 }
250 _SEH2_END;
251
252 if (Status == STATUS_PENDING)
253 return FALSE;
254
255 if (LockKey & KEY_USE_FASTIO)
256 return TRUE;
257 else
258 return FALSE;
259 }
260
261 static
262 NTSTATUS
263 TestIrpHandler(
264 _In_ PDEVICE_OBJECT DeviceObject,
265 _In_ PIRP Irp,
266 _In_ PIO_STACK_LOCATION IoStack)
267 {
268 NTSTATUS Status;
269 PTEST_FCB Fcb;
270 CACHE_MANAGER_CALLBACKS Callbacks;
271 CACHE_UNINITIALIZE_EVENT CacheUninitEvent;
272
273 PAGED_CODE();
274
275 DPRINT("IRP %x/%x\n", IoStack->MajorFunction, IoStack->MinorFunction);
276 ASSERT(IoStack->MajorFunction == IRP_MJ_CREATE ||
277 IoStack->MajorFunction == IRP_MJ_CLEANUP ||
278 IoStack->MajorFunction == IRP_MJ_READ ||
279 IoStack->MajorFunction == IRP_MJ_WRITE);
280
281 Status = STATUS_NOT_SUPPORTED;
282 Irp->IoStatus.Information = 0;
283
284 if (IoStack->MajorFunction == IRP_MJ_CREATE)
285 {
286 if (IoStack->FileObject->FileName.Length >= 2 * sizeof(WCHAR))
287 {
288 TestDeviceObject = DeviceObject;
289 TestFileObject = IoStack->FileObject;
290 }
291 Fcb = ExAllocatePoolWithTag(NonPagedPool, sizeof(*Fcb), 'FwrI');
292 RtlZeroMemory(Fcb, sizeof(*Fcb));
293 ExInitializeFastMutex(&Fcb->HeaderMutex);
294 FsRtlSetupAdvancedHeader(&Fcb->Header, &Fcb->HeaderMutex);
295 Fcb->Header.AllocationSize.QuadPart = TEST_FILE_SIZE;
296 Fcb->Header.FileSize.QuadPart = TEST_FILE_SIZE;
297 Fcb->Header.ValidDataLength.QuadPart = TEST_FILE_SIZE;
298 IoStack->FileObject->FsContext = Fcb;
299 IoStack->FileObject->SectionObjectPointer = &Fcb->SectionObjectPointers;
300 if (IoStack->FileObject->FileName.Length >= 2 * sizeof(WCHAR) &&
301 IoStack->FileObject->FileName.Buffer[1] != 'N')
302 {
303 Fcb->Cached = TRUE;
304 Callbacks.AcquireForLazyWrite = TestAcquireForLazyWrite;
305 Callbacks.ReleaseFromLazyWrite = TestReleaseFromLazyWrite;
306 Callbacks.AcquireForReadAhead = TestAcquireForReadAhead;
307 Callbacks.ReleaseFromReadAhead = TestReleaseFromReadAhead;
308 CcInitializeCacheMap(IoStack->FileObject,
309 (PCC_FILE_SIZES)&Fcb->Header.AllocationSize,
310 FALSE,
311 &Callbacks,
312 NULL);
313 }
314 Irp->IoStatus.Information = FILE_OPENED;
315 Status = STATUS_SUCCESS;
316 }
317 else if (IoStack->MajorFunction == IRP_MJ_CLEANUP)
318 {
319 KeInitializeEvent(&CacheUninitEvent.Event, NotificationEvent, FALSE);
320 CcUninitializeCacheMap(IoStack->FileObject, NULL, &CacheUninitEvent);
321 KeWaitForSingleObject(&CacheUninitEvent.Event, Executive, KernelMode, FALSE, NULL);
322 Fcb = IoStack->FileObject->FsContext;
323 ExFreePoolWithTag(Fcb, 'FwrI');
324 IoStack->FileObject->FsContext = NULL;
325 Status = STATUS_SUCCESS;
326 }
327 else if (IoStack->MajorFunction == IRP_MJ_READ)
328 {
329 //trace("IRP_MJ_READ: %p %lx %I64d+%lu -> %p\n", IoStack->FileObject, IoStack->Parameters.Read.Key, IoStack->Parameters.Read.ByteOffset.QuadPart, IoStack->Parameters.Read.Length, Irp->AssociatedIrp.SystemBuffer);
330 ok_eq_pointer(DeviceObject, TestDeviceObject);
331 ok_eq_pointer(IoStack->FileObject, TestFileObject);
332 Fcb = IoStack->FileObject->FsContext;
333 if (Fcb->Cached)
334 ok_eq_hex(IoStack->Parameters.Read.Key, TestLastFastReadKey);
335 ok(Irp->AssociatedIrp.SystemBuffer == NULL ||
336 (ULONG_PTR)Irp->AssociatedIrp.SystemBuffer > MM_USER_PROBE_ADDRESS,
337 "Buffer is %p\n",
338 Irp->AssociatedIrp.SystemBuffer);
339 Status = TestCommonRead(Irp->AssociatedIrp.SystemBuffer,
340 IoStack->Parameters.Read.Length,
341 IoStack->Parameters.Read.ByteOffset.QuadPart,
342 IoStack->Parameters.Read.Key,
343 &Irp->IoStatus);
344 }
345 else if (IoStack->MajorFunction == IRP_MJ_WRITE)
346 {
347 //trace("IRP_MJ_WRITE: %p %lx %I64d+%lu -> %p\n", IoStack->FileObject, IoStack->Parameters.Write.Key, IoStack->Parameters.Write.ByteOffset.QuadPart, IoStack->Parameters.Write.Length, Irp->AssociatedIrp.SystemBuffer);
348 ok_eq_pointer(DeviceObject, TestDeviceObject);
349 ok_eq_pointer(IoStack->FileObject, TestFileObject);
350 Fcb = IoStack->FileObject->FsContext;
351 if (Fcb->Cached)
352 ok_eq_hex(IoStack->Parameters.Write.Key, TestLastFastWriteKey);
353 ok(Irp->AssociatedIrp.SystemBuffer == NULL ||
354 (ULONG_PTR)Irp->AssociatedIrp.SystemBuffer > MM_USER_PROBE_ADDRESS,
355 "Buffer is %p\n",
356 Irp->AssociatedIrp.SystemBuffer);
357 Status = TestCommonWrite(Irp->AssociatedIrp.SystemBuffer,
358 IoStack->Parameters.Write.Length,
359 IoStack->Parameters.Write.ByteOffset.QuadPart,
360 IoStack->Parameters.Write.Key,
361 &Irp->IoStatus);
362 }
363
364 if (Status == STATUS_PENDING)
365 {
366 IoMarkIrpPending(Irp);
367 IoCompleteRequest(Irp, IO_NO_INCREMENT);
368 Status = STATUS_PENDING;
369 }
370 else
371 {
372 Irp->IoStatus.Status = Status;
373 IoCompleteRequest(Irp, IO_NO_INCREMENT);
374 }
375
376 return Status;
377 }