[KMTESTS:IO]
[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 | TESTENTRY_BUFFERED_IO_DEVICE;
47
48 TestFastIoDispatch.FastIoRead = TestFastIoRead;
49 TestFastIoDispatch.FastIoWrite = TestFastIoWrite;
50 DriverObject->FastIoDispatch = &TestFastIoDispatch;
51
52 KmtRegisterIrpHandler(IRP_MJ_CREATE, NULL, TestIrpHandler);
53 KmtRegisterIrpHandler(IRP_MJ_CLEANUP, NULL, TestIrpHandler);
54 KmtRegisterIrpHandler(IRP_MJ_READ, NULL, TestIrpHandler);
55 //KmtRegisterIrpHandler(IRP_MJ_WRITE, NULL, TestIrpHandler);
56
57 return Status;
58 }
59
60 VOID
61 TestUnload(
62 _In_ PDRIVER_OBJECT DriverObject)
63 {
64 PAGED_CODE();
65 }
66
67 static
68 BOOLEAN
69 NTAPI
70 TestAcquireForLazyWrite(
71 _In_ PVOID Context,
72 _In_ BOOLEAN Wait)
73 {
74 ok_eq_pointer(Context, NULL);
75 ok(0, "Unexpected call to AcquireForLazyWrite\n");
76 return TRUE;
77 }
78
79 static
80 VOID
81 NTAPI
82 TestReleaseFromLazyWrite(
83 _In_ PVOID Context)
84 {
85 ok_eq_pointer(Context, NULL);
86 ok(0, "Unexpected call to ReleaseFromLazyWrite\n");
87 }
88
89 static
90 BOOLEAN
91 NTAPI
92 TestAcquireForReadAhead(
93 _In_ PVOID Context,
94 _In_ BOOLEAN Wait)
95 {
96 ok_eq_pointer(Context, NULL);
97 ok(0, "Unexpected call to AcquireForReadAhead\n");
98 return TRUE;
99 }
100
101 static
102 VOID
103 NTAPI
104 TestReleaseFromReadAhead(
105 _In_ PVOID Context)
106 {
107 ok_eq_pointer(Context, NULL);
108 ok(0, "Unexpected call to ReleaseFromReadAhead\n");
109 }
110
111 static
112 NTSTATUS
113 TestCommonRead(
114 _In_ PVOID Buffer,
115 _In_ ULONG Length,
116 _In_ LONGLONG FileOffset,
117 _In_ ULONG LockKey,
118 _Out_ PIO_STATUS_BLOCK IoStatus)
119 {
120 if (FileOffset >= TEST_FILE_SIZE)
121 {
122 trace("FileOffset %I64d > file size\n", FileOffset);
123 IoStatus->Status = STATUS_END_OF_FILE;
124 IoStatus->Information = 0;
125 }
126 else if (Length == 0 || Buffer == NULL)
127 {
128 IoStatus->Status = STATUS_BUFFER_OVERFLOW;
129 IoStatus->Information = TEST_FILE_SIZE - FileOffset;
130 }
131 else
132 {
133 Length = min(Length, TEST_FILE_SIZE - FileOffset);
134 RtlFillMemory(Buffer, Length, KEY_GET_DATA(LockKey));
135 IoStatus->Status = TestGetReturnStatus(LockKey);
136 IoStatus->Information = Length;
137 }
138 if (LockKey & KEY_RETURN_PENDING)
139 return STATUS_PENDING;
140 return IoStatus->Status;
141 }
142
143 static
144 BOOLEAN
145 NTAPI
146 TestFastIoRead(
147 _In_ PFILE_OBJECT FileObject,
148 _In_ PLARGE_INTEGER FileOffset,
149 _In_ ULONG Length,
150 _In_ BOOLEAN Wait,
151 _In_ ULONG LockKey,
152 _Out_ PVOID Buffer,
153 _Out_ PIO_STATUS_BLOCK IoStatus,
154 _In_ PDEVICE_OBJECT DeviceObject)
155 {
156 PTEST_FCB Fcb;
157 NTSTATUS Status;
158
159 //trace("FastIoRead: %p %lx %I64d+%lu -> %p\n", FileObject, LockKey, FileOffset->QuadPart, Length, Buffer);
160 ok_eq_pointer(FileObject, TestFileObject);
161 ok_bool_true(Wait, "Wait is");
162 ok_eq_pointer(DeviceObject, TestDeviceObject);
163 Fcb = FileObject->FsContext;
164 ok_bool_true(Fcb->Cached, "Cached is");
165
166 TestLastFastReadKey = LockKey;
167 ok((ULONG_PTR)Buffer < MM_USER_PROBE_ADDRESS, "Buffer is %p\n", Buffer);
168 ok((ULONG_PTR)FileOffset > MM_USER_PROBE_ADDRESS, "FileOffset is %p\n", FileOffset);
169 ok((ULONG_PTR)IoStatus > MM_USER_PROBE_ADDRESS, "IoStatus is %p\n", IoStatus);
170 _SEH2_TRY
171 {
172 Status = TestCommonRead(Buffer, Length, FileOffset->QuadPart, LockKey, IoStatus);
173 }
174 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
175 {
176 IoStatus->Status = _SEH2_GetExceptionCode();
177 return FALSE;
178 }
179 _SEH2_END;
180
181 if (Status == STATUS_PENDING)
182 return FALSE;
183
184 if (LockKey & KEY_USE_FASTIO)
185 return TRUE;
186 else
187 return FALSE;
188 }
189
190 static
191 BOOLEAN
192 NTAPI
193 TestFastIoWrite(
194 _In_ PFILE_OBJECT FileObject,
195 _In_ PLARGE_INTEGER FileOffset,
196 _In_ ULONG Length,
197 _In_ BOOLEAN Wait,
198 _In_ ULONG LockKey,
199 _In_ PVOID Buffer,
200 _Out_ PIO_STATUS_BLOCK IoStatus,
201 _In_ PDEVICE_OBJECT DeviceObject)
202 {
203 UNIMPLEMENTED;
204 return FALSE;
205 }
206
207 static
208 NTSTATUS
209 TestIrpHandler(
210 _In_ PDEVICE_OBJECT DeviceObject,
211 _In_ PIRP Irp,
212 _In_ PIO_STACK_LOCATION IoStack)
213 {
214 NTSTATUS Status;
215 PTEST_FCB Fcb;
216 CACHE_MANAGER_CALLBACKS Callbacks;
217 CACHE_UNINITIALIZE_EVENT CacheUninitEvent;
218
219 PAGED_CODE();
220
221 DPRINT("IRP %x/%x\n", IoStack->MajorFunction, IoStack->MinorFunction);
222 ASSERT(IoStack->MajorFunction == IRP_MJ_CREATE ||
223 IoStack->MajorFunction == IRP_MJ_CLEANUP ||
224 IoStack->MajorFunction == IRP_MJ_READ ||
225 IoStack->MajorFunction == IRP_MJ_WRITE);
226
227 Status = STATUS_NOT_SUPPORTED;
228 Irp->IoStatus.Information = 0;
229
230 if (IoStack->MajorFunction == IRP_MJ_CREATE)
231 {
232 if (IoStack->FileObject->FileName.Length >= 2 * sizeof(WCHAR))
233 {
234 TestDeviceObject = DeviceObject;
235 TestFileObject = IoStack->FileObject;
236 }
237 Fcb = ExAllocatePoolWithTag(NonPagedPool, sizeof(*Fcb), 'FwrI');
238 RtlZeroMemory(Fcb, sizeof(*Fcb));
239 ExInitializeFastMutex(&Fcb->HeaderMutex);
240 FsRtlSetupAdvancedHeader(&Fcb->Header, &Fcb->HeaderMutex);
241 Fcb->Header.AllocationSize.QuadPart = TEST_FILE_SIZE;
242 Fcb->Header.FileSize.QuadPart = TEST_FILE_SIZE;
243 Fcb->Header.ValidDataLength.QuadPart = TEST_FILE_SIZE;
244 IoStack->FileObject->FsContext = Fcb;
245 IoStack->FileObject->SectionObjectPointer = &Fcb->SectionObjectPointers;
246 if (IoStack->FileObject->FileName.Length >= 2 * sizeof(WCHAR) &&
247 IoStack->FileObject->FileName.Buffer[1] != 'N')
248 {
249 Fcb->Cached = TRUE;
250 Callbacks.AcquireForLazyWrite = TestAcquireForLazyWrite;
251 Callbacks.ReleaseFromLazyWrite = TestReleaseFromLazyWrite;
252 Callbacks.AcquireForReadAhead = TestAcquireForReadAhead;
253 Callbacks.ReleaseFromReadAhead = TestReleaseFromReadAhead;
254 CcInitializeCacheMap(IoStack->FileObject,
255 (PCC_FILE_SIZES)&Fcb->Header.AllocationSize,
256 FALSE,
257 &Callbacks,
258 NULL);
259 }
260 Irp->IoStatus.Information = FILE_OPENED;
261 Status = STATUS_SUCCESS;
262 }
263 else if (IoStack->MajorFunction == IRP_MJ_CLEANUP)
264 {
265 KeInitializeEvent(&CacheUninitEvent.Event, NotificationEvent, FALSE);
266 CcUninitializeCacheMap(IoStack->FileObject, NULL, &CacheUninitEvent);
267 KeWaitForSingleObject(&CacheUninitEvent.Event, Executive, KernelMode, FALSE, NULL);
268 Fcb = IoStack->FileObject->FsContext;
269 ExFreePoolWithTag(Fcb, 'FwrI');
270 IoStack->FileObject->FsContext = NULL;
271 Status = STATUS_SUCCESS;
272 }
273 else if (IoStack->MajorFunction == IRP_MJ_READ)
274 {
275 //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);
276 ok_eq_pointer(DeviceObject, TestDeviceObject);
277 ok_eq_pointer(IoStack->FileObject, TestFileObject);
278 Fcb = IoStack->FileObject->FsContext;
279 if (Fcb->Cached)
280 ok_eq_hex(IoStack->Parameters.Read.Key, TestLastFastReadKey);
281 ok(Irp->AssociatedIrp.SystemBuffer == NULL ||
282 (ULONG_PTR)Irp->AssociatedIrp.SystemBuffer > MM_USER_PROBE_ADDRESS,
283 "Buffer is %p\n",
284 Irp->AssociatedIrp.SystemBuffer);
285 Status = TestCommonRead(Irp->AssociatedIrp.SystemBuffer,
286 IoStack->Parameters.Read.Length,
287 IoStack->Parameters.Read.ByteOffset.QuadPart,
288 IoStack->Parameters.Read.Key,
289 &Irp->IoStatus);
290 }
291 else if (IoStack->MajorFunction == IRP_MJ_WRITE)
292 {
293 ok_eq_pointer(DeviceObject, TestDeviceObject);
294 ok_eq_pointer(IoStack->FileObject, TestFileObject);
295 UNIMPLEMENTED;
296 Status = STATUS_NOT_IMPLEMENTED;
297 }
298
299 if (Status == STATUS_PENDING)
300 {
301 IoMarkIrpPending(Irp);
302 IoCompleteRequest(Irp, IO_NO_INCREMENT);
303 Status = STATUS_PENDING;
304 }
305 else
306 {
307 Irp->IoStatus.Status = Status;
308 IoCompleteRequest(Irp, IO_NO_INCREMENT);
309 }
310
311 return Status;
312 }