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
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
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 
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 
308     KmtLoadDriver(L"IoReadWrite", FALSE);
309     KmtOpenDriver();
310 
311     RtlFillMemory(&IoStatus, sizeof(IoStatus), 0x55);
312     InitializeObjectAttributes(&ObjectAttributes,
313                                &NonCachedFileName,
314                                OBJ_CASE_INSENSITIVE,
315                                NULL,
316                                NULL);
317     Status = NtOpenFile(&FileHandle,
318                         FILE_ALL_ACCESS,
319                         &ObjectAttributes,
320                         &IoStatus,
321                         0,
322                         FILE_NON_DIRECTORY_FILE |
323                         FILE_SYNCHRONOUS_IO_NONALERT);
324     ok_eq_hex(Status, STATUS_SUCCESS);
325     if (!skip(NT_SUCCESS(Status), "No file\n"))
326     {
327         ok_eq_hex(IoStatus.Status, STATUS_SUCCESS);
328         ok_eq_ulongptr(IoStatus.Information, FILE_OPENED);
329         trace("Non-Cached read, no FastIo, direct return\n");
330         TestRead(FileHandle, FALSE, FALSE, FALSE);
331         trace("Non-Cached read, allow FastIo, direct return\n");
332         TestRead(FileHandle, FALSE, TRUE, FALSE);
333         trace("Non-Cached read, no FastIo, pending return\n");
334         TestRead(FileHandle, FALSE, FALSE, TRUE);
335         trace("Non-Cached read, allow FastIo, pending return\n");
336         TestRead(FileHandle, FALSE, TRUE, TRUE);
337 
338         trace("Non-Cached write, no FastIo, direct return\n");
339         TestWrite(FileHandle, FALSE, FALSE, FALSE);
340         trace("Non-Cached write, allow FastIo, direct return\n");
341         TestWrite(FileHandle, FALSE, TRUE, FALSE);
342         trace("Non-Cached write, no FastIo, pending return\n");
343         TestWrite(FileHandle, FALSE, FALSE, TRUE);
344         trace("Non-Cached write, allow FastIo, pending return\n");
345         TestWrite(FileHandle, FALSE, TRUE, TRUE);
346         NtClose(FileHandle);
347     }
348 
349     RtlFillMemory(&IoStatus, sizeof(IoStatus), 0x55);
350     InitializeObjectAttributes(&ObjectAttributes,
351                                &CachedFileName,
352                                OBJ_CASE_INSENSITIVE,
353                                NULL,
354                                NULL);
355     Status = NtOpenFile(&FileHandle,
356                         FILE_ALL_ACCESS,
357                         &ObjectAttributes,
358                         &IoStatus,
359                         0,
360                         FILE_NON_DIRECTORY_FILE |
361                         FILE_SYNCHRONOUS_IO_NONALERT);
362     ok_eq_hex(Status, STATUS_SUCCESS);
363     if (!skip(NT_SUCCESS(Status), "No file\n"))
364     {
365         ok_eq_hex(IoStatus.Status, STATUS_SUCCESS);
366         ok_eq_ulongptr(IoStatus.Information, FILE_OPENED);
367         trace("Cached read, no FastIo, direct return\n");
368         TestRead(FileHandle, TRUE, FALSE, FALSE);
369         trace("Cached read, allow FastIo, direct return\n");
370         TestRead(FileHandle, TRUE, TRUE, FALSE);
371         trace("Cached read, no FastIo, pending return\n");
372         TestRead(FileHandle, TRUE, FALSE, TRUE);
373         trace("Cached read, allow FastIo, pending return\n");
374         TestRead(FileHandle, TRUE, TRUE, TRUE);
375 
376         trace("Cached write, no FastIo, direct return\n");
377         TestWrite(FileHandle, TRUE, FALSE, FALSE);
378         trace("Cached write, allow FastIo, direct return\n");
379         TestWrite(FileHandle, TRUE, TRUE, FALSE);
380         trace("Cached write, no FastIo, pending return\n");
381         TestWrite(FileHandle, TRUE, FALSE, TRUE);
382         trace("Cached write, allow FastIo, pending return\n");
383         TestWrite(FileHandle, TRUE, TRUE, TRUE);
384         NtClose(FileHandle);
385     }
386 
387     KmtCloseDriver();
388     KmtUnloadDriver();
389 }
390