mirror of
				https://github.com/winfsp/winfsp.git
				synced 2025-11-03 20:48:08 -06: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);
 | 
						|
}
 |