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