mirror of
https://github.com/winfsp/winfsp.git
synced 2025-04-23 00:43:00 -05:00
233 lines
8.2 KiB
C
233 lines
8.2 KiB
C
/**
|
|
* @file sys/mountdev.c
|
|
*
|
|
* @copyright 2015-2021 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,
|
|
BOOLEAN Persistent);
|
|
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,
|
|
BOOLEAN Persistent)
|
|
{
|
|
/*
|
|
* 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 Persistent == FsvrtDeviceExtension->Persistent ?
|
|
STATUS_TOO_LATE : STATUS_ACCESS_DENIED;
|
|
|
|
FsvrtDeviceExtension->Persistent = Persistent;
|
|
|
|
if (Persistent)
|
|
{
|
|
/* make UUID v5 from the fsvrt device GUID and a unique string derived from 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);
|
|
}
|
|
else
|
|
/* create volume guid */
|
|
Result = FspCreateGuid(&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)
|
|
{
|
|
PAGED_CODE();
|
|
|
|
FSP_FSVRT_DEVICE_EXTENSION *FsvrtDeviceExtension = FspFsvrtDeviceExtension(FsvrtDeviceObject);
|
|
PVOID Buffer = 0;
|
|
ULONG Length = 4096;
|
|
MOUNTMGR_MOUNT_POINT *MountPoint;
|
|
NTSTATUS Result;
|
|
|
|
if (0 == InterlockedCompareExchange(&FsvrtDeviceExtension->IsMountdev, 0, 0))
|
|
return;
|
|
|
|
if (FsvrtDeviceExtension->Persistent)
|
|
/* if the mountdev is marked as persistent do not purge the MountManager */
|
|
return;
|
|
|
|
Buffer = FspAllocNonPaged(Length);
|
|
if (0 == Buffer)
|
|
{
|
|
Result = STATUS_INSUFFICIENT_RESOURCES;
|
|
goto exit;
|
|
}
|
|
|
|
MountPoint = Buffer;
|
|
RtlZeroMemory(MountPoint, sizeof *MountPoint);
|
|
MountPoint->UniqueIdOffset = sizeof(MOUNTMGR_MOUNT_POINT);
|
|
MountPoint->UniqueIdLength = sizeof FsvrtDeviceExtension->UniqueId;
|
|
RtlCopyMemory((PUINT8)MountPoint + MountPoint->UniqueIdOffset,
|
|
&FsvrtDeviceExtension->UniqueId, MountPoint->UniqueIdLength);
|
|
|
|
Result = FspSendMountmgrDeviceControlIrp(IOCTL_MOUNTMGR_DELETE_POINTS,
|
|
Buffer, MountPoint->UniqueIdOffset + MountPoint->UniqueIdLength, &Length);
|
|
|
|
exit:
|
|
if (0 != Buffer)
|
|
FspFree(Buffer);
|
|
}
|