From a4629b8f8b8b3a74db094b6549f142975e15c2b4 Mon Sep 17 00:00:00 2001 From: Bill Zissimopoulos Date: Tue, 16 Jan 2018 10:38:52 -0800 Subject: [PATCH] sys: fsmup device - This commit introduces the fsmup device, which is a major change in how network file systems are handled. Previously every network file system's fsvol device was directly registered with the MUP. Now there is a single fsmup device that is registered with the MUP; network file systems' fsvol devices register with fsmup instead. The fsmup device maintains a prefix table which it uses to demultiplex and forward requests to the appropriate fsvol device. - This device change was necessatitated to fix issue #87. --- build/VStudio/winfsp_sys.vcxproj | 1 + build/VStudio/winfsp_sys.vcxproj.filters | 3 + inc/winfsp/fsctl.h | 1 + src/sys/create.c | 2 + src/sys/debug.c | 2 + src/sys/devctl.c | 10 +- src/sys/device.c | 44 ++++ src/sys/driver.c | 111 ++++++---- src/sys/driver.h | 32 ++- src/sys/mup.c | 266 +++++++++++++++++++++++ src/sys/shutdown.c | 29 +-- src/sys/volume.c | 102 ++------- 12 files changed, 435 insertions(+), 168 deletions(-) create mode 100644 src/sys/mup.c diff --git a/build/VStudio/winfsp_sys.vcxproj b/build/VStudio/winfsp_sys.vcxproj index 6fcfd949..3f23fcfd 100644 --- a/build/VStudio/winfsp_sys.vcxproj +++ b/build/VStudio/winfsp_sys.vcxproj @@ -173,6 +173,7 @@ + diff --git a/build/VStudio/winfsp_sys.vcxproj.filters b/build/VStudio/winfsp_sys.vcxproj.filters index eb0c4f04..3bad7aa5 100644 --- a/build/VStudio/winfsp_sys.vcxproj.filters +++ b/build/VStudio/winfsp_sys.vcxproj.filters @@ -101,6 +101,9 @@ Source + + Source + diff --git a/inc/winfsp/fsctl.h b/inc/winfsp/fsctl.h index 05012ee7..0be90c8b 100644 --- a/inc/winfsp/fsctl.h +++ b/inc/winfsp/fsctl.h @@ -34,6 +34,7 @@ extern "C" { #define FSP_FSCTL_DRIVER_NAME "WinFsp" #define FSP_FSCTL_DISK_DEVICE_NAME "WinFsp.Disk" #define FSP_FSCTL_NET_DEVICE_NAME "WinFsp.Net" +#define FSP_FSCTL_MUP_DEVICE_NAME "WinFsp.Mup" // {6F9D25FA-6DEE-4A9D-80F5-E98E14F35E54} extern const __declspec(selectany) GUID FspFsctlDeviceClassGuid = diff --git a/src/sys/create.c b/src/sys/create.c index 51a5bbcb..5ffd55c3 100644 --- a/src/sys/create.c +++ b/src/sys/create.c @@ -164,6 +164,8 @@ static NTSTATUS FspFsvolCreateNoLock( #pragma prefast(disable:28175, "We are a filesystem: ok to access Vpb") FileObject->Vpb = FsvolDeviceExtension->FsvrtDeviceObject->Vpb; + FileObject->FsContext2 = FsvolDeviceObject; + Irp->IoStatus.Information = FILE_OPENED; return STATUS_SUCCESS; } diff --git a/src/sys/debug.c b/src/sys/debug.c index b8fd16da..de02b586 100644 --- a/src/sys/debug.c +++ b/src/sys/debug.c @@ -281,6 +281,8 @@ const char *DeviceExtensionKindSym(UINT32 Kind) { case FspFsctlDeviceExtensionKind: return "Ctl"; + case FspFsmupDeviceExtensionKind: + return "Mup"; case FspFsvrtDeviceExtensionKind: return "Vrt"; case FspFsvolDeviceExtensionKind: diff --git a/src/sys/devctl.c b/src/sys/devctl.c index 7ff68c76..a076ec63 100644 --- a/src/sys/devctl.c +++ b/src/sys/devctl.c @@ -33,15 +33,7 @@ static NTSTATUS FspFsvolDeviceControl( { PAGED_CODE(); - NTSTATUS Result = STATUS_INVALID_DEVICE_REQUEST; - switch (IrpSp->Parameters.DeviceIoControl.IoControlCode) - { - case IOCTL_REDIR_QUERY_PATH_EX : - Result = FspVolumeRedirQueryPathEx(DeviceObject, Irp, IrpSp); - break; - } - - return Result; + return STATUS_INVALID_DEVICE_REQUEST; } NTSTATUS FspFsvolDeviceControlComplete( diff --git a/src/sys/device.c b/src/sys/device.c index 489d967d..68f3b3a5 100644 --- a/src/sys/device.c +++ b/src/sys/device.c @@ -63,6 +63,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 FspFsmupDeviceInit(PDEVICE_OBJECT DeviceObject); +static VOID FspFsmupDeviceFini(PDEVICE_OBJECT DeviceObject); NTSTATUS FspDeviceCopyList( PDEVICE_OBJECT **PDeviceObjects, PULONG PDeviceObjectCount); VOID FspDeviceDeleteList( @@ -94,6 +96,8 @@ VOID FspDeviceDeleteAll(VOID); #pragma alloc_text(PAGE, FspFsvolDeviceCompareContextByName) #pragma alloc_text(PAGE, FspFsvolDeviceAllocateContextByName) #pragma alloc_text(PAGE, FspFsvolDeviceFreeContextByName) +#pragma alloc_text(PAGE, FspFsmupDeviceInit) +#pragma alloc_text(PAGE, FspFsmupDeviceFini) #pragma alloc_text(PAGE, FspDeviceCopyList) #pragma alloc_text(PAGE, FspDeviceDeleteList) #pragma alloc_text(PAGE, FspDeviceDeleteAll) @@ -118,6 +122,9 @@ NTSTATUS FspDeviceCreateSecure(UINT32 Kind, ULONG ExtraSize, case FspFsvolDeviceExtensionKind: DeviceExtensionSize = sizeof(FSP_FSVOL_DEVICE_EXTENSION); break; + case FspFsmupDeviceExtensionKind: + DeviceExtensionSize = sizeof(FSP_FSMUP_DEVICE_EXTENSION); + break; case FspFsvrtDeviceExtensionKind: case FspFsctlDeviceExtensionKind: DeviceExtensionSize = sizeof(FSP_DEVICE_EXTENSION); @@ -173,6 +180,9 @@ NTSTATUS FspDeviceInitialize(PDEVICE_OBJECT DeviceObject) case FspFsvolDeviceExtensionKind: Result = FspFsvolDeviceInit(DeviceObject); break; + case FspFsmupDeviceExtensionKind: + Result = FspFsmupDeviceInit(DeviceObject); + break; case FspFsvrtDeviceExtensionKind: case FspFsctlDeviceExtensionKind: Result = STATUS_SUCCESS; @@ -199,6 +209,9 @@ VOID FspDeviceDelete(PDEVICE_OBJECT DeviceObject) case FspFsvolDeviceExtensionKind: FspFsvolDeviceFini(DeviceObject); break; + case FspFsmupDeviceExtensionKind: + FspFsmupDeviceFini(DeviceObject); + break; case FspFsvrtDeviceExtensionKind: case FspFsctlDeviceExtensionKind: break; @@ -876,6 +889,37 @@ VOID FspFsvolDeviceInvalidateVolumeInfo(PDEVICE_OBJECT DeviceObject) KeReleaseSpinLock(&FsvolDeviceExtension->InfoSpinLock, Irql); } +static NTSTATUS FspFsmupDeviceInit(PDEVICE_OBJECT DeviceObject) +{ + PAGED_CODE(); + + FSP_FSMUP_DEVICE_EXTENSION *FsmupDeviceExtension = FspFsmupDeviceExtension(DeviceObject); + + /* initialize our prefix table */ + ExInitializeResourceLite(&FsmupDeviceExtension->PrefixTableResource); + RtlInitializeUnicodePrefix(&FsmupDeviceExtension->PrefixTable); + FsmupDeviceExtension->InitDonePfxTab = 1; + + return STATUS_SUCCESS; +} + +static VOID FspFsmupDeviceFini(PDEVICE_OBJECT DeviceObject) +{ + PAGED_CODE(); + + FSP_FSMUP_DEVICE_EXTENSION *FsmupDeviceExtension = FspFsmupDeviceExtension(DeviceObject); + + if (FsmupDeviceExtension->InitDonePfxTab) + { + /* + * Normally we would have to finalize our prefix table. This is not necessary as all + * prefixes will be gone if this code ever gets reached. + */ + ASSERT(0 == RtlNextUnicodePrefix(&FsmupDeviceExtension->PrefixTable, TRUE)); + ExDeleteResourceLite(&FsmupDeviceExtension->PrefixTableResource); + } +} + NTSTATUS FspDeviceCopyList( PDEVICE_OBJECT **PDeviceObjects, PULONG PDeviceObjectCount) { diff --git a/src/sys/driver.c b/src/sys/driver.c index 31ffe1d9..9151cfab 100644 --- a/src/sys/driver.c +++ b/src/sys/driver.c @@ -44,45 +44,6 @@ NTSTATUS DriverEntry( { FSP_ENTER_DRV(); - FspDriverMultiVersionInitialize(); - - Result = FspProcessBufferInitialize(); - if (!NT_SUCCESS(Result)) - FSP_RETURN(); - - FspDriverObject = DriverObject; - ExInitializeResourceLite(&FspDeviceGlobalResource); - - /* create the file system control device objects */ - UNICODE_STRING DeviceSddl; - UNICODE_STRING DeviceName; - RtlInitUnicodeString(&DeviceSddl, L"" FSP_FSCTL_DEVICE_SDDL); - RtlInitUnicodeString(&DeviceName, L"\\Device\\" FSP_FSCTL_DISK_DEVICE_NAME); - Result = FspDeviceCreateSecure(FspFsctlDeviceExtensionKind, 0, - &DeviceName, FILE_DEVICE_DISK_FILE_SYSTEM, FILE_DEVICE_SECURE_OPEN, - &DeviceSddl, &FspFsctlDeviceClassGuid, - &FspFsctlDiskDeviceObject); - if (!NT_SUCCESS(Result)) - { - FspProcessBufferFinalize(); - FSP_RETURN(); - } - RtlInitUnicodeString(&DeviceName, L"\\Device\\" FSP_FSCTL_NET_DEVICE_NAME); - Result = FspDeviceCreateSecure(FspFsctlDeviceExtensionKind, 0, - &DeviceName, FILE_DEVICE_NETWORK_FILE_SYSTEM, FILE_DEVICE_SECURE_OPEN, - &DeviceSddl, &FspFsctlDeviceClassGuid, - &FspFsctlNetDeviceObject); - if (!NT_SUCCESS(Result)) - { - FspDeviceDelete(FspFsctlDiskDeviceObject); - FspProcessBufferFinalize(); - FSP_RETURN(); - } - Result = FspDeviceInitialize(FspFsctlDiskDeviceObject); - ASSERT(STATUS_SUCCESS == Result); - Result = FspDeviceInitialize(FspFsctlNetDeviceObject); - ASSERT(STATUS_SUCCESS == Result); - /* setup the driver object */ #if defined(FSP_UNLOAD) DriverObject->DriverUnload = FspUnload; @@ -127,7 +88,6 @@ NTSTATUS DriverEntry( FspIopCompleteFunction[IRP_MJ_DIRECTORY_CONTROL] = FspFsvolDirectoryControlComplete; FspIopCompleteFunction[IRP_MJ_FILE_SYSTEM_CONTROL] = FspFsvolFileSystemControlComplete; FspIopCompleteFunction[IRP_MJ_DEVICE_CONTROL] = FspFsvolDeviceControlComplete; - FspIopCompleteFunction[IRP_MJ_SHUTDOWN] = FspFsvolShutdownComplete; FspIopCompleteFunction[IRP_MJ_LOCK_CONTROL] = FspFsvolLockControlComplete; FspIopCompleteFunction[IRP_MJ_CLEANUP] = FspFsvolCleanupComplete; FspIopCompleteFunction[IRP_MJ_QUERY_SECURITY] = FspFsvolQuerySecurityComplete; @@ -169,9 +129,58 @@ NTSTATUS DriverEntry( #pragma prefast(suppress:28175, "We are a filesystem: ok to access FastIoDispatch") DriverObject->FastIoDispatch = &FspFastIoDispatch; + BOOLEAN InitDoneGRes = FALSE, InitDonePsBuf = FALSE; + UNICODE_STRING DeviceSddl; + UNICODE_STRING DeviceName; + + FspDriverObject = DriverObject; + ExInitializeResourceLite(&FspDeviceGlobalResource); + InitDoneGRes = TRUE; + + FspDriverMultiVersionInitialize(); + + Result = FspProcessBufferInitialize(); + if (!NT_SUCCESS(Result)) + goto exit; + InitDonePsBuf = TRUE; + + /* create the file system control device objects */ + RtlInitUnicodeString(&DeviceSddl, L"" FSP_FSCTL_DEVICE_SDDL); + RtlInitUnicodeString(&DeviceName, L"\\Device\\" FSP_FSCTL_DISK_DEVICE_NAME); + Result = FspDeviceCreateSecure(FspFsctlDeviceExtensionKind, 0, + &DeviceName, FILE_DEVICE_DISK_FILE_SYSTEM, FILE_DEVICE_SECURE_OPEN, + &DeviceSddl, &FspFsctlDeviceClassGuid, + &FspFsctlDiskDeviceObject); + if (!NT_SUCCESS(Result)) + goto exit; + RtlInitUnicodeString(&DeviceName, L"\\Device\\" FSP_FSCTL_NET_DEVICE_NAME); + Result = FspDeviceCreateSecure(FspFsctlDeviceExtensionKind, 0, + &DeviceName, FILE_DEVICE_NETWORK_FILE_SYSTEM, FILE_DEVICE_SECURE_OPEN, + &DeviceSddl, &FspFsctlDeviceClassGuid, + &FspFsctlNetDeviceObject); + if (!NT_SUCCESS(Result)) + goto exit; + Result = FspDeviceCreate(FspFsmupDeviceExtensionKind, 0, + FILE_DEVICE_NETWORK_FILE_SYSTEM, FILE_REMOTE_DEVICE, + &FspFsmupDeviceObject); + if (!NT_SUCCESS(Result)) + goto exit; + Result = FspDeviceInitialize(FspFsctlDiskDeviceObject); + ASSERT(STATUS_SUCCESS == Result); + Result = FspDeviceInitialize(FspFsctlNetDeviceObject); + ASSERT(STATUS_SUCCESS == Result); + Result = FspDeviceInitialize(FspFsmupDeviceObject); + ASSERT(STATUS_SUCCESS == Result); + + RtlInitUnicodeString(&DeviceName, L"\\Device\\" FSP_FSCTL_MUP_DEVICE_NAME); + Result = FsRtlRegisterUncProviderEx(&FspMupHandle, + &DeviceName, FspFsmupDeviceObject, 0); + if (!NT_SUCCESS(Result)) + goto exit; + /* * Register our "disk" device as a file system. We do not register our "net" device - * as a file system, but we register with the MUP instead at a later time. + * as a file system; we register with the MUP instead. * * Please note that the call below makes our driver unloadable. In fact the driver * remains unloadable even if we issue an IoUnregisterFileSystem() call immediately @@ -180,6 +189,23 @@ NTSTATUS DriverEntry( */ IoRegisterFileSystem(FspFsctlDiskDeviceObject); + Result = STATUS_SUCCESS; + +exit: + if (!NT_SUCCESS(Result)) + { + if (0 != FspFsmupDeviceObject) + FspDeviceDelete(FspFsmupDeviceObject); + if (0 != FspFsctlNetDeviceObject) + FspDeviceDelete(FspFsctlNetDeviceObject); + if (0 != FspFsctlDiskDeviceObject) + FspDeviceDelete(FspFsctlDiskDeviceObject); + if (InitDonePsBuf) + FspProcessBufferFinalize(); + if (InitDoneGRes) + ExDeleteResourceLite(&FspDeviceGlobalResource); + } + #pragma prefast(suppress:28175, "We are in DriverEntry: ok to access DriverName") FSP_LEAVE_DRV("DriverName=\"%wZ\", RegistryPath=\"%wZ\"", &DriverObject->DriverName, RegistryPath); @@ -213,6 +239,7 @@ VOID FspUnload( FspFsctlDiskDeviceObject = 0; FspFsctlNetDeviceObject = 0; + FspFsmupDeviceObject = 0; //FspDeviceDeleteAll(); ExDeleteResourceLite(&FspDeviceGlobalResource); @@ -229,6 +256,8 @@ VOID FspUnload( PDRIVER_OBJECT FspDriverObject; PDEVICE_OBJECT FspFsctlDiskDeviceObject; PDEVICE_OBJECT FspFsctlNetDeviceObject; +PDEVICE_OBJECT FspFsmupDeviceObject; +HANDLE FspMupHandle; FAST_IO_DISPATCH FspFastIoDispatch; CACHE_MANAGER_CALLBACKS FspCacheManagerCallbacks; diff --git a/src/sys/driver.h b/src/sys/driver.h index afb5f5e3..91519f2a 100644 --- a/src/sys/driver.h +++ b/src/sys/driver.h @@ -180,6 +180,8 @@ VOID FspDebugLogIrp(const char *func, PIRP Irp, NTSTATUS Result); #define FSP_LEAVE_DRV(fmt, ...) \ FSP_LEAVE_(FSP_DEBUGLOG_(fmt, " = %s", __VA_ARGS__, NtStatusSym(Result))); return Result #define FSP_ENTER_MJ(...) \ + if (FspFsmupDeviceExtensionKind == FspDeviceExtension(DeviceObject)->Kind)\ + return FspMupHandleIrp(DeviceObject, Irp);\ NTSTATUS Result = STATUS_SUCCESS; \ PIO_STACK_LOCATION IrpSp = IoGetCurrentIrpStackLocation(Irp);\ BOOLEAN fsp_device_deref = FALSE; \ @@ -328,7 +330,6 @@ FSP_IOPREP_DISPATCH FspFsvolSetInformationPrepare; FSP_IOCMPL_DISPATCH FspFsvolSetInformationComplete; FSP_IOCMPL_DISPATCH FspFsvolSetSecurityComplete; FSP_IOCMPL_DISPATCH FspFsvolSetVolumeInformationComplete; -FSP_IOCMPL_DISPATCH FspFsvolShutdownComplete; FSP_IOPREP_DISPATCH FspFsvolWritePrepare; FSP_IOCMPL_DISPATCH FspFsvolWriteComplete; @@ -1007,6 +1008,7 @@ typedef struct enum { FspFsctlDeviceExtensionKind = '\0ltC', /* file system control device (e.g. \Device\WinFsp.Disk) */ + FspFsmupDeviceExtensionKind = '\0puM', /* our own MUP device (linked to \Device\WinFsp.Mup) */ FspFsvrtDeviceExtensionKind = '\0trV', /* virtual volume device (e.g. \Device\Volume{GUID}) */ FspFsvolDeviceExtensionKind = '\0loV', /* file system volume device (unnamed) */ }; @@ -1023,11 +1025,12 @@ typedef struct InitDoneCtxTab:1, InitDoneTimer:1, InitDoneInfo:1, InitDoneNotify:1, InitDoneStat:1; PDEVICE_OBJECT FsctlDeviceObject; PDEVICE_OBJECT FsvrtDeviceObject; - HANDLE MupHandle; + PDEVICE_OBJECT FsvolDeviceObject; PVPB SwapVpb; FSP_DELAYED_WORK_ITEM DeleteVolumeDelayedWorkItem; FSP_FSCTL_VOLUME_PARAMS VolumeParams; UNICODE_STRING VolumePrefix; + UNICODE_PREFIX_TABLE_ENTRY VolumePrefixEntry; FSP_IOQ *Ioq; FSP_META_CACHE *SecurityCache; FSP_META_CACHE *DirInfoCache; @@ -1049,6 +1052,13 @@ typedef struct LIST_ENTRY NotifyList; FSP_STATISTICS *Statistics; } FSP_FSVOL_DEVICE_EXTENSION; +typedef struct +{ + FSP_DEVICE_EXTENSION Base; + UINT32 InitDonePfxTab:1; + ERESOURCE PrefixTableResource; + UNICODE_PREFIX_TABLE PrefixTable; +} FSP_FSMUP_DEVICE_EXTENSION; static inline FSP_DEVICE_EXTENSION *FspDeviceExtension(PDEVICE_OBJECT DeviceObject) { @@ -1060,6 +1070,12 @@ FSP_FSVOL_DEVICE_EXTENSION *FspFsvolDeviceExtension(PDEVICE_OBJECT DeviceObject) ASSERT(FspFsvolDeviceExtensionKind == ((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); + return DeviceObject->DeviceExtension; +} NTSTATUS FspDeviceCreateSecure(UINT32 Kind, ULONG ExtraSize, PUNICODE_STRING DeviceName, DEVICE_TYPE DeviceType, ULONG DeviceCharacteristics, PUNICODE_STRING DeviceSddl, LPCGUID DeviceClassGuid, @@ -1156,6 +1172,14 @@ BOOLEAN FspQueryDirectoryIrpShouldUseProcessBuffer(PIRP Irp, SIZE_T BufferSize) } #endif +/* fsmup */ +BOOLEAN FspMupRegister( + PDEVICE_OBJECT FsmupDeviceObject, PDEVICE_OBJECT FsvolDeviceObject); +VOID FspMupUnregister( + PDEVICE_OBJECT FsmupDeviceObject, PDEVICE_OBJECT FsvolDeviceObject); +NTSTATUS FspMupHandleIrp( + PDEVICE_OBJECT FsmupDeviceObject, PIRP Irp); + /* volume management */ #define FspVolumeTransactEarlyTimeout (1 * 10000ULL) NTSTATUS FspVolumeCreate( @@ -1164,8 +1188,6 @@ VOID FspVolumeDelete( PDEVICE_OBJECT FsctlDeviceObject, PIRP Irp, PIO_STACK_LOCATION IrpSp); NTSTATUS FspVolumeMount( PDEVICE_OBJECT FsctlDeviceObject, PIRP Irp, PIO_STACK_LOCATION IrpSp); -NTSTATUS FspVolumeRedirQueryPathEx( - PDEVICE_OBJECT FsvolDeviceObject, PIRP Irp, PIO_STACK_LOCATION IrpSp); NTSTATUS FspVolumeGetName( PDEVICE_OBJECT FsctlDeviceObject, PIRP Irp, PIO_STACK_LOCATION IrpSp); NTSTATUS FspVolumeGetNameList( @@ -1559,6 +1581,8 @@ FSP_MV_CcCoherencyFlushAndPurgeCache( extern PDRIVER_OBJECT FspDriverObject; extern PDEVICE_OBJECT FspFsctlDiskDeviceObject; extern PDEVICE_OBJECT FspFsctlNetDeviceObject; +extern PDEVICE_OBJECT FspFsmupDeviceObject; +extern HANDLE FspMupHandle; extern FAST_IO_DISPATCH FspFastIoDispatch; extern CACHE_MANAGER_CALLBACKS FspCacheManagerCallbacks; extern FSP_IOPREP_DISPATCH *FspIopPrepareFunction[]; diff --git a/src/sys/mup.c b/src/sys/mup.c new file mode 100644 index 00000000..ecc8431c --- /dev/null +++ b/src/sys/mup.c @@ -0,0 +1,266 @@ +/** + * @file sys/mup.c + * + * @copyright 2015-2018 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 file in + * accordance with the commercial license agreement provided with the + * software. + */ + +#include + +BOOLEAN FspMupRegister( + PDEVICE_OBJECT FsmupDeviceObject, PDEVICE_OBJECT FsvolDeviceObject); +VOID FspMupUnregister( + PDEVICE_OBJECT FsmupDeviceObject, PDEVICE_OBJECT FsvolDeviceObject); +NTSTATUS FspMupHandleIrp( + PDEVICE_OBJECT FsmupDeviceObject, PIRP Irp); +static NTSTATUS FspMupRedirQueryPathEx( + PDEVICE_OBJECT FsmupDeviceObject, PIRP Irp, PIO_STACK_LOCATION IrpSp); + +#ifdef ALLOC_PRAGMA +#pragma alloc_text(PAGE, FspMupRegister) +#pragma alloc_text(PAGE, FspMupUnregister) +#pragma alloc_text(PAGE, FspMupHandleIrp) +#pragma alloc_text(PAGE, FspMupRedirQueryPathEx) +#endif + +BOOLEAN FspMupRegister( + PDEVICE_OBJECT FsmupDeviceObject, PDEVICE_OBJECT FsvolDeviceObject) +{ + PAGED_CODE(); + + BOOLEAN Result; + FSP_FSMUP_DEVICE_EXTENSION *FsmupDeviceExtension = FspFsmupDeviceExtension(FsmupDeviceObject); + FSP_FSVOL_DEVICE_EXTENSION *FsvolDeviceExtension = FspFsvolDeviceExtension(FsvolDeviceObject); + + ExAcquireResourceExclusiveLite(&FsmupDeviceExtension->PrefixTableResource, TRUE); + Result = RtlInsertUnicodePrefix(&FsmupDeviceExtension->PrefixTable, + &FsvolDeviceExtension->VolumePrefix, &FsvolDeviceExtension->VolumePrefixEntry); + if (Result) + FspDeviceReference(FsvolDeviceObject); + ExReleaseResourceLite(&FsmupDeviceExtension->PrefixTableResource); + + return Result; +} + +VOID FspMupUnregister( + PDEVICE_OBJECT FsmupDeviceObject, PDEVICE_OBJECT FsvolDeviceObject) +{ + PAGED_CODE(); + + FSP_FSMUP_DEVICE_EXTENSION *FsmupDeviceExtension = FspFsmupDeviceExtension(FsmupDeviceObject); + FSP_FSVOL_DEVICE_EXTENSION *FsvolDeviceExtension = FspFsvolDeviceExtension(FsvolDeviceObject); + + ExAcquireResourceExclusiveLite(&FsmupDeviceExtension->PrefixTableResource, TRUE); + RtlRemoveUnicodePrefix(&FsmupDeviceExtension->PrefixTable, + &FsvolDeviceExtension->VolumePrefixEntry); + FspDeviceDereference(FsvolDeviceObject); + ExReleaseResourceLite(&FsmupDeviceExtension->PrefixTableResource); +} + +NTSTATUS FspMupHandleIrp( + PDEVICE_OBJECT FsmupDeviceObject, PIRP Irp) +{ + PAGED_CODE(); + + FSP_FSMUP_DEVICE_EXTENSION *FsmupDeviceExtension = FspFsmupDeviceExtension(FsmupDeviceObject); + PIO_STACK_LOCATION IrpSp = IoGetCurrentIrpStackLocation(Irp); + PFILE_OBJECT FileObject = IrpSp->FileObject; + PDEVICE_OBJECT FsvolDeviceObject = 0; + PUNICODE_PREFIX_TABLE_ENTRY Entry; + BOOLEAN DeviceDeref = FALSE; + NTSTATUS Result; + + FsRtlEnterFileSystem(); + + switch (IrpSp->MajorFunction) + { + case IRP_MJ_CREATE: + /* + * A CREATE request with an empty file name indicates that the fsmup device + * is being opened. Check for this case and handle it. + */ + if (0 == FileObject->FileName.Length) + { + Irp->IoStatus.Status = STATUS_SUCCESS; + Irp->IoStatus.Information = FILE_OPENED; + IoCompleteRequest(Irp, FSP_IO_INCREMENT); + Result = Irp->IoStatus.Status; + goto exit; + } + + /* + * Every other CREATE request must be forwarded to the appropriate fsvol device. + */ + + if (0 != FileObject->RelatedFileObject) + FileObject = FileObject->RelatedFileObject; + + ExAcquireResourceExclusiveLite(&FsmupDeviceExtension->PrefixTableResource, TRUE); + Entry = RtlFindUnicodePrefix(&FsmupDeviceExtension->PrefixTable, + &FileObject->FileName, 0); + if (0 != Entry) + { + FsvolDeviceObject = CONTAINING_RECORD(Entry, + FSP_FSVOL_DEVICE_EXTENSION, VolumePrefixEntry)->FsvolDeviceObject; + FspDeviceReference(FsvolDeviceObject); + DeviceDeref = TRUE; + } + ExReleaseResourceLite(&FsmupDeviceExtension->PrefixTableResource); + break; + + case IRP_MJ_DEVICE_CONTROL: + /* + * A DEVICE_CONTROL request with IOCTL_REDIR_QUERY_PATH_EX must be handled + * by the fsmup device. Check for this case and handle it. + */ + if (IOCTL_REDIR_QUERY_PATH_EX == IrpSp->Parameters.DeviceIoControl.IoControlCode) + { + Irp->IoStatus.Status = FspMupRedirQueryPathEx(FsmupDeviceObject, Irp, IrpSp); + IoCompleteRequest(Irp, FSP_IO_INCREMENT); + Result = Irp->IoStatus.Status; + goto exit; + } + + /* + * Every other DEVICE_CONTROL request must be forwarded to the appropriate fsvol device. + */ + + /* fall through! */ + + default: + /* + * Every other request must be forwarded to the appropriate fsvol device. If there is no + * fsvol device, then we must return the appropriate status code (see below). + * + * Please note that since we allow the fsmup device to be opened, we must also handle + * CLEANUP and CLOSE requests for it. + */ + + if (0 != FileObject) + { + if (FspFileNodeIsValid(FileObject->FsContext)) + FsvolDeviceObject = ((FSP_FILE_NODE *)FileObject->FsContext)->FsvolDeviceObject; + else if (0 != FileObject->FsContext2 && + 3 == ((PDEVICE_OBJECT)FileObject->FsContext2)->Type && + 0 != ((PDEVICE_OBJECT)FileObject->FsContext2)->DeviceExtension && + FspFsvolDeviceExtensionKind == FspDeviceExtension((PDEVICE_OBJECT)FileObject->FsContext2)->Kind) + FsvolDeviceObject = (PDEVICE_OBJECT)FileObject->FsContext2; + } + break; + } + + if (0 == FsvolDeviceObject) + { + /* + * We were not able to find an fsvol device to forward this IRP to. We will complete + * the IRP with an appropriate status code. + */ + + switch (IrpSp->MajorFunction) + { + case IRP_MJ_CLEANUP: + case IRP_MJ_CLOSE: + /* + * CLEANUP and CLOSE requests ignore their status code (except for STATUS_PENDING). + * So return STATUS_SUCCESS. This works regardless of whether this is a legitimate + * fsmup request or an erroneous CLOSE request that we should not have seen. + */ + Irp->IoStatus.Status = STATUS_SUCCESS; + break; + case IRP_MJ_QUERY_INFORMATION: + case IRP_MJ_SET_INFORMATION: + Irp->IoStatus.Status = STATUS_INVALID_PARAMETER; + break; + default: + Irp->IoStatus.Status = STATUS_INVALID_DEVICE_REQUEST; + break; + } + + Irp->IoStatus.Information = 0; + IoCompleteRequest(Irp, FSP_IO_INCREMENT); + Result = Irp->IoStatus.Status; + goto exit; + } + + ASSERT(FspFsvolDeviceExtensionKind == FspDeviceExtension(FsvolDeviceObject)->Kind); + + /* + * Forward the IRP to the appropriate fsvol device. The fsvol device will take care + * to complete the IRP, etc. + */ + IoSkipCurrentIrpStackLocation(Irp); + Result = IoCallDriver(FsvolDeviceObject, Irp); + + if (DeviceDeref) + FspDeviceDereference(FsvolDeviceObject); + +exit: + FsRtlExitFileSystem(); + + return Result; +} + +static NTSTATUS FspMupRedirQueryPathEx( + PDEVICE_OBJECT FsmupDeviceObject, PIRP Irp, PIO_STACK_LOCATION IrpSp) +{ + PAGED_CODE(); + + ASSERT(IRP_MJ_DEVICE_CONTROL == IrpSp->MajorFunction); + ASSERT(IOCTL_REDIR_QUERY_PATH_EX == IrpSp->Parameters.DeviceIoControl.IoControlCode); + + Irp->IoStatus.Information = 0; + + if (KernelMode != Irp->RequestorMode) + return STATUS_INVALID_DEVICE_REQUEST; + + /* check parameters */ + ULONG InputBufferLength = IrpSp->Parameters.DeviceIoControl.InputBufferLength; + ULONG OutputBufferLength = IrpSp->Parameters.DeviceIoControl.OutputBufferLength; + QUERY_PATH_REQUEST_EX *QueryPathRequest = IrpSp->Parameters.DeviceIoControl.Type3InputBuffer; + QUERY_PATH_RESPONSE *QueryPathResponse = Irp->UserBuffer; + if (sizeof(QUERY_PATH_REQUEST_EX) > InputBufferLength || + 0 == QueryPathRequest || 0 == QueryPathResponse) + return STATUS_INVALID_PARAMETER; + if (sizeof(QUERY_PATH_RESPONSE) > OutputBufferLength) + return STATUS_BUFFER_TOO_SMALL; + + NTSTATUS Result; + FSP_FSMUP_DEVICE_EXTENSION *FsmupDeviceExtension = FspFsmupDeviceExtension(FsmupDeviceObject); + FSP_FSVOL_DEVICE_EXTENSION *FsvolDeviceExtension; + PUNICODE_PREFIX_TABLE_ENTRY Entry; + PDEVICE_OBJECT FsvolDeviceObject = 0; + + Result = STATUS_BAD_NETWORK_PATH; + ExAcquireResourceExclusiveLite(&FsmupDeviceExtension->PrefixTableResource, TRUE); + Entry = RtlFindUnicodePrefix(&FsmupDeviceExtension->PrefixTable, + &QueryPathRequest->PathName, 0); + if (0 != Entry) + { + FsvolDeviceExtension = CONTAINING_RECORD(Entry, FSP_FSVOL_DEVICE_EXTENSION, VolumePrefixEntry); + FsvolDeviceObject = FsvolDeviceExtension->FsvolDeviceObject; + if (!FspIoqStopped(FsvolDeviceExtension->Ioq)) + { + if (0 < FsvolDeviceExtension->VolumePrefix.Length && + FspFsvolDeviceVolumePrefixInString(FsvolDeviceObject, &QueryPathRequest->PathName) && + (QueryPathRequest->PathName.Length == FsvolDeviceExtension->VolumePrefix.Length || + '\\' == QueryPathRequest->PathName.Buffer[FsvolDeviceExtension->VolumePrefix.Length / sizeof(WCHAR)])) + { + QueryPathResponse->LengthAccepted = FsvolDeviceExtension->VolumePrefix.Length; + Result = STATUS_SUCCESS; + } + } + } + ExReleaseResourceLite(&FsmupDeviceExtension->PrefixTableResource); + + return Result; +} diff --git a/src/sys/shutdown.c b/src/sys/shutdown.c index 576014e8..0cbd3485 100644 --- a/src/sys/shutdown.c +++ b/src/sys/shutdown.c @@ -17,45 +17,18 @@ #include -static NTSTATUS FspFsvolShutdown( - PDEVICE_OBJECT DeviceObject, PIRP Irp, PIO_STACK_LOCATION IrpSp); FSP_DRIVER_DISPATCH FspShutdown; -FSP_IOCMPL_DISPATCH FspFsvolShutdownComplete; #ifdef ALLOC_PRAGMA -#pragma alloc_text(PAGE, FspFsvolShutdown) -#pragma alloc_text(PAGE, FspFsvolShutdownComplete) #pragma alloc_text(PAGE, FspShutdown) #endif -static NTSTATUS FspFsvolShutdown( - PDEVICE_OBJECT DeviceObject, PIRP Irp, PIO_STACK_LOCATION IrpSp) -{ - PAGED_CODE(); - - return STATUS_INVALID_DEVICE_REQUEST; -} - -NTSTATUS FspFsvolShutdownComplete( - PIRP Irp, const FSP_FSCTL_TRANSACT_RSP *Response) -{ - FSP_ENTER_IOC(PAGED_CODE()); - - FSP_LEAVE_IOC("%s", ""); -} - NTSTATUS FspShutdown( PDEVICE_OBJECT DeviceObject, PIRP Irp) { FSP_ENTER_MJ(PAGED_CODE()); - switch (FspDeviceExtension(DeviceObject)->Kind) - { - case FspFsvolDeviceExtensionKind: - FSP_RETURN(Result = FspFsvolShutdown(DeviceObject, Irp, IrpSp)); - default: - FSP_RETURN(Result = STATUS_INVALID_DEVICE_REQUEST); - } + FSP_RETURN(Result = STATUS_INVALID_DEVICE_REQUEST); FSP_LEAVE_MJ("%s", ""); } diff --git a/src/sys/volume.c b/src/sys/volume.c index 4c0b30a7..4be4ec45 100644 --- a/src/sys/volume.c +++ b/src/sys/volume.c @@ -21,7 +21,6 @@ NTSTATUS FspVolumeCreate( PDEVICE_OBJECT FsctlDeviceObject, PIRP Irp, PIO_STACK_LOCATION IrpSp); static NTSTATUS FspVolumeCreateNoLock( PDEVICE_OBJECT FsctlDeviceObject, PIRP Irp, PIO_STACK_LOCATION IrpSp); -static WORKER_THREAD_ROUTINE FspVolumeCreateRegisterMup; VOID FspVolumeDelete( PDEVICE_OBJECT FsctlDeviceObject, PIRP Irp, PIO_STACK_LOCATION IrpSp); static VOID FspVolumeDeleteNoLock( @@ -31,8 +30,6 @@ NTSTATUS FspVolumeMount( PDEVICE_OBJECT FsctlDeviceObject, PIRP Irp, PIO_STACK_LOCATION IrpSp); static NTSTATUS FspVolumeMountNoLock( PDEVICE_OBJECT FsctlDeviceObject, PIRP Irp, PIO_STACK_LOCATION IrpSp); -NTSTATUS FspVolumeRedirQueryPathEx( - PDEVICE_OBJECT FsvolDeviceObject, PIRP Irp, PIO_STACK_LOCATION IrpSp); NTSTATUS FspVolumeGetName( PDEVICE_OBJECT FsctlDeviceObject, PIRP Irp, PIO_STACK_LOCATION IrpSp); NTSTATUS FspVolumeGetNameList( @@ -49,13 +46,11 @@ NTSTATUS FspVolumeWork( #ifdef ALLOC_PRAGMA #pragma alloc_text(PAGE, FspVolumeCreate) #pragma alloc_text(PAGE, FspVolumeCreateNoLock) -#pragma alloc_text(PAGE, FspVolumeCreateRegisterMup) // ! #pragma alloc_text(PAGE, FspVolumeDelete) // ! #pragma alloc_text(PAGE, FspVolumeDeleteNoLock) // ! #pragma alloc_text(PAGE, FspVolumeDeleteDelayed) // ! #pragma alloc_text(PAGE, FspVolumeMount) // ! #pragma alloc_text(PAGE, FspVolumeMountNoLock) -#pragma alloc_text(PAGE, FspVolumeRedirQueryPathEx) #pragma alloc_text(PAGE, FspVolumeGetName) #pragma alloc_text(PAGE, FspVolumeGetNameList) #pragma alloc_text(PAGE, FspVolumeGetNameListNoLock) @@ -67,13 +62,6 @@ NTSTATUS FspVolumeWork( #define PREFIXW L"" FSP_FSCTL_VOLUME_PARAMS_PREFIX #define PREFIXW_SIZE (sizeof PREFIXW - sizeof(WCHAR)) -typedef struct -{ - PDEVICE_OBJECT FsvolDeviceObject; - NTSTATUS Result; - FSP_SYNCHRONOUS_WORK_ITEM SynchronousWorkItem; -} FSP_CREATE_VOLUME_REGISTER_MUP_WORK_ITEM; - NTSTATUS FspVolumeCreate( PDEVICE_OBJECT FsctlDeviceObject, PIRP Irp, PIO_STACK_LOCATION IrpSp) { @@ -106,11 +94,11 @@ static NTSTATUS FspVolumeCreateNoLock( GUID Guid; UNICODE_STRING DeviceSddl; UNICODE_STRING VolumeName; + UNICODE_STRING FsmupDeviceName; WCHAR VolumeNameBuf[FSP_FSCTL_VOLUME_NAME_SIZE / sizeof(WCHAR)]; PDEVICE_OBJECT FsvolDeviceObject; PDEVICE_OBJECT FsvrtDeviceObject; FSP_FSVOL_DEVICE_EXTENSION *FsvolDeviceExtension; - FSP_CREATE_VOLUME_REGISTER_MUP_WORK_ITEM RegisterMupWorkItem; /* check parameters */ if (PREFIXW_SIZE + sizeof(FSP_FSCTL_VOLUME_PARAMS) * sizeof(WCHAR) > FileObject->FileName.Length) @@ -225,6 +213,7 @@ static NTSTATUS FspVolumeCreateNoLock( FsvolDeviceExtension = FspFsvolDeviceExtension(FsvolDeviceObject); FsvolDeviceExtension->FsctlDeviceObject = FsctlDeviceObject; FsvolDeviceExtension->FsvrtDeviceObject = FsvrtDeviceObject; + FsvolDeviceExtension->FsvolDeviceObject = FsvolDeviceObject; FsvolDeviceExtension->VolumeParams = VolumeParams; if (FILE_DEVICE_NETWORK_FILE_SYSTEM == FsctlDeviceObject->DeviceType) RtlInitUnicodeString(&FsvolDeviceExtension->VolumePrefix, @@ -245,24 +234,20 @@ static NTSTATUS FspVolumeCreateNoLock( FspDeviceDereference(FsvolDeviceObject); } - /* do we need to register with MUP? */ + /* do we need to register with fsmup? */ if (0 == FsvrtDeviceObject) { - /* - * Turns out we cannot call FsRtlRegisterUncProviderEx when the PreviousMode - * is UserMode! So we need to somehow switch to KernelMode prior to issuing - * the FsRtlRegisterUncProviderEx call. There seems to be no straightforward - * way to switch the PreviousMode (no ExSetPreviousMode). So we do it indirectly - * by executing a synchronous work item (FspExecuteSynchronousWorkItem). - */ - RtlZeroMemory(&RegisterMupWorkItem, sizeof RegisterMupWorkItem); - RegisterMupWorkItem.FsvolDeviceObject = FsvolDeviceObject; - FspInitializeSynchronousWorkItem(&RegisterMupWorkItem.SynchronousWorkItem, - FspVolumeCreateRegisterMup, &RegisterMupWorkItem); - FspExecuteSynchronousWorkItem(&RegisterMupWorkItem.SynchronousWorkItem); - Result = RegisterMupWorkItem.Result; + if (!FspMupRegister(FspFsmupDeviceObject, FsvolDeviceObject)) + { + FspDeviceDereference(FsvolDeviceObject); + return STATUS_OBJECT_NAME_COLLISION; + } + + RtlInitUnicodeString(&FsmupDeviceName, L"\\Device\\" FSP_FSCTL_MUP_DEVICE_NAME); + Result = IoCreateSymbolicLink(&FsvolDeviceExtension->VolumeName, &FsmupDeviceName); if (!NT_SUCCESS(Result)) { + FspMupUnregister(FspFsmupDeviceObject, FsvolDeviceObject); FspDeviceDereference(FsvolDeviceObject); return Result; } @@ -275,18 +260,6 @@ static NTSTATUS FspVolumeCreateNoLock( return STATUS_SUCCESS; } -static VOID FspVolumeCreateRegisterMup(PVOID Context) -{ - PAGED_CODE(); - - FSP_CREATE_VOLUME_REGISTER_MUP_WORK_ITEM *RegisterMupWorkItem = Context; - PDEVICE_OBJECT FsvolDeviceObject = RegisterMupWorkItem->FsvolDeviceObject; - FSP_FSVOL_DEVICE_EXTENSION *FsvolDeviceExtension = FspFsvolDeviceExtension(FsvolDeviceObject); - - RegisterMupWorkItem->Result = FsRtlRegisterUncProviderEx(&FsvolDeviceExtension->MupHandle, - &FsvolDeviceExtension->VolumeName, FsvolDeviceObject, 0); -} - VOID FspVolumeDelete( PDEVICE_OBJECT FsctlDeviceObject, PIRP Irp, PIO_STACK_LOCATION IrpSp) { @@ -333,7 +306,7 @@ static VOID FspVolumeDeleteNoLock( /* stop the I/O queue */ FspIoqStop(FsvolDeviceExtension->Ioq); - /* do we have a virtual disk device or a MUP handle? */ + /* do we have a virtual disk device or are we registered with fsmup? */ if (0 != FsvolDeviceExtension->FsvrtDeviceObject) { PDEVICE_OBJECT FsvrtDeviceObject = FsvolDeviceExtension->FsvrtDeviceObject; @@ -391,10 +364,10 @@ static VOID FspVolumeDeleteNoLock( FspQueueDelayedWorkItem(&FsvolDeviceExtension->DeleteVolumeDelayedWorkItem, Delay); } } - else if (0 != FsvolDeviceExtension->MupHandle) + else { - FsRtlDeregisterUncProvider(FsvolDeviceExtension->MupHandle); - FsvolDeviceExtension->MupHandle = 0; + IoDeleteSymbolicLink(&FsvolDeviceExtension->VolumeName); + FspMupUnregister(FspFsmupDeviceObject, FsvolDeviceObject); } /* release the volume device object */ @@ -515,49 +488,6 @@ static NTSTATUS FspVolumeMountNoLock( return STATUS_SUCCESS; } -NTSTATUS FspVolumeRedirQueryPathEx( - PDEVICE_OBJECT FsvolDeviceObject, PIRP Irp, PIO_STACK_LOCATION IrpSp) -{ - PAGED_CODE(); - - ASSERT(IRP_MJ_DEVICE_CONTROL == IrpSp->MajorFunction); - ASSERT(IOCTL_REDIR_QUERY_PATH_EX == IrpSp->Parameters.DeviceIoControl.IoControlCode); - - if (KernelMode != Irp->RequestorMode) - return STATUS_INVALID_DEVICE_REQUEST; - - /* check parameters */ - ULONG InputBufferLength = IrpSp->Parameters.DeviceIoControl.InputBufferLength; - ULONG OutputBufferLength = IrpSp->Parameters.DeviceIoControl.OutputBufferLength; - QUERY_PATH_REQUEST_EX *QueryPathRequest = IrpSp->Parameters.DeviceIoControl.Type3InputBuffer; - QUERY_PATH_RESPONSE *QueryPathResponse = Irp->UserBuffer; - if (sizeof(QUERY_PATH_REQUEST_EX) > InputBufferLength || - 0 == QueryPathRequest || 0 == QueryPathResponse) - return STATUS_INVALID_PARAMETER; - if (sizeof(QUERY_PATH_RESPONSE) > OutputBufferLength) - return STATUS_BUFFER_TOO_SMALL; - - NTSTATUS Result; - FSP_FSVOL_DEVICE_EXTENSION *FsvolDeviceExtension = FspFsvolDeviceExtension(FsvolDeviceObject); - - Result = STATUS_BAD_NETWORK_PATH; - if (!FspIoqStopped(FsvolDeviceExtension->Ioq)) - { - if (0 < FsvolDeviceExtension->VolumePrefix.Length && - FspFsvolDeviceVolumePrefixInString(FsvolDeviceObject, &QueryPathRequest->PathName) && - (QueryPathRequest->PathName.Length == FsvolDeviceExtension->VolumePrefix.Length || - '\\' == QueryPathRequest->PathName.Buffer[FsvolDeviceExtension->VolumePrefix.Length / sizeof(WCHAR)])) - { - QueryPathResponse->LengthAccepted = FsvolDeviceExtension->VolumePrefix.Length; - - Irp->IoStatus.Information = 0; - Result = STATUS_SUCCESS; - } - } - - return Result; -} - NTSTATUS FspVolumeGetName( PDEVICE_OBJECT FsctlDeviceObject, PIRP Irp, PIO_STACK_LOCATION IrpSp) {