[KMTESTS:IO]
authorPierre Schweitzer <pierre@reactos.org>
Tue, 22 Sep 2015 22:31:08 +0000 (22:31 +0000)
committerPierre Schweitzer <pierre@reactos.org>
Tue, 22 Sep 2015 22:31:08 +0000 (22:31 +0000)
Extend the IoCreateFile tests with two parts tests.
First part properly checks for opening/reparse handling on mount points (and ideally on symlinks, see below).
The other part checks for proper handling of the IO_STOP_ON_SYMLINK parameter.

Regarding symlink, I'm clearly not convinced that what I did is correct (hence the failure on both W2K3 & ROS). It seems to me that symlink resolution is up to the FSD and not to IO which only handles mount point traversal.
If someone (Alex?) can confirm/infirm and give more insight, that's more than welcome.

svn path=/trunk/; revision=69322

rostests/kmtests/CMakeLists.txt
rostests/kmtests/kmtest/testlist.c
rostests/kmtests/ntos_io/CMakeLists.txt
rostests/kmtests/ntos_io/IoCreateFile.h [new file with mode: 0644]
rostests/kmtests/ntos_io/IoCreateFile_drv.c [new file with mode: 0644]
rostests/kmtests/ntos_io/IoCreateFile_user.c [new file with mode: 0644]

index 2093302..b9741b4 100644 (file)
@@ -111,6 +111,7 @@ list(APPEND KMTEST_SOURCE
 
     example/Example_user.c
     kernel32/FindFile_user.c
+    ntos_io/IoCreateFile_user.c
     ntos_io/IoDeviceObject_user.c
     ntos_io/IoReadWrite_user.c
     tcpip/TcpIp_user.c
@@ -134,6 +135,7 @@ add_custom_target(kmtest_drivers)
 add_dependencies(kmtest_drivers
     kmtest_drv
     example_drv
+    iocreatefile_drv
     iodeviceobject_drv
     iohelper_drv
     ioreadwrite_drv
index 8f16578..2823a07 100644 (file)
@@ -9,6 +9,7 @@
 
 KMT_TESTFUNC Test_Example;
 KMT_TESTFUNC Test_FindFile;
+KMT_TESTFUNC Test_IoCreateFile;
 KMT_TESTFUNC Test_IoDeviceObject;
 KMT_TESTFUNC Test_IoReadWrite;
 KMT_TESTFUNC Test_RtlAvlTree;
@@ -27,6 +28,7 @@ const KMT_TEST TestList[] =
 {
     { "-Example",           Test_Example },
     { "FindFile",           Test_FindFile },
+    { "IoCreateFile",       Test_IoCreateFile },
     { "IoDeviceObject",     Test_IoDeviceObject },
     { "IoReadWrite",        Test_IoReadWrite },
     { "RtlAvlTree",         Test_RtlAvlTree },
index 9a00001..2b3fc07 100644 (file)
@@ -1,6 +1,21 @@
 
 include_directories(../include)
 
+#
+# IoCreateFile
+#
+list(APPEND IOCREATEFILE_DRV_SOURCE
+    ../kmtest_drv/kmtest_standalone.c
+    IoCreateFile_drv.c)
+
+add_library(iocreatefile_drv SHARED ${IOCREATEFILE_DRV_SOURCE})
+set_module_type(iocreatefile_drv kernelmodedriver)
+target_link_libraries(iocreatefile_drv kmtest_printf ${PSEH_LIB})
+add_importlibs(iocreatefile_drv ntoskrnl hal)
+add_target_compile_definitions(iocreatefile_drv KMT_STANDALONE_DRIVER)
+#add_pch(iocreatefile_drv ../include/kmt_test.h)
+add_cd_file(TARGET iocreatefile_drv DESTINATION reactos/bin FOR all)
+
 #
 # IoDeviceObject
 #
diff --git a/rostests/kmtests/ntos_io/IoCreateFile.h b/rostests/kmtests/ntos_io/IoCreateFile.h
new file mode 100644 (file)
index 0000000..903ffc1
--- /dev/null
@@ -0,0 +1,14 @@
+/*
+ * PROJECT:         ReactOS kernel-mode tests
+ * LICENSE:         LGPLv2.1+ - See COPYING.LIB in the top level directory
+ * PURPOSE:         IoCreateFile test declarations
+ * PROGRAMMER:      Pierre Schweitzer <pierre@reactos.org>
+ */
+
+#ifndef _KMTEST_IOCREATEFILE_H_
+#define _KMTEST_IOCREATEFILE_H_
+
+#define IOCTL_CREATE_SYMLINK    1
+#define IOCTL_CREATE_NO_SYMLINK 2
+
+#endif /* !defined _KMTEST_IOCREATEFILE_H_ */
diff --git a/rostests/kmtests/ntos_io/IoCreateFile_drv.c b/rostests/kmtests/ntos_io/IoCreateFile_drv.c
new file mode 100644 (file)
index 0000000..2101ad0
--- /dev/null
@@ -0,0 +1,270 @@
+/*
+ * PROJECT:         ReactOS kernel-mode tests
+ * LICENSE:         LGPLv2.1+ - See COPYING.LIB in the top level directory
+ * PURPOSE:         Test driver for reparse point operations
+ * PROGRAMMER:      Pierre Schweitzer <pierre@reactos.org>
+ */
+
+#include <kmt_test.h>
+
+#define NDEBUG
+#include <debug.h>
+
+#include "IoCreateFile.h"
+
+typedef struct _TEST_FCB
+{
+    FSRTL_ADVANCED_FCB_HEADER Header;
+    SECTION_OBJECT_POINTERS SectionObjectPointers;
+    FAST_MUTEX HeaderMutex;
+} TEST_FCB, *PTEST_FCB;
+
+static KMT_IRP_HANDLER TestIrpHandler;
+static KMT_MESSAGE_HANDLER TestMessageHandler;
+
+static PFILE_OBJECT TestFileObject;
+static PDEVICE_OBJECT TestDeviceObject;
+
+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"IoCreateFile";
+    *Flags = TESTENTRY_NO_EXCLUSIVE_DEVICE |
+             TESTENTRY_BUFFERED_IO_DEVICE |
+             TESTENTRY_NO_READONLY_DEVICE;
+
+    KmtRegisterIrpHandler(IRP_MJ_CREATE, NULL, TestIrpHandler);
+    KmtRegisterIrpHandler(IRP_MJ_CLEANUP, NULL, TestIrpHandler);
+    KmtRegisterMessageHandler(0, NULL, TestMessageHandler);
+
+    return Status;
+}
+
+VOID
+TestUnload(
+    _In_ PDRIVER_OBJECT DriverObject)
+{
+    PAGED_CODE();
+}
+
+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_CREATE ||
+           IoStack->MajorFunction == IRP_MJ_CLEANUP);
+
+    Status = STATUS_NOT_SUPPORTED;
+    Irp->IoStatus.Information = 0;
+
+    if (IoStack->MajorFunction == IRP_MJ_CREATE)
+    {
+        ok((IoStack->Parameters.Create.Options & FILE_OPEN_REPARSE_POINT) == 0, "FILE_OPEN_REPARSE_POINT set\n");
+        ok((IoStack->Flags == 0) || (IoStack->Flags == SL_STOP_ON_SYMLINK), "IoStack->Flags = %lx\n", IoStack->Flags);
+
+        if (IoStack->FileObject->FileName.Length >= 2 * sizeof(WCHAR))
+        {
+            TestDeviceObject = DeviceObject;
+            TestFileObject = IoStack->FileObject;
+        }
+        if (IoStack->FileObject->FileName.Length >= 2 * sizeof(WCHAR) &&
+            IoStack->FileObject->FileName.Buffer[1] == 'M')
+        {
+            PREPARSE_DATA_BUFFER Reparse;
+
+            Irp->Tail.Overlay.AuxiliaryBuffer = ExAllocatePoolWithTag(NonPagedPool, MAXIMUM_REPARSE_DATA_BUFFER_SIZE, 'FwrI');
+            Reparse = (PREPARSE_DATA_BUFFER)Irp->Tail.Overlay.AuxiliaryBuffer;
+
+            RtlZeroMemory(Reparse, MAXIMUM_REPARSE_DATA_BUFFER_SIZE);
+            Reparse->ReparseTag = IO_REPARSE_TAG_MOUNT_POINT;
+            Reparse->ReparseDataLength = 12 + sizeof(L"\\??\\C:\\Documents and Settings");
+            Reparse->MountPointReparseBuffer.SubstituteNameLength = sizeof(L"\\??\\C:\\Documents and Settings") - sizeof(UNICODE_NULL);
+            Reparse->MountPointReparseBuffer.PrintNameOffset = sizeof(L"\\??\\C:\\Documents and Settings");
+            RtlCopyMemory(Reparse->MountPointReparseBuffer.PathBuffer, L"\\??\\C:\\Documents and Settings", sizeof(L"\\??\\C:\\Documents and Settings"));
+            Irp->IoStatus.Information = IO_REPARSE_TAG_MOUNT_POINT;
+            Status = STATUS_REPARSE;
+        }
+        else if (IoStack->FileObject->FileName.Length >= 2 * sizeof(WCHAR) &&
+            IoStack->FileObject->FileName.Buffer[1] == 'S')
+        {
+            if (IoStack->Flags & SL_STOP_ON_SYMLINK)
+            {
+                Status = STATUS_STOPPED_ON_SYMLINK;
+            }
+            else
+            {
+                PREPARSE_DATA_BUFFER Reparse;
+
+                Irp->Tail.Overlay.AuxiliaryBuffer = ExAllocatePoolWithTag(NonPagedPool, MAXIMUM_REPARSE_DATA_BUFFER_SIZE, 'FwrI');
+                Reparse = (PREPARSE_DATA_BUFFER)Irp->Tail.Overlay.AuxiliaryBuffer;
+
+                RtlZeroMemory(Reparse, MAXIMUM_REPARSE_DATA_BUFFER_SIZE);
+                Reparse->ReparseTag = IO_REPARSE_TAG_SYMLINK;
+                Reparse->ReparseDataLength = 12 + sizeof(L"\\??\\C:\\Documents and Settings");
+                Reparse->SymbolicLinkReparseBuffer.SubstituteNameLength = sizeof(L"\\??\\C:\\Documents and Settings") - sizeof(UNICODE_NULL);
+                Reparse->SymbolicLinkReparseBuffer.PrintNameOffset = sizeof(L"\\??\\C:\\Documents and Settings");
+                RtlCopyMemory(Reparse->SymbolicLinkReparseBuffer.PathBuffer, L"\\??\\C:\\Documents and Settings", sizeof(L"\\??\\C:\\Documents and Settings"));
+                Irp->IoStatus.Information = IO_REPARSE_TAG_SYMLINK;
+                Status = STATUS_REPARSE;
+            }
+        }
+        else
+        {
+            Fcb = ExAllocatePoolWithTag(NonPagedPool, sizeof(*Fcb), 'FwrI');
+            RtlZeroMemory(Fcb, sizeof(*Fcb));
+            ExInitializeFastMutex(&Fcb->HeaderMutex);
+            FsRtlSetupAdvancedHeader(&Fcb->Header, &Fcb->HeaderMutex);
+            Fcb->Header.AllocationSize.QuadPart = 0;
+            Fcb->Header.FileSize.QuadPart = 0;
+            Fcb->Header.ValidDataLength.QuadPart = 0;
+            IoStack->FileObject->FsContext = Fcb;
+            IoStack->FileObject->SectionObjectPointer = &Fcb->SectionObjectPointers;
+
+            Irp->IoStatus.Information = FILE_OPENED;
+            Status = STATUS_SUCCESS;
+        }
+    }
+    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;
+}
+
+static UNICODE_STRING FileObjectFileName = RTL_CONSTANT_STRING(L"\\NonSymlinked");
+static UNICODE_STRING DocumentsAndSettings = RTL_CONSTANT_STRING(L"\\Documents and Settings");
+
+static
+NTSTATUS
+TestIoCreateFile(
+    IN PUNICODE_STRING Path,
+    IN BOOLEAN NoLinks)
+{
+    OBJECT_ATTRIBUTES ObjectAttributes;
+    IO_STATUS_BLOCK IoStatusBlock;
+    HANDLE Handle;
+    NTSTATUS Status;
+    PFILE_OBJECT FileObject;
+
+    InitializeObjectAttributes(&ObjectAttributes,
+                               Path,
+                               OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE,
+                               NULL,
+                               NULL);
+    Status = IoCreateFile(&Handle,
+                          GENERIC_READ,
+                          &ObjectAttributes,
+                          &IoStatusBlock,
+                          NULL,
+                          FILE_ATTRIBUTE_NORMAL,
+                          FILE_SHARE_READ | FILE_SHARE_WRITE,
+                          FILE_OPEN,
+                          FILE_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_ALERT,
+                          NULL,
+                          0,
+                          CreateFileTypeNone,
+                          NULL,
+                          IO_NO_PARAMETER_CHECKING | (NoLinks ? IO_STOP_ON_SYMLINK : 0));
+    if (NT_SUCCESS(Status))
+    {
+        NTSTATUS IntStatus;
+
+        IntStatus = ObReferenceObjectByHandle(Handle,
+                                              FILE_READ_DATA,
+                                              *IoFileObjectType,
+                                              KernelMode,
+                                              (PVOID *)&FileObject,
+                                              NULL);
+        ok_eq_hex(IntStatus, STATUS_SUCCESS);
+        if (NT_SUCCESS(IntStatus))
+        {
+            ok(RtlCompareUnicodeString(&FileObjectFileName, &FileObject->FileName, TRUE) == 0 ||
+               RtlCompareUnicodeString(&DocumentsAndSettings, &FileObject->FileName, TRUE) == 0,
+               "Expected: %wZ or %wZ. Opened: %wZ\n", &FileObjectFileName, &DocumentsAndSettings, &FileObject->FileName);
+            ObDereferenceObject(FileObject);
+        }
+        NtClose(Handle);
+    }
+
+    return Status;
+}
+
+static
+NTSTATUS
+TestMessageHandler(
+    IN PDEVICE_OBJECT DeviceObject,
+    IN ULONG ControlCode,
+    IN PVOID Buffer OPTIONAL,
+    IN SIZE_T InLength,
+    IN OUT PSIZE_T OutLength)
+{
+    NTSTATUS Status = STATUS_SUCCESS;
+
+    PAGED_CODE();
+
+    switch (ControlCode)
+    {
+        case IOCTL_CREATE_SYMLINK:
+        case IOCTL_CREATE_NO_SYMLINK:
+        {
+            ANSI_STRING Path;
+            UNICODE_STRING PathW;
+
+            ok(Buffer != NULL, "Buffer is NULL\n");
+            Path.Length = Path.MaximumLength = (USHORT)InLength;
+            Path.Buffer = Buffer;
+
+            Status = RtlAnsiStringToUnicodeString(&PathW, &Path, TRUE);
+            ok_eq_hex(Status, STATUS_SUCCESS);
+
+            Status = TestIoCreateFile(&PathW, (ControlCode == IOCTL_CREATE_NO_SYMLINK));
+
+            RtlFreeUnicodeString(&PathW);
+
+            break;
+        }
+        default:
+            return STATUS_NOT_SUPPORTED;
+    }
+
+    return Status;
+}
diff --git a/rostests/kmtests/ntos_io/IoCreateFile_user.c b/rostests/kmtests/ntos_io/IoCreateFile_user.c
new file mode 100644 (file)
index 0000000..858cba4
--- /dev/null
@@ -0,0 +1,40 @@
+/*
+ * PROJECT:         ReactOS kernel-mode tests
+ * LICENSE:         GPLv2+ - See COPYING in the top level directory
+ * PURPOSE:         Kernel-Mode Test Suite Reparse points test user-mode part
+ * PROGRAMMER:      Pierre Schweitzer <pierre@reactos.org>
+ */
+
+#include <kmt_test.h>
+#include "IoCreateFile.h"
+
+static CHAR MountedPointFileName[] = "\\Device\\Kmtest-IoCreateFile\\MountedPoint";
+static CHAR SymlinkedFileName[] = "\\Device\\Kmtest-IoCreateFile\\Symlinked";
+static CHAR NonSymlinkedFileName[] = "\\Device\\Kmtest-IoCreateFile\\NonSymlinked";
+
+START_TEST(IoCreateFile)
+{
+    DWORD Error;
+
+    KmtRunKernelTest("IoCreateFile");
+
+    KmtLoadDriver(L"IoCreateFile", FALSE);
+    KmtOpenDriver();
+
+    Error = KmtSendStringToDriver(IOCTL_CREATE_SYMLINK, NonSymlinkedFileName);
+    ok(Error == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %lx\n", Error);
+    Error = KmtSendStringToDriver(IOCTL_CREATE_SYMLINK, SymlinkedFileName);
+    ok(Error == ERROR_CANT_ACCESS_FILE, "Expected ERROR_CANT_ACCESS_FILE, got %lx\n", Error); /* FIXME */
+    Error = KmtSendStringToDriver(IOCTL_CREATE_SYMLINK, MountedPointFileName);
+    ok(Error == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %lx\n", Error);
+
+    Error = KmtSendStringToDriver(IOCTL_CREATE_NO_SYMLINK, NonSymlinkedFileName);
+    ok(Error == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %lx\n", Error);
+    Error = KmtSendStringToDriver(IOCTL_CREATE_NO_SYMLINK, SymlinkedFileName);
+    ok(Error == ERROR_MR_MID_NOT_FOUND, "Expected ERROR_MR_MID_NOT_FOUND, got %lx\n", Error);
+    Error = KmtSendStringToDriver(IOCTL_CREATE_NO_SYMLINK, MountedPointFileName);
+    ok(Error == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %lx\n", Error);
+
+    KmtCloseDriver();
+    KmtUnloadDriver();
+}