1 /*
2 * PROJECT: ReactOS kernel-mode tests
3 * LICENSE: LGPLv2.1+ - See COPYING.LIB in the top level directory
4 * PURPOSE: Test 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 static
12 VOID
TestRead(_In_ HANDLE FileHandle,_In_ BOOLEAN Cached,_In_ BOOLEAN UseFastIo,_In_ BOOLEAN ReturnPending)13 TestRead(
14 _In_ HANDLE FileHandle,
15 _In_ BOOLEAN Cached,
16 _In_ BOOLEAN UseFastIo,
17 _In_ BOOLEAN ReturnPending)
18 {
19 NTSTATUS Status;
20 IO_STATUS_BLOCK IoStatus;
21 HANDLE EventHandle;
22 UCHAR Buffer[32];
23 LARGE_INTEGER Offset;
24 ULONG BaseKey, StatusKey, Key;
25 DWORD WaitStatus;
26
27 BaseKey = (UseFastIo ? KEY_USE_FASTIO : 0) |
28 (ReturnPending ? KEY_RETURN_PENDING : 0);
29
30 EventHandle = CreateEventW(NULL, TRUE, FALSE, NULL);
31 ok(EventHandle != NULL, "CreateEvent failed with %lu\n", GetLastError());
32
33 for (StatusKey = KEY_SUCCEED ; StatusKey != 0xff; StatusKey = KEY_NEXT(StatusKey))
34 {
35 //trace("\tSTATUS KEY: %lx\n", StatusKey);
36 ResetEvent(EventHandle);
37 RtlFillMemory(&IoStatus, sizeof(IoStatus), 0x55);
38 Key = BaseKey | StatusKey | KEY_DATA(0x11);
39 Offset.QuadPart = 0;
40 Status = NtReadFile(FileHandle,
41 EventHandle,
42 NULL,
43 NULL,
44 &IoStatus,
45 NULL,
46 0,
47 &Offset,
48 &Key);
49 WaitStatus = WaitForSingleObject(EventHandle, 0);
50 if (ReturnPending)
51 ok_eq_hex(Status, STATUS_ACCESS_VIOLATION);
52 else
53 ok_eq_hex(Status, STATUS_BUFFER_OVERFLOW);
54 if (Cached && UseFastIo && !ReturnPending)
55 {
56 ok_eq_ulong(WaitStatus, WAIT_OBJECT_0);
57 ok_eq_hex(IoStatus.Status, STATUS_BUFFER_OVERFLOW);
58 ok_eq_ulongptr(IoStatus.Information, TEST_FILE_SIZE);
59 }
60 else
61 {
62 ok_eq_ulong(WaitStatus, WAIT_TIMEOUT);
63 ok_eq_hex(IoStatus.Status, 0x55555555);
64 ok_eq_ulongptr(IoStatus.Information, (ULONG_PTR)0x5555555555555555);
65 }
66
67 KmtStartSeh()
68 ResetEvent(EventHandle);
69 RtlFillMemory(&IoStatus, sizeof(IoStatus), 0x55);
70 Key = BaseKey | StatusKey | KEY_DATA(0x22);
71 Offset.QuadPart = 0;
72 Status = NtReadFile(FileHandle,
73 EventHandle,
74 NULL,
75 NULL,
76 &IoStatus,
77 NULL,
78 sizeof(Buffer),
79 &Offset,
80 &Key);
81 WaitStatus = WaitForSingleObject(EventHandle, 0);
82 ok_eq_ulong(WaitStatus, WAIT_TIMEOUT);
83 ok_eq_hex(Status, STATUS_ACCESS_VIOLATION);
84 ok_eq_hex(IoStatus.Status, 0x55555555);
85 ok_eq_ulongptr(IoStatus.Information, (ULONG_PTR)0x5555555555555555);
86 KmtEndSeh(STATUS_SUCCESS);
87
88 ResetEvent(EventHandle);
89 RtlFillMemory(&IoStatus, sizeof(IoStatus), 0x55);
90 RtlFillMemory(Buffer, sizeof(Buffer), 0x55);
91 Key = BaseKey | StatusKey | KEY_DATA(0x33);
92 Offset.QuadPart = 0;
93 Status = NtReadFile(FileHandle,
94 EventHandle,
95 NULL,
96 NULL,
97 &IoStatus,
98 Buffer,
99 0,
100 &Offset,
101 &Key);
102 WaitStatus = WaitForSingleObject(EventHandle, 0);
103 if (ReturnPending)
104 ok_eq_hex(Status, STATUS_ACCESS_VIOLATION);
105 else
106 ok_eq_hex(Status, STATUS_BUFFER_OVERFLOW);
107 if (Cached && UseFastIo && !ReturnPending)
108 {
109 ok_eq_ulong(WaitStatus, WAIT_OBJECT_0);
110 ok_eq_hex(IoStatus.Status, STATUS_BUFFER_OVERFLOW);
111 ok_eq_ulongptr(IoStatus.Information, TEST_FILE_SIZE);
112 }
113 else
114 {
115 ok_eq_ulong(WaitStatus, WAIT_TIMEOUT);
116 ok_eq_hex(IoStatus.Status, 0x55555555);
117 ok_eq_ulongptr(IoStatus.Information, (ULONG_PTR)0x5555555555555555);
118 }
119 ok_eq_uint(Buffer[0], 0x55);
120
121 ResetEvent(EventHandle);
122 RtlFillMemory(&IoStatus, sizeof(IoStatus), 0x55);
123 RtlFillMemory(Buffer, sizeof(Buffer), 0x55);
124 Key = BaseKey | StatusKey | KEY_DATA(0x44);
125 Offset.QuadPart = 0;
126 Status = NtReadFile(FileHandle,
127 EventHandle,
128 NULL,
129 NULL,
130 &IoStatus,
131 Buffer,
132 sizeof(Buffer),
133 &Offset,
134 &Key);
135 WaitStatus = WaitForSingleObject(EventHandle, 0);
136 ok_eq_hex(Status, TestGetReturnStatus(StatusKey));
137 if ((Cached && UseFastIo && !ReturnPending &&
138 (StatusKey == KEY_SUCCEED || StatusKey == KEY_FAIL_OVERFLOW || StatusKey == KEY_FAIL_EOF)) ||
139 !KEY_ERROR(StatusKey))
140 {
141 ok_eq_ulong(WaitStatus, WAIT_OBJECT_0);
142 ok_eq_hex(IoStatus.Status, TestGetReturnStatus(StatusKey));
143 ok_eq_ulongptr(IoStatus.Information, TEST_FILE_SIZE);
144 }
145 else
146 {
147 ok_eq_ulong(WaitStatus, WAIT_TIMEOUT);
148 ok_eq_hex(IoStatus.Status, 0x55555555);
149 ok_eq_ulongptr(IoStatus.Information, (ULONG_PTR)0x5555555555555555);
150 }
151 if ((StatusKey != KEY_FAIL_VERIFY_REQUIRED && !KEY_ERROR(StatusKey)) ||
152 Cached)
153 {
154 ok_eq_uint(Buffer[0], 0x44);
155 ok_eq_uint(Buffer[TEST_FILE_SIZE - 1], 0x44);
156 ok_eq_uint(Buffer[TEST_FILE_SIZE], 0x55);
157 }
158 else
159 {
160 ok_eq_uint(Buffer[0], 0x55);
161 }
162 }
163 }
164
165 static
166 VOID
TestWrite(_In_ HANDLE FileHandle,_In_ BOOLEAN Cached,_In_ BOOLEAN UseFastIo,_In_ BOOLEAN ReturnPending)167 TestWrite(
168 _In_ HANDLE FileHandle,
169 _In_ BOOLEAN Cached,
170 _In_ BOOLEAN UseFastIo,
171 _In_ BOOLEAN ReturnPending)
172 {
173 NTSTATUS Status;
174 IO_STATUS_BLOCK IoStatus;
175 HANDLE EventHandle;
176 UCHAR Buffer[32];
177 LARGE_INTEGER Offset;
178 ULONG BaseKey, StatusKey, Key;
179 DWORD WaitStatus;
180
181 BaseKey = (UseFastIo ? KEY_USE_FASTIO : 0) |
182 (ReturnPending ? KEY_RETURN_PENDING : 0);
183
184 EventHandle = CreateEventW(NULL, TRUE, FALSE, NULL);
185 ok(EventHandle != NULL, "CreateEvent failed with %lu\n", GetLastError());
186
187 for (StatusKey = KEY_SUCCEED ; StatusKey != 0xff; StatusKey = KEY_NEXT(StatusKey))
188 {
189 //trace("\tSTATUS KEY: %lx\n", StatusKey);
190 ResetEvent(EventHandle);
191 RtlFillMemory(&IoStatus, sizeof(IoStatus), 0x55);
192 Key = BaseKey | StatusKey | KEY_DATA(0x11);
193 Offset.QuadPart = 0;
194 Status = NtWriteFile(FileHandle,
195 EventHandle,
196 NULL,
197 NULL,
198 &IoStatus,
199 NULL,
200 0,
201 &Offset,
202 &Key);
203 WaitStatus = WaitForSingleObject(EventHandle, 0);
204 ok_eq_hex(Status, TestGetReturnStatus(StatusKey));
205 if (!KEY_ERROR(StatusKey))
206 {
207 ok_eq_ulong(WaitStatus, WAIT_OBJECT_0);
208 ok_eq_hex(IoStatus.Status, TestGetReturnStatus(StatusKey));
209 ok_eq_ulongptr(IoStatus.Information, 0);
210 }
211 else
212 {
213 ok_eq_ulong(WaitStatus, WAIT_TIMEOUT);
214 ok_eq_hex(IoStatus.Status, 0x55555555);
215 ok_eq_ulongptr(IoStatus.Information, (ULONG_PTR)0x5555555555555555);
216 }
217
218 KmtStartSeh()
219 ResetEvent(EventHandle);
220 RtlFillMemory(&IoStatus, sizeof(IoStatus), 0x55);
221 Key = BaseKey | StatusKey | KEY_DATA(0x22);
222 Offset.QuadPart = 0;
223 Status = NtWriteFile(FileHandle,
224 EventHandle,
225 NULL,
226 NULL,
227 &IoStatus,
228 NULL,
229 sizeof(Buffer),
230 &Offset,
231 &Key);
232 WaitStatus = WaitForSingleObject(EventHandle, 0);
233 ok_eq_ulong(WaitStatus, WAIT_TIMEOUT);
234 ok_eq_hex(Status, STATUS_ACCESS_VIOLATION);
235 ok_eq_hex(IoStatus.Status, 0x55555555);
236 ok_eq_ulongptr(IoStatus.Information, (ULONG_PTR)0x5555555555555555);
237 KmtEndSeh(STATUS_SUCCESS);
238
239 ResetEvent(EventHandle);
240 RtlFillMemory(&IoStatus, sizeof(IoStatus), 0x55);
241 RtlFillMemory(Buffer, sizeof(Buffer), 0x55);
242 Key = BaseKey | StatusKey | KEY_DATA(0x33);
243 Offset.QuadPart = 0;
244 Status = NtWriteFile(FileHandle,
245 EventHandle,
246 NULL,
247 NULL,
248 &IoStatus,
249 Buffer,
250 0,
251 &Offset,
252 &Key);
253 WaitStatus = WaitForSingleObject(EventHandle, 0);
254 ok_eq_hex(Status, TestGetReturnStatus(StatusKey));
255 if (!KEY_ERROR(StatusKey))
256 {
257 ok_eq_ulong(WaitStatus, WAIT_OBJECT_0);
258 ok_eq_hex(IoStatus.Status, TestGetReturnStatus(StatusKey));
259 ok_eq_ulongptr(IoStatus.Information, 0);
260 }
261 else
262 {
263 ok_eq_ulong(WaitStatus, WAIT_TIMEOUT);
264 ok_eq_hex(IoStatus.Status, 0x55555555);
265 ok_eq_ulongptr(IoStatus.Information, (ULONG_PTR)0x5555555555555555);
266 }
267
268 ResetEvent(EventHandle);
269 RtlFillMemory(&IoStatus, sizeof(IoStatus), 0x55);
270 RtlFillMemory(Buffer, sizeof(Buffer), 0x44);
271 Key = BaseKey | StatusKey | KEY_DATA(0x44);
272 Offset.QuadPart = 0;
273 Status = NtWriteFile(FileHandle,
274 EventHandle,
275 NULL,
276 NULL,
277 &IoStatus,
278 Buffer,
279 sizeof(Buffer),
280 &Offset,
281 &Key);
282 WaitStatus = WaitForSingleObject(EventHandle, 0);
283 ok_eq_hex(Status, TestGetReturnStatus(StatusKey));
284 if (!KEY_ERROR(StatusKey))
285 {
286 ok_eq_ulong(WaitStatus, WAIT_OBJECT_0);
287 ok_eq_hex(IoStatus.Status, TestGetReturnStatus(StatusKey));
288 ok_eq_ulongptr(IoStatus.Information, sizeof(Buffer));
289 }
290 else
291 {
292 ok_eq_ulong(WaitStatus, WAIT_TIMEOUT);
293 ok_eq_hex(IoStatus.Status, 0x55555555);
294 ok_eq_ulongptr(IoStatus.Information, (ULONG_PTR)0x5555555555555555);
295 }
296 }
297 }
298
START_TEST(IoReadWrite)299 START_TEST(IoReadWrite)
300 {
301 HANDLE FileHandle;
302 UNICODE_STRING CachedFileName = RTL_CONSTANT_STRING(L"\\Device\\Kmtest-IoReadWrite\\Cached");
303 UNICODE_STRING NonCachedFileName = RTL_CONSTANT_STRING(L"\\Device\\Kmtest-IoReadWrite\\NonCached");
304 OBJECT_ATTRIBUTES ObjectAttributes;
305 IO_STATUS_BLOCK IoStatus;
306 NTSTATUS Status;
307 DWORD Error;
308
309 Error = KmtLoadAndOpenDriver(L"IoReadWrite", FALSE);
310 ok_eq_int(Error, ERROR_SUCCESS);
311 if (Error)
312 return;
313
314 RtlFillMemory(&IoStatus, sizeof(IoStatus), 0x55);
315 InitializeObjectAttributes(&ObjectAttributes,
316 &NonCachedFileName,
317 OBJ_CASE_INSENSITIVE,
318 NULL,
319 NULL);
320 Status = NtOpenFile(&FileHandle,
321 FILE_ALL_ACCESS,
322 &ObjectAttributes,
323 &IoStatus,
324 0,
325 FILE_NON_DIRECTORY_FILE |
326 FILE_SYNCHRONOUS_IO_NONALERT);
327 ok_eq_hex(Status, STATUS_SUCCESS);
328 if (!skip(NT_SUCCESS(Status), "No file\n"))
329 {
330 ok_eq_hex(IoStatus.Status, STATUS_SUCCESS);
331 ok_eq_ulongptr(IoStatus.Information, FILE_OPENED);
332 trace("Non-Cached read, no FastIo, direct return\n");
333 TestRead(FileHandle, FALSE, FALSE, FALSE);
334 trace("Non-Cached read, allow FastIo, direct return\n");
335 TestRead(FileHandle, FALSE, TRUE, FALSE);
336 trace("Non-Cached read, no FastIo, pending return\n");
337 TestRead(FileHandle, FALSE, FALSE, TRUE);
338 trace("Non-Cached read, allow FastIo, pending return\n");
339 TestRead(FileHandle, FALSE, TRUE, TRUE);
340
341 trace("Non-Cached write, no FastIo, direct return\n");
342 TestWrite(FileHandle, FALSE, FALSE, FALSE);
343 trace("Non-Cached write, allow FastIo, direct return\n");
344 TestWrite(FileHandle, FALSE, TRUE, FALSE);
345 trace("Non-Cached write, no FastIo, pending return\n");
346 TestWrite(FileHandle, FALSE, FALSE, TRUE);
347 trace("Non-Cached write, allow FastIo, pending return\n");
348 TestWrite(FileHandle, FALSE, TRUE, TRUE);
349 NtClose(FileHandle);
350 }
351
352 RtlFillMemory(&IoStatus, sizeof(IoStatus), 0x55);
353 InitializeObjectAttributes(&ObjectAttributes,
354 &CachedFileName,
355 OBJ_CASE_INSENSITIVE,
356 NULL,
357 NULL);
358 Status = NtOpenFile(&FileHandle,
359 FILE_ALL_ACCESS,
360 &ObjectAttributes,
361 &IoStatus,
362 0,
363 FILE_NON_DIRECTORY_FILE |
364 FILE_SYNCHRONOUS_IO_NONALERT);
365 ok_eq_hex(Status, STATUS_SUCCESS);
366 if (!skip(NT_SUCCESS(Status), "No file\n"))
367 {
368 ok_eq_hex(IoStatus.Status, STATUS_SUCCESS);
369 ok_eq_ulongptr(IoStatus.Information, FILE_OPENED);
370 trace("Cached read, no FastIo, direct return\n");
371 TestRead(FileHandle, TRUE, FALSE, FALSE);
372 trace("Cached read, allow FastIo, direct return\n");
373 TestRead(FileHandle, TRUE, TRUE, FALSE);
374 trace("Cached read, no FastIo, pending return\n");
375 TestRead(FileHandle, TRUE, FALSE, TRUE);
376 trace("Cached read, allow FastIo, pending return\n");
377 TestRead(FileHandle, TRUE, TRUE, TRUE);
378
379 trace("Cached write, no FastIo, direct return\n");
380 TestWrite(FileHandle, TRUE, FALSE, FALSE);
381 trace("Cached write, allow FastIo, direct return\n");
382 TestWrite(FileHandle, TRUE, TRUE, FALSE);
383 trace("Cached write, no FastIo, pending return\n");
384 TestWrite(FileHandle, TRUE, FALSE, TRUE);
385 trace("Cached write, allow FastIo, pending return\n");
386 TestWrite(FileHandle, TRUE, TRUE, TRUE);
387 NtClose(FileHandle);
388 }
389
390 KmtCloseDriver();
391 KmtUnloadDriver();
392 }
393