mirror of
https://github.com/reactos/reactos.git
synced 2024-11-06 22:52:46 +00:00
272 lines
9.3 KiB
C
272 lines
9.3 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 volatile long gNoLinks = FALSE;
|
|
|
|
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 && !gNoLinks) || (IoStack->Flags == SL_STOP_ON_SYMLINK && gNoLinks), "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;
|
|
}
|
|
|
|
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)
|
|
{
|
|
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 | (gNoLinks ? 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);
|
|
}
|
|
|
|
IntStatus = ObCloseHandle(Handle, KernelMode);
|
|
ok_eq_hex(IntStatus, STATUS_SUCCESS);
|
|
}
|
|
|
|
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_DISABLE_SYMLINK:
|
|
{
|
|
if (InterlockedExchange(&gNoLinks, TRUE) == TRUE)
|
|
{
|
|
Status = STATUS_UNSUCCESSFUL;
|
|
}
|
|
|
|
break;
|
|
}
|
|
case IOCTL_CALL_CREATE:
|
|
{
|
|
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);
|
|
|
|
RtlFreeUnicodeString(&PathW);
|
|
|
|
break;
|
|
}
|
|
default:
|
|
return STATUS_NOT_SUPPORTED;
|
|
}
|
|
|
|
return Status;
|
|
}
|