sys: mountdev: mount manager support

This commit is contained in:
Bill Zissimopoulos 2019-09-05 09:54:36 -07:00
parent 89ec3e6733
commit a47f853beb
No known key found for this signature in database
GPG Key ID: 3D4F95D52C7B3EA3
6 changed files with 264 additions and 5 deletions

View File

@ -176,6 +176,7 @@
<ClCompile Include="..\..\src\sys\ioq.c" />
<ClCompile Include="..\..\src\sys\lockctl.c" />
<ClCompile Include="..\..\src\sys\meta.c" />
<ClCompile Include="..\..\src\sys\mountdev.c" />
<ClCompile Include="..\..\src\sys\mup.c" />
<ClCompile Include="..\..\src\sys\name.c" />
<ClCompile Include="..\..\src\sys\psbuffer.c" />

View File

@ -116,6 +116,9 @@
<ClCompile Include="..\..\src\ku\uuid5.c">
<Filter>Source\ku</Filter>
</ClCompile>
<ClCompile Include="..\..\src\sys\mountdev.c">
<Filter>Source</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<ClInclude Include="..\..\src\sys\driver.h">

View File

@ -43,10 +43,15 @@ enum
};
static NTSTATUS FspFsvrtDeviceControl(
PDEVICE_OBJECT FsvolDeviceObject, PIRP Irp, PIO_STACK_LOCATION IrpSp)
PDEVICE_OBJECT FsvrtDeviceObject, PIRP Irp, PIO_STACK_LOCATION IrpSp)
{
PAGED_CODE();
NTSTATUS Result;
if (FspMountdevDeviceControl(FsvrtDeviceObject, Irp, IrpSp, &Result))
return Result;
/*
* Fix GitHub issue #177. All credit for the investigation of this issue
* and the suggested steps to reproduce and work around the problem goes
@ -72,6 +77,19 @@ static NTSTATUS FspFsvolDeviceControl(
FSP_FSVOL_DEVICE_EXTENSION *FsvolDeviceExtension = FspFsvolDeviceExtension(FsvolDeviceObject);
PFILE_OBJECT FileObject = IrpSp->FileObject;
ULONG IoControlCode = IrpSp->Parameters.DeviceIoControl.IoControlCode;
NTSTATUS Result;
if (FspMountdevDeviceControl(FsvolDeviceExtension->FsvrtDeviceObject, Irp, IrpSp, &Result))
return Result;
/*
* Possibly forward the IOCTL request to the user mode file system. The rules are:
*
* - File system must support DeviceControl.
* - Only IOCTL with custom devices (see DEVICE_TYPE_FROM_CTL_CODE) and
* METHOD_BUFFERED will be forwarded.
*/
/* do we support DeviceControl? */
if (!FsvolDeviceExtension->VolumeParams.DeviceControl)
@ -90,7 +108,6 @@ static NTSTATUS FspFsvolDeviceControl(
if (!FspFileNodeIsValid(FileObject->FsContext))
return STATUS_INVALID_PARAMETER;
NTSTATUS Result;
FSP_FILE_NODE *FileNode = FileObject->FsContext;
FSP_FILE_DESC *FileDesc = FileObject->FsContext2;
PVOID InputBuffer = Irp->AssociatedIrp.SystemBuffer;

View File

@ -67,6 +67,8 @@ VOID FspFsvolDeviceGetVolumeInfo(PDEVICE_OBJECT DeviceObject, FSP_FSCTL_VOLUME_I
BOOLEAN FspFsvolDeviceTryGetVolumeInfo(PDEVICE_OBJECT DeviceObject, FSP_FSCTL_VOLUME_INFO *VolumeInfo);
VOID FspFsvolDeviceSetVolumeInfo(PDEVICE_OBJECT DeviceObject, const FSP_FSCTL_VOLUME_INFO *VolumeInfo);
VOID FspFsvolDeviceInvalidateVolumeInfo(PDEVICE_OBJECT DeviceObject);
static NTSTATUS FspFsvrtDeviceInit(PDEVICE_OBJECT DeviceObject);
static VOID FspFsvrtDeviceFini(PDEVICE_OBJECT DeviceObject);
static NTSTATUS FspFsmupDeviceInit(PDEVICE_OBJECT DeviceObject);
static VOID FspFsmupDeviceFini(PDEVICE_OBJECT DeviceObject);
NTSTATUS FspDeviceCopyList(
@ -100,6 +102,8 @@ VOID FspDeviceDeleteAll(VOID);
#pragma alloc_text(PAGE, FspFsvolDeviceCompareContextByName)
#pragma alloc_text(PAGE, FspFsvolDeviceAllocateContextByName)
#pragma alloc_text(PAGE, FspFsvolDeviceFreeContextByName)
#pragma alloc_text(PAGE, FspFsvrtDeviceInit)
#pragma alloc_text(PAGE, FspFsvrtDeviceFini)
#pragma alloc_text(PAGE, FspFsmupDeviceInit)
#pragma alloc_text(PAGE, FspFsmupDeviceFini)
#pragma alloc_text(PAGE, FspDeviceCopyList)
@ -126,10 +130,12 @@ NTSTATUS FspDeviceCreateSecure(UINT32 Kind, ULONG ExtraSize,
case FspFsvolDeviceExtensionKind:
DeviceExtensionSize = sizeof(FSP_FSVOL_DEVICE_EXTENSION);
break;
case FspFsvrtDeviceExtensionKind:
DeviceExtensionSize = sizeof(FSP_FSVRT_DEVICE_EXTENSION);
break;
case FspFsmupDeviceExtensionKind:
DeviceExtensionSize = sizeof(FSP_FSMUP_DEVICE_EXTENSION);
break;
case FspFsvrtDeviceExtensionKind:
case FspFsctlDeviceExtensionKind:
DeviceExtensionSize = sizeof(FSP_DEVICE_EXTENSION);
break;
@ -184,10 +190,12 @@ NTSTATUS FspDeviceInitialize(PDEVICE_OBJECT DeviceObject)
case FspFsvolDeviceExtensionKind:
Result = FspFsvolDeviceInit(DeviceObject);
break;
case FspFsvrtDeviceExtensionKind:
Result = FspFsvrtDeviceInit(DeviceObject);
break;
case FspFsmupDeviceExtensionKind:
Result = FspFsmupDeviceInit(DeviceObject);
break;
case FspFsvrtDeviceExtensionKind:
case FspFsctlDeviceExtensionKind:
Result = STATUS_SUCCESS;
break;
@ -213,10 +221,12 @@ VOID FspDeviceDelete(PDEVICE_OBJECT DeviceObject)
case FspFsvolDeviceExtensionKind:
FspFsvolDeviceFini(DeviceObject);
break;
case FspFsvrtDeviceExtensionKind:
FspFsvrtDeviceFini(DeviceObject);
break;
case FspFsmupDeviceExtensionKind:
FspFsmupDeviceFini(DeviceObject);
break;
case FspFsvrtDeviceExtensionKind:
case FspFsctlDeviceExtensionKind:
break;
default:
@ -940,6 +950,20 @@ VOID FspFsvolDeviceInvalidateVolumeInfo(PDEVICE_OBJECT DeviceObject)
KeReleaseSpinLock(&FsvolDeviceExtension->InfoSpinLock, Irql);
}
static NTSTATUS FspFsvrtDeviceInit(PDEVICE_OBJECT DeviceObject)
{
PAGED_CODE();
return STATUS_SUCCESS;
}
static VOID FspFsvrtDeviceFini(PDEVICE_OBJECT DeviceObject)
{
PAGED_CODE();
FspMountdevFini(DeviceObject);
}
static NTSTATUS FspFsmupDeviceInit(PDEVICE_OBJECT DeviceObject)
{
PAGED_CODE();

View File

@ -26,6 +26,7 @@
#define POOL_NX_OPTIN 1
#include <ntifs.h>
#include <mountdev.h>
#include <ntstrsafe.h>
#include <wdmsec.h>
#include <winfsp/fsctl.h>
@ -1101,6 +1102,14 @@ typedef struct
FSP_FSCTL_DECLSPEC_ALIGN UINT8 FsextData[];
} FSP_FSVOL_DEVICE_EXTENSION;
typedef struct
{
FSP_DEVICE_EXTENSION Base;
LONG IsMountdev;
GUID UniqueId;
UNICODE_STRING VolumeName;
WCHAR VolumeNameBuf[FSP_FSCTL_VOLUME_NAME_SIZE / sizeof(WCHAR)];
} FSP_FSVRT_DEVICE_EXTENSION;
typedef struct
{
FSP_DEVICE_EXTENSION Base;
UINT32 InitDonePfxTab:1;
@ -1120,6 +1129,12 @@ FSP_FSVOL_DEVICE_EXTENSION *FspFsvolDeviceExtension(PDEVICE_OBJECT DeviceObject)
return DeviceObject->DeviceExtension;
}
static inline
FSP_FSVRT_DEVICE_EXTENSION *FspFsvrtDeviceExtension(PDEVICE_OBJECT DeviceObject)
{
ASSERT(FspFsvrtDeviceExtensionKind == ((FSP_DEVICE_EXTENSION *)DeviceObject->DeviceExtension)->Kind);
return DeviceObject->DeviceExtension;
}
static inline
FSP_FSMUP_DEVICE_EXTENSION *FspFsmupDeviceExtension(PDEVICE_OBJECT DeviceObject)
{
ASSERT(FspFsmupDeviceExtensionKind == ((FSP_DEVICE_EXTENSION *)DeviceObject->DeviceExtension)->Kind);
@ -1224,6 +1239,19 @@ BOOLEAN FspQueryDirectoryIrpShouldUseProcessBuffer(PIRP Irp, SIZE_T BufferSize)
}
#endif
/* mountdev */
NTSTATUS FspMountdevQueryDeviceName(
PDEVICE_OBJECT FsvrtDeviceObject, PIRP Irp, PIO_STACK_LOCATION IrpSp);
NTSTATUS FspMountdevQueryUniqueId(
PDEVICE_OBJECT FsvrtDeviceObject, PIRP Irp, PIO_STACK_LOCATION IrpSp);
BOOLEAN FspMountdevDeviceControl(
PDEVICE_OBJECT FsvrtDeviceObject, PIRP Irp, PIO_STACK_LOCATION IrpSp,
PNTSTATUS PResult);
NTSTATUS FspMountdevMake(
PDEVICE_OBJECT FsvrtDeviceObject, PDEVICE_OBJECT FsvolDeviceObject);
VOID FspMountdevFini(
PDEVICE_OBJECT FsvrtDeviceObject);
/* fsmup */
NTSTATUS FspMupRegister(
PDEVICE_OBJECT FsmupDeviceObject, PDEVICE_OBJECT FsvolDeviceObject);

186
src/sys/mountdev.c Normal file
View File

@ -0,0 +1,186 @@
/**
* @file sys/mountdev.c
*
* @copyright 2015-2019 Bill Zissimopoulos
*/
/*
* This file is part of WinFsp.
*
* You can redistribute it and/or modify it under the terms of the GNU
* General Public License version 3 as published by the Free Software
* Foundation.
*
* Licensees holding a valid commercial license may use this software
* in accordance with the commercial license agreement provided in
* conjunction with the software. The terms and conditions of any such
* commercial license agreement shall govern, supersede, and render
* ineffective any application of the GPLv3 license to this software,
* notwithstanding of any reference thereto in the software or
* associated repository.
*/
#include <sys/driver.h>
NTSTATUS FspMountdevQueryDeviceName(
PDEVICE_OBJECT FsvrtDeviceObject, PIRP Irp, PIO_STACK_LOCATION IrpSp);
NTSTATUS FspMountdevQueryUniqueId(
PDEVICE_OBJECT FsvrtDeviceObject, PIRP Irp, PIO_STACK_LOCATION IrpSp);
BOOLEAN FspMountdevDeviceControl(
PDEVICE_OBJECT FsvrtDeviceObject, PIRP Irp, PIO_STACK_LOCATION IrpSp,
PNTSTATUS PResult);
NTSTATUS FspMountdevMake(
PDEVICE_OBJECT FsvrtDeviceObject, PDEVICE_OBJECT FsvolDeviceObject);
VOID FspMountdevFini(
PDEVICE_OBJECT FsvrtDeviceObject);
#ifdef ALLOC_PRAGMA
#pragma alloc_text(PAGE, FspMountdevQueryDeviceName)
#pragma alloc_text(PAGE, FspMountdevQueryUniqueId)
#pragma alloc_text(PAGE, FspMountdevDeviceControl)
#pragma alloc_text(PAGE, FspMountdevMake)
#pragma alloc_text(PAGE, FspMountdevFini)
#endif
NTSTATUS FspMountdevQueryDeviceName(
PDEVICE_OBJECT FsvrtDeviceObject, PIRP Irp, PIO_STACK_LOCATION IrpSp)
{
PAGED_CODE();
FSP_FSVRT_DEVICE_EXTENSION *FsvrtDeviceExtension = FspFsvrtDeviceExtension(FsvrtDeviceObject);
ULONG OutputBufferLength = IrpSp->Parameters.DeviceIoControl.OutputBufferLength;
PMOUNTDEV_NAME OutputBuffer = Irp->AssociatedIrp.SystemBuffer;
if (sizeof(MOUNTDEV_NAME) > OutputBufferLength)
/* NOTE: Windows storage samples also set: Irp->IoStatus.Information = sizeof(MOUNTDEV_NAME) */
return STATUS_BUFFER_TOO_SMALL;
RtlZeroMemory(OutputBuffer, sizeof(MOUNTDEV_NAME));
OutputBuffer->NameLength = FsvrtDeviceExtension->VolumeName.Length;
Irp->IoStatus.Information =
FIELD_OFFSET(MOUNTDEV_NAME, Name) + OutputBuffer->NameLength;
if (Irp->IoStatus.Information > OutputBufferLength)
{
Irp->IoStatus.Information = sizeof(MOUNTDEV_NAME);
return STATUS_BUFFER_OVERFLOW;
}
RtlCopyMemory(OutputBuffer->Name,
FsvrtDeviceExtension->VolumeName.Buffer, OutputBuffer->NameLength);
return STATUS_SUCCESS;
}
NTSTATUS FspMountdevQueryUniqueId(
PDEVICE_OBJECT FsvrtDeviceObject, PIRP Irp, PIO_STACK_LOCATION IrpSp)
{
PAGED_CODE();
FSP_FSVRT_DEVICE_EXTENSION *FsvrtDeviceExtension = FspFsvrtDeviceExtension(FsvrtDeviceObject);
ULONG OutputBufferLength = IrpSp->Parameters.DeviceIoControl.OutputBufferLength;
PMOUNTDEV_UNIQUE_ID OutputBuffer = Irp->AssociatedIrp.SystemBuffer;
if (sizeof(MOUNTDEV_UNIQUE_ID) > OutputBufferLength)
/* NOTE: Windows storage samples also set: Irp->IoStatus.Information = sizeof(MOUNTDEV_UNIQUE_ID) */
return STATUS_BUFFER_TOO_SMALL;
RtlZeroMemory(OutputBuffer, sizeof(MOUNTDEV_UNIQUE_ID));
OutputBuffer->UniqueIdLength = sizeof FsvrtDeviceExtension->UniqueId;
Irp->IoStatus.Information =
FIELD_OFFSET(MOUNTDEV_UNIQUE_ID, UniqueId) + OutputBuffer->UniqueIdLength;
if (Irp->IoStatus.Information > OutputBufferLength)
{
Irp->IoStatus.Information = sizeof(MOUNTDEV_UNIQUE_ID);
return STATUS_BUFFER_OVERFLOW;
}
RtlCopyMemory(OutputBuffer->UniqueId,
&FsvrtDeviceExtension->UniqueId, OutputBuffer->UniqueIdLength);
return STATUS_SUCCESS;
}
BOOLEAN FspMountdevDeviceControl(
PDEVICE_OBJECT FsvrtDeviceObject, PIRP Irp, PIO_STACK_LOCATION IrpSp,
PNTSTATUS PResult)
{
PAGED_CODE();
if (0 != FsvrtDeviceObject)
{
FSP_FSVRT_DEVICE_EXTENSION *FsvrtDeviceExtension = FspFsvrtDeviceExtension(FsvrtDeviceObject);
if (0 != InterlockedCompareExchange(&FsvrtDeviceExtension->IsMountdev, 0, 0))
{
switch (IrpSp->Parameters.DeviceIoControl.IoControlCode)
{
case IOCTL_MOUNTDEV_QUERY_DEVICE_NAME:
*PResult = FspMountdevQueryDeviceName(FsvrtDeviceObject, Irp, IrpSp);
return TRUE;
case IOCTL_MOUNTDEV_QUERY_UNIQUE_ID:
*PResult = FspMountdevQueryUniqueId(FsvrtDeviceObject, Irp, IrpSp);
return TRUE;
}
}
}
return FALSE;
}
NTSTATUS FspMountdevMake(
PDEVICE_OBJECT FsvrtDeviceObject, PDEVICE_OBJECT FsvolDeviceObject)
{
/*
* This function converts the fsvrt device into a mountdev device that
* responds to MountManager IOCTL's. This allows the fsvrt device to
* be mounted using the MountManager.
*
* This function requires protection against concurrency. In general this
* is achieved by acquiring the GlobalDeviceLock.
*/
PAGED_CODE();
FSP_FSVOL_DEVICE_EXTENSION *FsvolDeviceExtension = FspFsvolDeviceExtension(FsvolDeviceObject);
FSP_FSVRT_DEVICE_EXTENSION *FsvrtDeviceExtension = FspFsvrtDeviceExtension(FsvrtDeviceObject);
UNICODE_STRING String;
WCHAR StringBuf[FSP_FSCTL_VOLUME_FSNAME_SIZE / sizeof(WCHAR) + 18];
GUID Guid;
NTSTATUS Result;
ASSERT(FsvolDeviceExtension->FsvrtDeviceObject == FsvrtDeviceObject);
if (0 != InterlockedCompareExchange(&FsvrtDeviceExtension->IsMountdev, 0, 0))
return STATUS_SUCCESS;
/* make UUID v5 from the fsvrt device GUID and a unique string derived from the VolumeParams */
RtlInitEmptyUnicodeString(&String, StringBuf, sizeof StringBuf);
Result = RtlUnicodeStringPrintf(&String,
L"%s:%08lx:%08lx",
FsvolDeviceExtension->VolumeParams.FileSystemName,
FsvolDeviceExtension->VolumeParams.VolumeSerialNumber,
FsvolDeviceExtension->VolumeParams.VolumeCreationTime);
ASSERT(NT_SUCCESS(Result));
Result = FspUuid5Make(&FspFsvrtDeviceClassGuid, String.Buffer, String.Length, &Guid);
if (!NT_SUCCESS(Result))
goto exit;
/* initialize the fsvrt device extension */
RtlCopyMemory(&FsvrtDeviceExtension->UniqueId, &Guid, sizeof Guid);
RtlInitEmptyUnicodeString(&FsvrtDeviceExtension->VolumeName,
FsvrtDeviceExtension->VolumeNameBuf, sizeof FsvrtDeviceExtension->VolumeNameBuf);
RtlCopyUnicodeString(&FsvrtDeviceExtension->VolumeName, &FsvolDeviceExtension->VolumeName);
/* mark the fsvrt device as initialized */
InterlockedIncrement(&FspFsvrtDeviceExtension(FsvrtDeviceObject)->IsMountdev);
Result = STATUS_SUCCESS;
exit:
return Result;
}
VOID FspMountdevFini(
PDEVICE_OBJECT FsvrtDeviceObject)
{
}