diff --git a/rostests/kmtests/ntos_io/IoReadWrite.h b/rostests/kmtests/ntos_io/IoReadWrite.h index 28001c70414..a306c851d5a 100644 --- a/rostests/kmtests/ntos_io/IoReadWrite.h +++ b/rostests/kmtests/ntos_io/IoReadWrite.h @@ -11,6 +11,10 @@ #define TEST_FILE_SIZE 17 #define KEY_SUCCEED 0x00 +#define KEY_SUCCESS_WAIT1 0x01 + +#define KEY_INFO_EXISTS 0x41 + #define KEY_FAIL_MISALIGNED 0x81 #define KEY_FAIL_OVERFLOW 0x82 #define KEY_FAIL_PARTIAL 0x83 @@ -28,7 +32,8 @@ #define KEY_NEXT(key) ( (key) == KEY_FAIL_MISALIGNED_ERROR ? 0xff : \ (key) == KEY_FAIL_VERIFY_REQUIRED ? KEY_FAIL_UNSUCCESSFUL : \ - (key) == KEY_SUCCEED ? KEY_FAIL_MISALIGNED : \ + (key) == KEY_INFO_EXISTS ? KEY_FAIL_MISALIGNED : \ + (key) == KEY_SUCCESS_WAIT1 ? KEY_INFO_EXISTS : \ (key) + 1 ) #define KEY_ERROR(key) (((key) & 0xc0) == 0xc0) static @@ -40,6 +45,11 @@ TestGetReturnStatus( { case KEY_SUCCEED: return STATUS_SUCCESS; + case KEY_SUCCESS_WAIT1: + return STATUS_WAIT_1; + + case KEY_INFO_EXISTS: + return STATUS_OBJECT_NAME_EXISTS; case KEY_FAIL_MISALIGNED: return STATUS_DATATYPE_MISALIGNMENT; diff --git a/rostests/kmtests/ntos_io/IoReadWrite_drv.c b/rostests/kmtests/ntos_io/IoReadWrite_drv.c index 0c030685005..89bdf91181d 100644 --- a/rostests/kmtests/ntos_io/IoReadWrite_drv.c +++ b/rostests/kmtests/ntos_io/IoReadWrite_drv.c @@ -43,7 +43,9 @@ TestEntry( UNREFERENCED_PARAMETER(RegistryPath); *DeviceName = L"IoReadWrite"; - *Flags = TESTENTRY_NO_EXCLUSIVE_DEVICE | TESTENTRY_BUFFERED_IO_DEVICE; + *Flags = TESTENTRY_NO_EXCLUSIVE_DEVICE | + TESTENTRY_BUFFERED_IO_DEVICE | + TESTENTRY_NO_READONLY_DEVICE; TestFastIoDispatch.FastIoRead = TestFastIoRead; TestFastIoDispatch.FastIoWrite = TestFastIoWrite; @@ -52,7 +54,7 @@ TestEntry( KmtRegisterIrpHandler(IRP_MJ_CREATE, NULL, TestIrpHandler); KmtRegisterIrpHandler(IRP_MJ_CLEANUP, NULL, TestIrpHandler); KmtRegisterIrpHandler(IRP_MJ_READ, NULL, TestIrpHandler); - //KmtRegisterIrpHandler(IRP_MJ_WRITE, NULL, TestIrpHandler); + KmtRegisterIrpHandler(IRP_MJ_WRITE, NULL, TestIrpHandler); return Status; } @@ -187,6 +189,28 @@ TestFastIoRead( return FALSE; } +static +NTSTATUS +TestCommonWrite( + _In_ PVOID Buffer, + _In_ ULONG Length, + _In_ LONGLONG FileOffset, + _In_ ULONG LockKey, + _Out_ PIO_STATUS_BLOCK IoStatus) +{ + ULONG i; + PUCHAR BufferBytes = Buffer; + + for (i = 0; i < Length; i++) + ok(BufferBytes[i] == KEY_GET_DATA(LockKey), "Buffer[%lu] = 0x%x, expected 0x%x\n", i, BufferBytes[i], KEY_GET_DATA(LockKey)); + IoStatus->Status = TestGetReturnStatus(LockKey); + IoStatus->Information = Length; + + if (LockKey & KEY_RETURN_PENDING) + return STATUS_PENDING; + return IoStatus->Status; +} + static BOOLEAN NTAPI @@ -200,9 +224,38 @@ TestFastIoWrite( _Out_ PIO_STATUS_BLOCK IoStatus, _In_ PDEVICE_OBJECT DeviceObject) { + PTEST_FCB Fcb; + NTSTATUS Status; + + //trace("FastIoWrite: %p %lx %p -> %I64d+%lu\n", FileObject, LockKey, Buffer, FileOffset->QuadPart, Length); + ok_eq_pointer(FileObject, TestFileObject); + ok_bool_true(Wait, "Wait is"); + ok_eq_pointer(DeviceObject, TestDeviceObject); + Fcb = FileObject->FsContext; + ok_bool_true(Fcb->Cached, "Cached is"); + TestLastFastWriteKey = LockKey; - UNIMPLEMENTED; - return FALSE; + ok((ULONG_PTR)Buffer < MM_USER_PROBE_ADDRESS, "Buffer is %p\n", Buffer); + ok((ULONG_PTR)FileOffset > MM_USER_PROBE_ADDRESS, "FileOffset is %p\n", FileOffset); + ok((ULONG_PTR)IoStatus > MM_USER_PROBE_ADDRESS, "IoStatus is %p\n", IoStatus); + _SEH2_TRY + { + Status = TestCommonWrite(Buffer, Length, FileOffset->QuadPart, LockKey, IoStatus); + } + _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) + { + IoStatus->Status = _SEH2_GetExceptionCode(); + return FALSE; + } + _SEH2_END; + + if (Status == STATUS_PENDING) + return FALSE; + + if (LockKey & KEY_USE_FASTIO) + return TRUE; + else + return FALSE; } static @@ -291,10 +344,21 @@ TestIrpHandler( } else if (IoStack->MajorFunction == IRP_MJ_WRITE) { + //trace("IRP_MJ_WRITE: %p %lx %I64d+%lu -> %p\n", IoStack->FileObject, IoStack->Parameters.Write.Key, IoStack->Parameters.Write.ByteOffset.QuadPart, IoStack->Parameters.Write.Length, Irp->AssociatedIrp.SystemBuffer); ok_eq_pointer(DeviceObject, TestDeviceObject); ok_eq_pointer(IoStack->FileObject, TestFileObject); - UNIMPLEMENTED; - Status = STATUS_NOT_IMPLEMENTED; + Fcb = IoStack->FileObject->FsContext; + if (Fcb->Cached) + ok_eq_hex(IoStack->Parameters.Write.Key, TestLastFastWriteKey); + ok(Irp->AssociatedIrp.SystemBuffer == NULL || + (ULONG_PTR)Irp->AssociatedIrp.SystemBuffer > MM_USER_PROBE_ADDRESS, + "Buffer is %p\n", + Irp->AssociatedIrp.SystemBuffer); + Status = TestCommonWrite(Irp->AssociatedIrp.SystemBuffer, + IoStack->Parameters.Write.Length, + IoStack->Parameters.Write.ByteOffset.QuadPart, + IoStack->Parameters.Write.Key, + &Irp->IoStatus); } if (Status == STATUS_PENDING) diff --git a/rostests/kmtests/ntos_io/IoReadWrite_user.c b/rostests/kmtests/ntos_io/IoReadWrite_user.c index 429dbc29bc9..e04119bf775 100644 --- a/rostests/kmtests/ntos_io/IoReadWrite_user.c +++ b/rostests/kmtests/ntos_io/IoReadWrite_user.c @@ -32,7 +32,7 @@ TestRead( for (StatusKey = KEY_SUCCEED ; StatusKey != 0xff; StatusKey = KEY_NEXT(StatusKey)) { - trace("\tSTATUS KEY: %lx\n", StatusKey); + //trace("\tSTATUS KEY: %lx\n", StatusKey); ResetEvent(EventHandle); RtlFillMemory(&IoStatus, sizeof(IoStatus), 0x55); Key = BaseKey | StatusKey | KEY_DATA(0x11); @@ -162,6 +162,140 @@ TestRead( } } +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; @@ -192,14 +326,23 @@ START_TEST(IoReadWrite) { ok_eq_hex(IoStatus.Status, STATUS_SUCCESS); ok_eq_ulongptr(IoStatus.Information, FILE_OPENED); - trace("Non-Cached, no FastIo, direct return\n"); + trace("Non-Cached read, no FastIo, direct return\n"); TestRead(FileHandle, FALSE, FALSE, FALSE); - trace("Non-Cached, allow FastIo, direct return\n"); + trace("Non-Cached read, allow FastIo, direct return\n"); TestRead(FileHandle, FALSE, TRUE, FALSE); - trace("Non-Cached, no FastIo, pending return\n"); + trace("Non-Cached read, no FastIo, pending return\n"); TestRead(FileHandle, FALSE, FALSE, TRUE); - trace("Non-Cached, allow FastIo, pending return\n"); + 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); } @@ -221,14 +364,23 @@ START_TEST(IoReadWrite) { ok_eq_hex(IoStatus.Status, STATUS_SUCCESS); ok_eq_ulongptr(IoStatus.Information, FILE_OPENED); - trace("Cached, no FastIo, direct return\n"); + trace("Cached read, no FastIo, direct return\n"); TestRead(FileHandle, TRUE, FALSE, FALSE); - trace("Cached, allow FastIo, direct return\n"); + trace("Cached read, allow FastIo, direct return\n"); TestRead(FileHandle, TRUE, TRUE, FALSE); - trace("Cached, no FastIo, pending return\n"); + trace("Cached read, no FastIo, pending return\n"); TestRead(FileHandle, TRUE, FALSE, TRUE); - trace("Cached, allow FastIo, pending return\n"); + 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); }