/* * PROJECT: ReactOS kernel-mode tests * LICENSE: LGPLv2.1+ - See COPYING.LIB in the top level directory * PURPOSE: Test for Read/Write operations * PROGRAMMER: Thomas Faber */ #include #include "IoReadWrite.h" static VOID TestRead( _In_ HANDLE FileHandle, _In_ BOOLEAN Cached, _In_ BOOLEAN UseFastIo, _In_ BOOLEAN ReturnPending) { NTSTATUS Status; IO_STATUS_BLOCK IoStatus; HANDLE EventHandle; UCHAR Buffer[32]; LARGE_INTEGER Offset; ULONG BaseKey, StatusKey, Key; DWORD WaitStatus; BaseKey = (UseFastIo ? KEY_USE_FASTIO : 0) | (ReturnPending ? KEY_RETURN_PENDING : 0); EventHandle = CreateEventW(NULL, TRUE, FALSE, NULL); ok(EventHandle != NULL, "CreateEvent failed with %lu\n", GetLastError()); for (StatusKey = KEY_SUCCEED ; StatusKey != 0xff; StatusKey = KEY_NEXT(StatusKey)) { //trace("\tSTATUS KEY: %lx\n", StatusKey); ResetEvent(EventHandle); RtlFillMemory(&IoStatus, sizeof(IoStatus), 0x55); Key = BaseKey | StatusKey | KEY_DATA(0x11); Offset.QuadPart = 0; Status = NtReadFile(FileHandle, EventHandle, NULL, NULL, &IoStatus, NULL, 0, &Offset, &Key); WaitStatus = WaitForSingleObject(EventHandle, 0); if (ReturnPending) ok_eq_hex(Status, STATUS_ACCESS_VIOLATION); else ok_eq_hex(Status, STATUS_BUFFER_OVERFLOW); if (Cached && UseFastIo && !ReturnPending) { ok_eq_ulong(WaitStatus, WAIT_OBJECT_0); ok_eq_hex(IoStatus.Status, STATUS_BUFFER_OVERFLOW); ok_eq_ulongptr(IoStatus.Information, TEST_FILE_SIZE); } else { ok_eq_ulong(WaitStatus, WAIT_TIMEOUT); ok_eq_hex(IoStatus.Status, 0x55555555); ok_eq_ulongptr(IoStatus.Information, (ULONG_PTR)0x5555555555555555); } KmtStartSeh() ResetEvent(EventHandle); RtlFillMemory(&IoStatus, sizeof(IoStatus), 0x55); Key = BaseKey | StatusKey | KEY_DATA(0x22); Offset.QuadPart = 0; Status = NtReadFile(FileHandle, EventHandle, NULL, NULL, &IoStatus, NULL, sizeof(Buffer), &Offset, &Key); WaitStatus = WaitForSingleObject(EventHandle, 0); ok_eq_ulong(WaitStatus, WAIT_TIMEOUT); ok_eq_hex(Status, STATUS_ACCESS_VIOLATION); ok_eq_hex(IoStatus.Status, 0x55555555); ok_eq_ulongptr(IoStatus.Information, (ULONG_PTR)0x5555555555555555); KmtEndSeh(STATUS_SUCCESS); ResetEvent(EventHandle); RtlFillMemory(&IoStatus, sizeof(IoStatus), 0x55); RtlFillMemory(Buffer, sizeof(Buffer), 0x55); Key = BaseKey | StatusKey | KEY_DATA(0x33); Offset.QuadPart = 0; Status = NtReadFile(FileHandle, EventHandle, NULL, NULL, &IoStatus, Buffer, 0, &Offset, &Key); WaitStatus = WaitForSingleObject(EventHandle, 0); if (ReturnPending) ok_eq_hex(Status, STATUS_ACCESS_VIOLATION); else ok_eq_hex(Status, STATUS_BUFFER_OVERFLOW); if (Cached && UseFastIo && !ReturnPending) { ok_eq_ulong(WaitStatus, WAIT_OBJECT_0); ok_eq_hex(IoStatus.Status, STATUS_BUFFER_OVERFLOW); ok_eq_ulongptr(IoStatus.Information, TEST_FILE_SIZE); } else { ok_eq_ulong(WaitStatus, WAIT_TIMEOUT); ok_eq_hex(IoStatus.Status, 0x55555555); ok_eq_ulongptr(IoStatus.Information, (ULONG_PTR)0x5555555555555555); } ok_eq_uint(Buffer[0], 0x55); ResetEvent(EventHandle); RtlFillMemory(&IoStatus, sizeof(IoStatus), 0x55); RtlFillMemory(Buffer, sizeof(Buffer), 0x55); Key = BaseKey | StatusKey | KEY_DATA(0x44); Offset.QuadPart = 0; Status = NtReadFile(FileHandle, EventHandle, NULL, NULL, &IoStatus, Buffer, sizeof(Buffer), &Offset, &Key); WaitStatus = WaitForSingleObject(EventHandle, 0); ok_eq_hex(Status, TestGetReturnStatus(StatusKey)); if ((Cached && UseFastIo && !ReturnPending && (StatusKey == KEY_SUCCEED || StatusKey == KEY_FAIL_OVERFLOW || StatusKey == KEY_FAIL_EOF)) || !KEY_ERROR(StatusKey)) { ok_eq_ulong(WaitStatus, WAIT_OBJECT_0); ok_eq_hex(IoStatus.Status, TestGetReturnStatus(StatusKey)); ok_eq_ulongptr(IoStatus.Information, TEST_FILE_SIZE); } else { ok_eq_ulong(WaitStatus, WAIT_TIMEOUT); ok_eq_hex(IoStatus.Status, 0x55555555); ok_eq_ulongptr(IoStatus.Information, (ULONG_PTR)0x5555555555555555); } if ((StatusKey != KEY_FAIL_VERIFY_REQUIRED && !KEY_ERROR(StatusKey)) || Cached) { ok_eq_uint(Buffer[0], 0x44); ok_eq_uint(Buffer[TEST_FILE_SIZE - 1], 0x44); ok_eq_uint(Buffer[TEST_FILE_SIZE], 0x55); } else { ok_eq_uint(Buffer[0], 0x55); } } } static VOID TestWrite( _In_ HANDLE FileHandle, _In_ BOOLEAN Cached, _In_ BOOLEAN UseFastIo, _In_ BOOLEAN ReturnPending) { NTSTATUS Status; IO_STATUS_BLOCK IoStatus; HANDLE EventHandle; UCHAR Buffer[32]; LARGE_INTEGER Offset; ULONG BaseKey, StatusKey, Key; DWORD WaitStatus; BaseKey = (UseFastIo ? KEY_USE_FASTIO : 0) | (ReturnPending ? KEY_RETURN_PENDING : 0); EventHandle = CreateEventW(NULL, TRUE, FALSE, NULL); ok(EventHandle != NULL, "CreateEvent failed with %lu\n", GetLastError()); for (StatusKey = KEY_SUCCEED ; StatusKey != 0xff; StatusKey = KEY_NEXT(StatusKey)) { //trace("\tSTATUS KEY: %lx\n", StatusKey); ResetEvent(EventHandle); RtlFillMemory(&IoStatus, sizeof(IoStatus), 0x55); Key = BaseKey | StatusKey | KEY_DATA(0x11); Offset.QuadPart = 0; Status = NtWriteFile(FileHandle, EventHandle, NULL, NULL, &IoStatus, NULL, 0, &Offset, &Key); WaitStatus = WaitForSingleObject(EventHandle, 0); ok_eq_hex(Status, TestGetReturnStatus(StatusKey)); if (!KEY_ERROR(StatusKey)) { ok_eq_ulong(WaitStatus, WAIT_OBJECT_0); ok_eq_hex(IoStatus.Status, TestGetReturnStatus(StatusKey)); ok_eq_ulongptr(IoStatus.Information, 0); } else { ok_eq_ulong(WaitStatus, WAIT_TIMEOUT); ok_eq_hex(IoStatus.Status, 0x55555555); ok_eq_ulongptr(IoStatus.Information, (ULONG_PTR)0x5555555555555555); } KmtStartSeh() ResetEvent(EventHandle); RtlFillMemory(&IoStatus, sizeof(IoStatus), 0x55); Key = BaseKey | StatusKey | KEY_DATA(0x22); Offset.QuadPart = 0; Status = NtWriteFile(FileHandle, EventHandle, NULL, NULL, &IoStatus, NULL, sizeof(Buffer), &Offset, &Key); WaitStatus = WaitForSingleObject(EventHandle, 0); ok_eq_ulong(WaitStatus, WAIT_TIMEOUT); ok_eq_hex(Status, STATUS_ACCESS_VIOLATION); ok_eq_hex(IoStatus.Status, 0x55555555); ok_eq_ulongptr(IoStatus.Information, (ULONG_PTR)0x5555555555555555); KmtEndSeh(STATUS_SUCCESS); ResetEvent(EventHandle); RtlFillMemory(&IoStatus, sizeof(IoStatus), 0x55); RtlFillMemory(Buffer, sizeof(Buffer), 0x55); Key = BaseKey | StatusKey | KEY_DATA(0x33); Offset.QuadPart = 0; Status = NtWriteFile(FileHandle, EventHandle, NULL, NULL, &IoStatus, Buffer, 0, &Offset, &Key); WaitStatus = WaitForSingleObject(EventHandle, 0); ok_eq_hex(Status, TestGetReturnStatus(StatusKey)); if (!KEY_ERROR(StatusKey)) { ok_eq_ulong(WaitStatus, WAIT_OBJECT_0); ok_eq_hex(IoStatus.Status, TestGetReturnStatus(StatusKey)); ok_eq_ulongptr(IoStatus.Information, 0); } else { ok_eq_ulong(WaitStatus, WAIT_TIMEOUT); ok_eq_hex(IoStatus.Status, 0x55555555); ok_eq_ulongptr(IoStatus.Information, (ULONG_PTR)0x5555555555555555); } ResetEvent(EventHandle); RtlFillMemory(&IoStatus, sizeof(IoStatus), 0x55); RtlFillMemory(Buffer, sizeof(Buffer), 0x44); Key = BaseKey | StatusKey | KEY_DATA(0x44); Offset.QuadPart = 0; Status = NtWriteFile(FileHandle, EventHandle, NULL, NULL, &IoStatus, Buffer, sizeof(Buffer), &Offset, &Key); WaitStatus = WaitForSingleObject(EventHandle, 0); ok_eq_hex(Status, TestGetReturnStatus(StatusKey)); if (!KEY_ERROR(StatusKey)) { ok_eq_ulong(WaitStatus, WAIT_OBJECT_0); ok_eq_hex(IoStatus.Status, TestGetReturnStatus(StatusKey)); ok_eq_ulongptr(IoStatus.Information, sizeof(Buffer)); } else { ok_eq_ulong(WaitStatus, WAIT_TIMEOUT); ok_eq_hex(IoStatus.Status, 0x55555555); ok_eq_ulongptr(IoStatus.Information, (ULONG_PTR)0x5555555555555555); } } } START_TEST(IoReadWrite) { HANDLE FileHandle; UNICODE_STRING CachedFileName = RTL_CONSTANT_STRING(L"\\Device\\Kmtest-IoReadWrite\\Cached"); UNICODE_STRING NonCachedFileName = RTL_CONSTANT_STRING(L"\\Device\\Kmtest-IoReadWrite\\NonCached"); OBJECT_ATTRIBUTES ObjectAttributes; IO_STATUS_BLOCK IoStatus; NTSTATUS Status; KmtLoadDriver(L"IoReadWrite", FALSE); KmtOpenDriver(); RtlFillMemory(&IoStatus, sizeof(IoStatus), 0x55); InitializeObjectAttributes(&ObjectAttributes, &NonCachedFileName, OBJ_CASE_INSENSITIVE, NULL, NULL); Status = NtOpenFile(&FileHandle, FILE_ALL_ACCESS, &ObjectAttributes, &IoStatus, 0, FILE_NON_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT); ok_eq_hex(Status, STATUS_SUCCESS); if (!skip(NT_SUCCESS(Status), "No file\n")) { ok_eq_hex(IoStatus.Status, STATUS_SUCCESS); ok_eq_ulongptr(IoStatus.Information, FILE_OPENED); trace("Non-Cached read, no FastIo, direct return\n"); TestRead(FileHandle, FALSE, FALSE, FALSE); trace("Non-Cached read, allow FastIo, direct return\n"); TestRead(FileHandle, FALSE, TRUE, FALSE); trace("Non-Cached read, no FastIo, pending return\n"); TestRead(FileHandle, FALSE, FALSE, TRUE); trace("Non-Cached read, allow FastIo, pending return\n"); TestRead(FileHandle, FALSE, TRUE, TRUE); trace("Non-Cached write, no FastIo, direct return\n"); TestWrite(FileHandle, FALSE, FALSE, FALSE); trace("Non-Cached write, allow FastIo, direct return\n"); TestWrite(FileHandle, FALSE, TRUE, FALSE); trace("Non-Cached write, no FastIo, pending return\n"); TestWrite(FileHandle, FALSE, FALSE, TRUE); trace("Non-Cached write, allow FastIo, pending return\n"); TestWrite(FileHandle, FALSE, TRUE, TRUE); NtClose(FileHandle); } RtlFillMemory(&IoStatus, sizeof(IoStatus), 0x55); InitializeObjectAttributes(&ObjectAttributes, &CachedFileName, OBJ_CASE_INSENSITIVE, NULL, NULL); Status = NtOpenFile(&FileHandle, FILE_ALL_ACCESS, &ObjectAttributes, &IoStatus, 0, FILE_NON_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT); ok_eq_hex(Status, STATUS_SUCCESS); if (!skip(NT_SUCCESS(Status), "No file\n")) { ok_eq_hex(IoStatus.Status, STATUS_SUCCESS); ok_eq_ulongptr(IoStatus.Information, FILE_OPENED); trace("Cached read, no FastIo, direct return\n"); TestRead(FileHandle, TRUE, FALSE, FALSE); trace("Cached read, allow FastIo, direct return\n"); TestRead(FileHandle, TRUE, TRUE, FALSE); trace("Cached read, no FastIo, pending return\n"); TestRead(FileHandle, TRUE, FALSE, TRUE); trace("Cached read, allow FastIo, pending return\n"); TestRead(FileHandle, TRUE, TRUE, TRUE); trace("Cached write, no FastIo, direct return\n"); TestWrite(FileHandle, TRUE, FALSE, FALSE); trace("Cached write, allow FastIo, direct return\n"); TestWrite(FileHandle, TRUE, TRUE, FALSE); trace("Cached write, no FastIo, pending return\n"); TestWrite(FileHandle, TRUE, FALSE, TRUE); trace("Cached write, allow FastIo, pending return\n"); TestWrite(FileHandle, TRUE, TRUE, TRUE); NtClose(FileHandle); } KmtCloseDriver(); KmtUnloadDriver(); }