reactos/rostests/kmtests/ntos_io/IoCreateFile_drv.c
Pierre Schweitzer 9e06c66b38 [KMTESTS:IO]
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
2015-09-22 22:31:08 +00:00

271 lines
9.2 KiB
C

/*
* 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;
}