--- /dev/null
+/*
+ * PROJECT: ReactOS kernel-mode tests
+ * LICENSE: LGPLv2.1+ - See COPYING.LIB in the top level directory
+ * PURPOSE: Test driver for CcCopyRead function
+ * PROGRAMMER: Pierre Schweitzer <pierre@reactos.org>
+ */
+
+#include <kmt_test.h>
+
+#define NDEBUG
+#include <debug.h>
+
+typedef struct _TEST_FCB
+{
+ FSRTL_ADVANCED_FCB_HEADER Header;
+ SECTION_OBJECT_POINTERS SectionObjectPointers;
+ FAST_MUTEX HeaderMutex;
+} TEST_FCB, *PTEST_FCB;
+
+static PFILE_OBJECT TestFileObject;
+static PDEVICE_OBJECT TestDeviceObject;
+static KMT_IRP_HANDLER TestIrpHandler;
+static FAST_IO_DISPATCH TestFastIoDispatch;
+
+static
+BOOLEAN
+NTAPI
+FastIoRead(
+ _In_ PFILE_OBJECT FileObject,
+ _In_ PLARGE_INTEGER FileOffset,
+ _In_ ULONG Length,
+ _In_ BOOLEAN Wait,
+ _In_ ULONG LockKey,
+ _Out_ PVOID Buffer,
+ _Out_ PIO_STATUS_BLOCK IoStatus,
+ _In_ PDEVICE_OBJECT DeviceObject)
+{
+ IoStatus->Status = STATUS_NOT_SUPPORTED;
+ return FALSE;
+}
+
+NTSTATUS
+TestEntry(
+ _In_ PDRIVER_OBJECT DriverObject,
+ _In_ PCUNICODE_STRING RegistryPath,
+ _Out_ PCWSTR *DeviceName,
+ _Inout_ INT *Flags)
+{
+ NTSTATUS Status = STATUS_SUCCESS;
+
+ PAGED_CODE();
+
+ UNREFERENCED_PARAMETER(RegistryPath);
+
+ *DeviceName = L"CcCopyRead";
+ *Flags = TESTENTRY_NO_EXCLUSIVE_DEVICE |
+ TESTENTRY_BUFFERED_IO_DEVICE |
+ TESTENTRY_NO_READONLY_DEVICE;
+
+ KmtRegisterIrpHandler(IRP_MJ_CLEANUP, NULL, TestIrpHandler);
+ KmtRegisterIrpHandler(IRP_MJ_CREATE, NULL, TestIrpHandler);
+ KmtRegisterIrpHandler(IRP_MJ_READ, NULL, TestIrpHandler);
+
+ TestFastIoDispatch.FastIoRead = FastIoRead;
+ DriverObject->FastIoDispatch = &TestFastIoDispatch;
+
+
+ return Status;
+}
+
+VOID
+TestUnload(
+ _In_ PDRIVER_OBJECT DriverObject)
+{
+ PAGED_CODE();
+}
+
+BOOLEAN
+NTAPI
+AcquireForLazyWrite(
+ _In_ PVOID Context,
+ _In_ BOOLEAN Wait)
+{
+ return TRUE;
+}
+
+VOID
+NTAPI
+ReleaseFromLazyWrite(
+ _In_ PVOID Context)
+{
+ return;
+}
+
+BOOLEAN
+NTAPI
+AcquireForReadAhead(
+ _In_ PVOID Context,
+ _In_ BOOLEAN Wait)
+{
+ return TRUE;
+}
+
+VOID
+NTAPI
+ReleaseFromReadAhead(
+ _In_ PVOID Context)
+{
+ return;
+}
+
+static CACHE_MANAGER_CALLBACKS Callbacks = {
+ AcquireForLazyWrite,
+ ReleaseFromLazyWrite,
+ AcquireForReadAhead,
+ ReleaseFromReadAhead,
+};
+
+static
+PVOID
+MapUserBuffer(
+ _In_ _Out_ PIRP Irp)
+{
+ if (Irp->MdlAddress == NULL)
+ {
+ return Irp->UserBuffer;
+ }
+ else
+ {
+ return MmGetSystemAddressForMdlSafe(Irp->MdlAddress, NormalPagePriority);
+ }
+}
+
+
+static
+NTSTATUS
+TestIrpHandler(
+ _In_ PDEVICE_OBJECT DeviceObject,
+ _In_ PIRP Irp,
+ _In_ PIO_STACK_LOCATION IoStack)
+{
+ NTSTATUS Status;
+ PTEST_FCB Fcb;
+ CACHE_UNINITIALIZE_EVENT CacheUninitEvent;
+
+ PAGED_CODE();
+
+ DPRINT("IRP %x/%x\n", IoStack->MajorFunction, IoStack->MinorFunction);
+ ASSERT(IoStack->MajorFunction == IRP_MJ_CLEANUP ||
+ IoStack->MajorFunction == IRP_MJ_CREATE ||
+ IoStack->MajorFunction == IRP_MJ_READ);
+
+ Status = STATUS_NOT_SUPPORTED;
+ Irp->IoStatus.Information = 0;
+
+ if (IoStack->MajorFunction == IRP_MJ_CREATE)
+ {
+ if (IoStack->FileObject->FileName.Length >= 2 * sizeof(WCHAR))
+ {
+ TestDeviceObject = DeviceObject;
+ TestFileObject = IoStack->FileObject;
+ }
+ Fcb = ExAllocatePoolWithTag(NonPagedPool, sizeof(*Fcb), 'FwrI');
+ RtlZeroMemory(Fcb, sizeof(*Fcb));
+ ExInitializeFastMutex(&Fcb->HeaderMutex);
+ FsRtlSetupAdvancedHeader(&Fcb->Header, &Fcb->HeaderMutex);
+ if (IoStack->FileObject->FileName.Length >= 2 * sizeof(WCHAR) &&
+ IoStack->FileObject->FileName.Buffer[1] == 'B')
+ {
+ Fcb->Header.AllocationSize.QuadPart = 1000000;
+ Fcb->Header.FileSize.QuadPart = 1000000;
+ Fcb->Header.ValidDataLength.QuadPart = 1000000;
+ }
+ else if (IoStack->FileObject->FileName.Length >= 2 * sizeof(WCHAR) &&
+ IoStack->FileObject->FileName.Buffer[1] == 'S')
+ {
+ Fcb->Header.AllocationSize.QuadPart = 3000;
+ Fcb->Header.FileSize.QuadPart = 3000;
+ Fcb->Header.ValidDataLength.QuadPart = 3000;
+ }
+ else
+ {
+ Fcb->Header.AllocationSize.QuadPart = 512;
+ Fcb->Header.FileSize.QuadPart = 512;
+ Fcb->Header.ValidDataLength.QuadPart = 512;
+ }
+ Fcb->Header.IsFastIoPossible = FALSE;
+ IoStack->FileObject->FsContext = Fcb;
+ IoStack->FileObject->SectionObjectPointer = &Fcb->SectionObjectPointers;
+
+ CcInitializeCacheMap(IoStack->FileObject,
+ (PCC_FILE_SIZES)&Fcb->Header.AllocationSize,
+ FALSE, &Callbacks, NULL);
+
+ Irp->IoStatus.Information = FILE_OPENED;
+ Status = STATUS_SUCCESS;
+ }
+ else if (IoStack->MajorFunction == IRP_MJ_READ)
+ {
+ BOOLEAN Ret;
+ ULONG Length;
+ PVOID Buffer;
+ LARGE_INTEGER Offset;
+
+ Offset = IoStack->Parameters.Read.ByteOffset;
+ Length = IoStack->Parameters.Read.Length;
+ Fcb = IoStack->FileObject->FsContext;
+
+ ok_eq_pointer(DeviceObject, TestDeviceObject);
+ ok_eq_pointer(IoStack->FileObject, TestFileObject);
+
+ if (!FlagOn(Irp->Flags, IRP_NOCACHE))
+ {
+ ok(Offset.QuadPart % 512 != 0, "Offset is aligned: %I64i\n", Offset.QuadPart);
+ ok(Length % 512 != 0, "Length is aligned: %I64i\n", Length);
+
+ Buffer = MapUserBuffer(Irp);
+ ok(Buffer != NULL, "Null pointer!\n");
+
+ _SEH2_TRY
+ {
+ Ret = CcCopyRead(IoStack->FileObject, &Offset, Length, TRUE, Buffer,
+ &Irp->IoStatus);
+ ok_bool_true(Ret, "CcCopyRead");
+ }
+ _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
+ {
+ Irp->IoStatus.Status = _SEH2_GetExceptionCode();
+ }
+ _SEH2_END;
+
+ Status = Irp->IoStatus.Status;
+ }
+ else
+ {
+ ok(Offset.QuadPart % 512 == 0, "Offset is not aligned: %I64i\n", Offset.QuadPart);
+ ok(Length % 512 == 0, "Length is not aligned: %I64i\n", Length);
+
+ Status = STATUS_SUCCESS;
+ }
+
+ if (NT_SUCCESS(Status))
+ {
+ Irp->IoStatus.Information = Length;
+ IoStack->FileObject->CurrentByteOffset.QuadPart = Offset.QuadPart + Length;
+ }
+ }
+ else if (IoStack->MajorFunction == IRP_MJ_CLEANUP)
+ {
+ KeInitializeEvent(&CacheUninitEvent.Event, NotificationEvent, FALSE);
+ CcUninitializeCacheMap(IoStack->FileObject, NULL, &CacheUninitEvent);
+ KeWaitForSingleObject(&CacheUninitEvent.Event, Executive, KernelMode, FALSE, NULL);
+ Fcb = IoStack->FileObject->FsContext;
+ ExFreePoolWithTag(Fcb, 'FwrI');
+ IoStack->FileObject->FsContext = NULL;
+ Status = STATUS_SUCCESS;
+ }
+
+ if (Status == STATUS_PENDING)
+ {
+ IoMarkIrpPending(Irp);
+ IoCompleteRequest(Irp, IO_NO_INCREMENT);
+ Status = STATUS_PENDING;
+ }
+ else
+ {
+ Irp->IoStatus.Status = Status;
+ IoCompleteRequest(Irp, IO_NO_INCREMENT);
+ }
+
+ return Status;
+}
--- /dev/null
+/*
+ * PROJECT: ReactOS kernel-mode tests
+ * LICENSE: GPLv2+ - See COPYING in the top level directory
+ * PURPOSE: Kernel-Mode Test Suite CcCopyRead test user-mode part
+ * PROGRAMMER: Pierre Schweitzer <pierre@reactos.org>
+ */
+
+#include <kmt_test.h>
+
+START_TEST(CcCopyRead)
+{
+ HANDLE Handle;
+ NTSTATUS Status;
+ LARGE_INTEGER ByteOffset;
+ IO_STATUS_BLOCK IoStatusBlock;
+ OBJECT_ATTRIBUTES ObjectAttributes;
+ PVOID Buffer = RtlAllocateHeap(RtlGetProcessHeap(), 0, 1024);
+ UNICODE_STRING BigAlignmentTest = RTL_CONSTANT_STRING(L"\\Device\\Kmtest-CcCopyRead\\BigAlignmentTest");
+ UNICODE_STRING SmallAlignmentTest = RTL_CONSTANT_STRING(L"\\Device\\Kmtest-CcCopyRead\\SmallAlignmentTest");
+
+ KmtLoadDriver(L"CcCopyRead", FALSE);
+ KmtOpenDriver();
+
+ InitializeObjectAttributes(&ObjectAttributes, &SmallAlignmentTest, OBJ_CASE_INSENSITIVE, NULL, NULL);
+ Status = NtOpenFile(&Handle, FILE_ALL_ACCESS, &ObjectAttributes, &IoStatusBlock, 0, FILE_NON_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT);
+ ok_eq_hex(Status, STATUS_SUCCESS);
+
+ ByteOffset.QuadPart = 3;
+ Status = NtReadFile(Handle, NULL, NULL, NULL, &IoStatusBlock, Buffer, 3, &ByteOffset, NULL);
+ ok_eq_hex(Status, STATUS_SUCCESS);
+
+ ByteOffset.QuadPart = 514;
+ Status = NtReadFile(Handle, NULL, NULL, NULL, &IoStatusBlock, Buffer, 514, &ByteOffset, NULL);
+ ok_eq_hex(Status, STATUS_SUCCESS);
+
+ NtClose(Handle);
+
+ InitializeObjectAttributes(&ObjectAttributes, &BigAlignmentTest, OBJ_CASE_INSENSITIVE, NULL, NULL);
+ Status = NtOpenFile(&Handle, FILE_ALL_ACCESS, &ObjectAttributes, &IoStatusBlock, 0, FILE_NON_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT);
+ ok_eq_hex(Status, STATUS_SUCCESS);
+
+ ByteOffset.QuadPart = 3;
+ Status = NtReadFile(Handle, NULL, NULL, NULL, &IoStatusBlock, Buffer, 3, &ByteOffset, NULL);
+ ok_eq_hex(Status, STATUS_SUCCESS);
+
+ ByteOffset.QuadPart = 514;
+ Status = NtReadFile(Handle, NULL, NULL, NULL, &IoStatusBlock, Buffer, 514, &ByteOffset, NULL);
+ ok_eq_hex(Status, STATUS_SUCCESS);
+
+ ByteOffset.QuadPart = 300000;
+ Status = NtReadFile(Handle, NULL, NULL, NULL, &IoStatusBlock, Buffer, 10, &ByteOffset, NULL);
+ ok_eq_hex(Status, STATUS_SUCCESS);
+
+ NtClose(Handle);
+
+ RtlFreeHeap(RtlGetProcessHeap(), 0, Buffer);
+ KmtCloseDriver();
+ KmtUnloadDriver();
+}