diff --git a/build/VStudio/winfsp_sys.vcxproj b/build/VStudio/winfsp_sys.vcxproj
index 0bbf7bee..2177afe5 100644
--- a/build/VStudio/winfsp_sys.vcxproj
+++ b/build/VStudio/winfsp_sys.vcxproj
@@ -167,6 +167,7 @@
+
diff --git a/build/VStudio/winfsp_sys.vcxproj.filters b/build/VStudio/winfsp_sys.vcxproj.filters
index eff809c7..fea8d778 100644
--- a/build/VStudio/winfsp_sys.vcxproj.filters
+++ b/build/VStudio/winfsp_sys.vcxproj.filters
@@ -80,6 +80,9 @@
Source
+
+ Source
+
diff --git a/inc/winfsp/fsctl.h b/inc/winfsp/fsctl.h
index 7dc171d9..48eddb97 100644
--- a/inc/winfsp/fsctl.h
+++ b/inc/winfsp/fsctl.h
@@ -9,6 +9,11 @@
#include
+#define FSP_FSCTL_DISK_DEVICE_NAME "WinFsp.Disk"
+#define FSP_FSCTL_NET_DEVICE_NAME "WinFsp.Net"
+
+#define FSP_FSCTL_VOLUME_PARAMS_PREFIX "\\VolumeParams="
+
// {6F9D25FA-6DEE-4A9D-80F5-E98E14F35E54}
extern const __declspec(selectany) GUID FspFsctlDeviceClassGuid =
{ 0x6f9d25fa, 0x6dee, 0x4a9d, { 0x80, 0xf5, 0xe9, 0x8e, 0x14, 0xf3, 0x5e, 0x54 } };
@@ -16,9 +21,6 @@ extern const __declspec(selectany) GUID FspFsctlDeviceClassGuid =
extern const __declspec(selectany) GUID FspFsvrtDeviceClassGuid =
{ 0xb48171c3, 0xdd50, 0x4852, { 0x83, 0xa3, 0x34, 0x4c, 0x50, 0xd9, 0x3b, 0x17 } };
-#define FSP_FSCTL_DISK_DEVICE_NAME "WinFsp.Disk"
-#define FSP_FSCTL_NET_DEVICE_NAME "WinFsp.Net"
-
/* alignment macros */
#define FSP_FSCTL_ALIGN_UP(x, s) (((x) + ((s) - 1L)) & ~((s) - 1L))
#define FSP_FSCTL_DEFAULT_ALIGNMENT 8
@@ -26,12 +28,13 @@ extern const __declspec(selectany) GUID FspFsvrtDeviceClassGuid =
#define FSP_FSCTL_DECLSPEC_ALIGN __declspec(align(FSP_FSCTL_DEFAULT_ALIGNMENT))
/* fsctl device codes */
-#define FSP_FSCTL_CREATE \
- CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 0x800 + 'C', METHOD_BUFFERED, FILE_ANY_ACCESS)
+#define FSP_FSCTL_VOLUME_NAME \
+ CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 0x800 + 'N', METHOD_BUFFERED, FILE_ANY_ACCESS)
#define FSP_FSCTL_TRANSACT \
CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 0x800 + 'T', METHOD_OUT_DIRECT, FILE_ANY_ACCESS)
-#define FSP_FSCTL_CREATE_BUFFER_SIZEMIN 128
+#define FSP_FSCTL_VOLUME_NAME_SIZEMAX 128
+
#define FSP_FSCTL_TRANSACT_REQ_BUFFER_SIZEMIN 16384 /* checked by driver! */
#define FSP_FSCTL_TRANSACT_REQ_SIZEMAX (4096 - 64) /* 64: size for internal request header */
#define FSP_FSCTL_TRANSACT_RSP_SIZEMAX (4096 - 64) /* symmetry! */
diff --git a/src/sys/cleanup.c b/src/sys/cleanup.c
index 3ff58fb4..ad1e1dee 100644
--- a/src/sys/cleanup.c
+++ b/src/sys/cleanup.c
@@ -23,15 +23,12 @@ FSP_DRIVER_DISPATCH FspCleanup;
#pragma alloc_text(PAGE, FspCleanup)
#endif
-VOID FspFsctlDeleteVolume(
- PDEVICE_OBJECT DeviceObject, PIRP Irp, PIO_STACK_LOCATION IrpSp);
-
static NTSTATUS FspFsctlCleanup(
PDEVICE_OBJECT DeviceObject, PIRP Irp, PIO_STACK_LOCATION IrpSp)
{
PAGED_CODE();
- FspFsctlDeleteVolume(DeviceObject, Irp, IrpSp);
+ FspVolumeDelete(DeviceObject, Irp, IrpSp);
Irp->IoStatus.Information = 0;
return STATUS_SUCCESS;
diff --git a/src/sys/create.c b/src/sys/create.c
index 61e8e94d..817910f8 100644
--- a/src/sys/create.c
+++ b/src/sys/create.c
@@ -27,22 +27,28 @@ FSP_DRIVER_DISPATCH FspCreate;
#pragma alloc_text(PAGE, FspCreate)
#endif
+#define PREFIXW L"" FSP_FSCTL_VOLUME_PARAMS_PREFIX
+#define PREFIXW_SIZE (sizeof PREFIXW - sizeof(WCHAR))
+
static NTSTATUS FspFsctlCreate(
PDEVICE_OBJECT DeviceObject, PIRP Irp, PIO_STACK_LOCATION IrpSp)
{
PAGED_CODE();
- FSP_FSCTL_FILE_CONTEXT2 *FsContext2;
- FsContext2 = FspAllocNonPaged(sizeof *FsContext2);
- if (0 == FsContext2)
- return STATUS_INSUFFICIENT_RESOURCES;
+ NTSTATUS Result;
+ PFILE_OBJECT FileObject = IrpSp->FileObject;
- RtlZeroMemory(FsContext2, sizeof *FsContext2);
- ExInitializeFastMutex(&FsContext2->FastMutex);
- IrpSp->FileObject->FsContext2 = FsContext2;
+ if (0 == FileObject->RelatedFileObject &&
+ PREFIXW_SIZE <= FileObject->FileName.Length &&
+ RtlEqualMemory(PREFIXW, FileObject->FileName.Buffer, PREFIXW_SIZE))
+ Result = FspVolumeCreate(DeviceObject, Irp, IrpSp);
+ else
+ {
+ Result = STATUS_SUCCESS;
+ Irp->IoStatus.Information = FILE_OPENED;
+ }
- Irp->IoStatus.Information = FILE_OPENED;
- return STATUS_SUCCESS;
+ return Result;
}
static NTSTATUS FspFsvrtCreate(
diff --git a/src/sys/debug.c b/src/sys/debug.c
index 8c5fa6a4..90638cdc 100644
--- a/src/sys/debug.c
+++ b/src/sys/debug.c
@@ -153,7 +153,7 @@ const char *IoctlCodeSym(ULONG ControlCode)
{
switch (ControlCode)
{
- SYM(FSP_FSCTL_CREATE)
+ SYM(FSP_FSCTL_VOLUME_NAME)
SYM(FSP_FSCTL_TRANSACT)
SYM(FSP_FSCTL_WORK)
// cygwin: sed -n '/[IF][OS]CTL.*CTL_CODE/s/^#define[ \t]*\([^ \t]*\).*/SYM(\1)/p'
diff --git a/src/sys/devctl.c b/src/sys/devctl.c
index 8e6f9d26..aae85ed6 100644
--- a/src/sys/devctl.c
+++ b/src/sys/devctl.c
@@ -8,14 +8,11 @@
static NTSTATUS FspFsvolDeviceControl(
PDEVICE_OBJECT DeviceObject, PIRP Irp, PIO_STACK_LOCATION IrpSp);
-static NTSTATUS FspFsvolRedirQueryPathEx(
- PDEVICE_OBJECT DeviceObject, PIRP Irp, PIO_STACK_LOCATION IrpSp);
FSP_IOCMPL_DISPATCH FspFsvolDeviceControlComplete;
FSP_DRIVER_DISPATCH FspDeviceControl;
#ifdef ALLOC_PRAGMA
#pragma alloc_text(PAGE, FspFsvolDeviceControl)
-#pragma alloc_text(PAGE, FspFsvolRedirQueryPathEx)
#pragma alloc_text(PAGE, FspFsvolDeviceControlComplete)
#pragma alloc_text(PAGE, FspDeviceControl)
#endif
@@ -29,21 +26,13 @@ static NTSTATUS FspFsvolDeviceControl(
switch (IrpSp->Parameters.DeviceIoControl.IoControlCode)
{
case IOCTL_REDIR_QUERY_PATH_EX :
- Result = FspFsvolRedirQueryPathEx(DeviceObject, Irp, IrpSp);
+ Result = FspVolumeRedirQueryPathEx(DeviceObject, Irp, IrpSp);
break;
}
return Result;
}
-static NTSTATUS FspFsvolRedirQueryPathEx(
- PDEVICE_OBJECT DeviceObject, PIRP Irp, PIO_STACK_LOCATION IrpSp)
-{
- PAGED_CODE();
-
- return STATUS_INVALID_DEVICE_REQUEST;
-}
-
VOID FspFsvolDeviceControlComplete(
PIRP Irp, const FSP_FSCTL_TRANSACT_RSP *Response)
{
diff --git a/src/sys/device.c b/src/sys/device.c
index 3ab97ff6..226faaf6 100644
--- a/src/sys/device.c
+++ b/src/sys/device.c
@@ -293,6 +293,10 @@ static NTSTATUS FspFsvolDeviceInit(PDEVICE_OBJECT DeviceObject)
RtlInitializeGenericTableAvl(&FsvolDeviceExtension->GenericTable,
FspFsvolDeviceCompareElement, FspFsvolDeviceAllocateElement, FspFsvolDeviceFreeElement, 0);
+ /* initialize the volume name buffer */
+ RtlInitEmptyUnicodeString(&FsvolDeviceExtension->VolumeName,
+ FsvolDeviceExtension->VolumeNameBuf, sizeof FsvolDeviceExtension->VolumeNameBuf);
+
return STATUS_SUCCESS;
}
diff --git a/src/sys/driver.h b/src/sys/driver.h
index 2bb0e6d2..b5689190 100644
--- a/src/sys/driver.h
+++ b/src/sys/driver.h
@@ -339,6 +339,7 @@ NTSTATUS FspIopDispatchPrepare(PIRP Irp, FSP_FSCTL_TRANSACT_REQ *Request);
VOID FspIopDispatchComplete(PIRP Irp, const FSP_FSCTL_TRANSACT_RSP *Response);
/* device management */
+#define FSP_DEVICE_VOLUME_NAME_LENMAX (FSP_FSCTL_VOLUME_NAME_SIZEMAX - sizeof(WCHAR))
typedef struct
{
UINT64 Identifier;
@@ -378,6 +379,8 @@ typedef struct
FAST_MUTEX GenericTableFastMutex;
RTL_AVL_TABLE GenericTable;
PVOID GenericTableElementStorage;
+ UNICODE_STRING VolumeName;
+ WCHAR VolumeNameBuf[FSP_DEVICE_VOLUME_NAME_LENMAX / sizeof(WCHAR)];
} FSP_FSVOL_DEVICE_EXTENSION;
static inline
FSP_DEVICE_EXTENSION *FspDeviceExtension(PDEVICE_OBJECT DeviceObject)
@@ -418,12 +421,21 @@ VOID FspDeviceDeleteList(
PDEVICE_OBJECT *DeviceObjects, ULONG DeviceObjectCount);
VOID FspDeviceDeleteAll(VOID);
-/* fsctl file objects */
-typedef struct
-{
- FAST_MUTEX FastMutex;
- PDEVICE_OBJECT FsvolDeviceObject;
-} FSP_FSCTL_FILE_CONTEXT2;
+/* volume management */
+NTSTATUS FspVolumeCreate(
+ PDEVICE_OBJECT FsctlDeviceObject, PIRP Irp, PIO_STACK_LOCATION IrpSp);
+VOID FspVolumeDelete(
+ PDEVICE_OBJECT FsctlDeviceObject, PIRP Irp, PIO_STACK_LOCATION IrpSp);
+NTSTATUS FspVolumeGetName(
+ PDEVICE_OBJECT FsctlDeviceObject, PIRP Irp, PIO_STACK_LOCATION IrpSp);
+NTSTATUS FspVolumeMount(
+ PDEVICE_OBJECT FsctlDeviceObject, PIRP Irp, PIO_STACK_LOCATION IrpSp);
+NTSTATUS FspVolumeTransact(
+ PDEVICE_OBJECT FsctlDeviceObject, PIRP Irp, PIO_STACK_LOCATION IrpSp);
+NTSTATUS FspVolumeRedirQueryPathEx(
+ PDEVICE_OBJECT FsvolDeviceObject, PIRP Irp, PIO_STACK_LOCATION IrpSp);
+NTSTATUS FspVolumeWork(
+ PDEVICE_OBJECT FsvolDeviceObject, PIRP Irp, PIO_STACK_LOCATION IrpSp);
/* debug */
#if DBG
diff --git a/src/sys/fsctl.c b/src/sys/fsctl.c
index 1f79e629..6f79f32a 100644
--- a/src/sys/fsctl.c
+++ b/src/sys/fsctl.c
@@ -8,48 +8,18 @@
static NTSTATUS FspFsctlFileSystemControl(
PDEVICE_OBJECT DeviceObject, PIRP Irp, PIO_STACK_LOCATION IrpSp);
-static NTSTATUS FspFsctlCreateVolume(
- PDEVICE_OBJECT DeviceObject, PIRP Irp, PIO_STACK_LOCATION IrpSp);
-static NTSTATUS FspFsctlMountVolume(
- PDEVICE_OBJECT DeviceObject, PIRP Irp, PIO_STACK_LOCATION IrpSp);
-VOID FspFsctlDeleteVolume(
- PDEVICE_OBJECT DeviceObject, PIRP Irp, PIO_STACK_LOCATION IrpSp);
-static WORKER_THREAD_ROUTINE FspFsctlDeleteVolumeDelayed;
-static NTSTATUS FspFsctlTransact(
- PDEVICE_OBJECT DeviceObject, PIRP Irp, PIO_STACK_LOCATION IrpSp);
static NTSTATUS FspFsvolFileSystemControl(
PDEVICE_OBJECT DeviceObject, PIRP Irp, PIO_STACK_LOCATION IrpSp);
-static NTSTATUS FspFsvolWork(
- PDEVICE_OBJECT DeviceObject, PIRP Irp, PIO_STACK_LOCATION IrpSp);
FSP_IOCMPL_DISPATCH FspFsvolFileSystemControlComplete;
FSP_DRIVER_DISPATCH FspFileSystemControl;
#ifdef ALLOC_PRAGMA
#pragma alloc_text(PAGE, FspFsctlFileSystemControl)
-#pragma alloc_text(PAGE, FspFsctlCreateVolume)
-#pragma alloc_text(PAGE, FspFsctlMountVolume)
-#pragma alloc_text(PAGE, FspFsctlDeleteVolume)
-#pragma alloc_text(PAGE, FspFsctlDeleteVolumeDelayed)
-#pragma alloc_text(PAGE, FspFsctlTransact)
#pragma alloc_text(PAGE, FspFsvolFileSystemControl)
-#pragma alloc_text(PAGE, FspFsvolWork)
#pragma alloc_text(PAGE, FspFsvolFileSystemControlComplete)
#pragma alloc_text(PAGE, FspFileSystemControl)
#endif
-static inline PDEVICE_OBJECT FspFsvolDeviceObjectFromFileObject(PFILE_OBJECT FileObject)
-{
- PDEVICE_OBJECT FsvolDeviceObject;
- FSP_FSCTL_FILE_CONTEXT2 *FsContext2 = FileObject->FsContext2;
-
- ExAcquireFastMutex(&FsContext2->FastMutex);
- FsvolDeviceObject = FsContext2->FsvolDeviceObject;
- ExReleaseFastMutex(&FsContext2->FastMutex);
-
- /* no FspDeviceRetain on the volume device, because it exists until the FileObject IRP_MJ_CLEANUP */
- return FsvolDeviceObject;
-}
-
static NTSTATUS FspFsctlFileSystemControl(
PDEVICE_OBJECT DeviceObject, PIRP Irp, PIO_STACK_LOCATION IrpSp)
{
@@ -61,440 +31,22 @@ static NTSTATUS FspFsctlFileSystemControl(
case IRP_MN_USER_FS_REQUEST:
switch (IrpSp->Parameters.FileSystemControl.FsControlCode)
{
- case FSP_FSCTL_CREATE:
- Result = FspFsctlCreateVolume(DeviceObject, Irp, IrpSp);
+ case FSP_FSCTL_VOLUME_NAME:
+ Result = FspVolumeGetName(DeviceObject, Irp, IrpSp);
break;
case FSP_FSCTL_TRANSACT:
- Result = FspFsctlTransact(DeviceObject, Irp, IrpSp);
+ Result = FspVolumeTransact(DeviceObject, Irp, IrpSp);
break;
}
break;
case IRP_MN_MOUNT_VOLUME:
- Result = FspFsctlMountVolume(DeviceObject, Irp, IrpSp);
+ Result = FspVolumeMount(DeviceObject, Irp, IrpSp);
break;
-#if 0
- case IRP_MN_VERIFY_VOLUME:
- break;
-#endif
}
return Result;
}
-static NTSTATUS FspFsctlCreateVolume(
- PDEVICE_OBJECT DeviceObject, PIRP Irp, PIO_STACK_LOCATION IrpSp)
-{
- PAGED_CODE();
-
- /* check parameters */
- ULONG InputBufferLength = IrpSp->Parameters.FileSystemControl.InputBufferLength;
- ULONG OutputBufferLength = IrpSp->Parameters.FileSystemControl.OutputBufferLength;
- PVOID SystemBuffer = Irp->AssociatedIrp.SystemBuffer;
- if (0 == SystemBuffer || sizeof(FSP_FSCTL_VOLUME_PARAMS) > InputBufferLength)
- return STATUS_INVALID_PARAMETER;
- if (FSP_FSCTL_CREATE_BUFFER_SIZEMIN > OutputBufferLength)
- return STATUS_BUFFER_TOO_SMALL;
-
- NTSTATUS Result;
- FSP_FSCTL_VOLUME_PARAMS VolumeParams = *(FSP_FSCTL_VOLUME_PARAMS *)SystemBuffer;
- GUID Guid;
- UNICODE_STRING DeviceSddl;
- UNICODE_STRING DeviceName;
- FSP_FSCTL_FILE_CONTEXT2 *FsContext2;
- HANDLE MupHandle = 0;
- PDEVICE_OBJECT FsvrtDeviceObject = 0;
- PDEVICE_OBJECT FsvolDeviceObject;
- FSP_FSVOL_DEVICE_EXTENSION *FsvolDeviceExtension;
-
- /* check the passed in VolumeParams */
- if (FspFsctlIrpTimeoutMinimum > VolumeParams.IrpTimeout ||
- VolumeParams.IrpTimeout > FspFsctlIrpTimeoutMaximum)
- {
-#if DBG
- /* allow the debug timeout value on debug builds */
- if (FspFsctlIrpTimeoutDebug != VolumeParams.IrpTimeout)
-#endif
- VolumeParams.IrpTimeout = FspFsctlIrpTimeoutDefault;
- }
- if (FspFsctlTransactTimeoutMinimum > VolumeParams.TransactTimeout ||
- VolumeParams.TransactTimeout > FspFsctlTransactTimeoutMaximum)
- VolumeParams.TransactTimeout = FspFsctlTransactTimeoutDefault;
-
- /* create volume guid */
- Result = FspCreateGuid(&Guid);
- if (!NT_SUCCESS(Result))
- return Result;
-
- /* prepare the device name and SDDL */
- RtlInitUnicodeString(&DeviceSddl, L"" FSP_FSVRT_DEVICE_SDDL);
- RtlInitEmptyUnicodeString(&DeviceName, SystemBuffer, FSP_FSCTL_CREATE_BUFFER_SIZEMIN);
- Result = RtlUnicodeStringPrintf(&DeviceName,
- L"\\Device\\Volume{%08lx-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x}",
- Guid.Data1, Guid.Data2, Guid.Data3,
- Guid.Data4[0], Guid.Data4[1], Guid.Data4[2], Guid.Data4[3],
- Guid.Data4[4], Guid.Data4[5], Guid.Data4[6], Guid.Data4[7]);
- ASSERT(NT_SUCCESS(Result));
-
- FsContext2 = IrpSp->FileObject->FsContext2;
- ExAcquireFastMutex(&FsContext2->FastMutex);
- try
- {
- /* check to see if we already have a volume */
- if (0 != FsContext2->FsvolDeviceObject)
- {
- Result = STATUS_ACCESS_DENIED;
- goto exit;
- }
-
- /* create the volume (and virtual disk) device(s) */
- Result = FspDeviceCreate(FspFsvolDeviceExtensionKind, 0,
- DeviceObject->DeviceType,
- &FsvolDeviceObject);
- if (!NT_SUCCESS(Result))
- goto exit;
- if (FILE_DEVICE_DISK_FILE_SYSTEM == DeviceObject->DeviceType)
- {
- Result = FspDeviceCreateSecure(FspFsvrtDeviceExtensionKind, 0,
- &DeviceName, FILE_DEVICE_VIRTUAL_DISK,
- &DeviceSddl, &FspFsvrtDeviceClassGuid,
- &FsvrtDeviceObject);
- if (!NT_SUCCESS(Result))
- {
- FspDeviceRelease(FsvolDeviceObject);
- goto exit;
- }
-#pragma prefast(suppress:28175, "We are a filesystem: ok to access SectorSize")
- FsvrtDeviceObject->SectorSize = VolumeParams.SectorSize;
- }
-#pragma prefast(suppress:28175, "We are a filesystem: ok to access SectorSize")
- FsvolDeviceObject->SectorSize = VolumeParams.SectorSize;
- FsvolDeviceExtension = FspFsvolDeviceExtension(FsvolDeviceObject);
- FsvolDeviceExtension->FsctlDeviceObject = DeviceObject;
- FsvolDeviceExtension->FsvrtDeviceObject = FsvrtDeviceObject;
- FsvolDeviceExtension->VolumeParams = VolumeParams;
- if (0 != FsvrtDeviceObject)
- FspDeviceInitComplete(FsvrtDeviceObject);
- FspDeviceInitComplete(FsvolDeviceObject);
-
- /* do we need to register with MUP? */
- if (0 == FsvrtDeviceObject)
- {
- Result = FsRtlRegisterUncProviderEx(&MupHandle, &DeviceName, FsvolDeviceObject, 0);
- if (!NT_SUCCESS(Result))
- {
- FspDeviceRelease(FsvolDeviceObject);
- goto exit;
- }
- FsvolDeviceExtension->MupHandle = MupHandle;
- }
-
- /* associate the new volume device with our file object */
- FsContext2->FsvolDeviceObject = FsvolDeviceObject;
-
- Irp->IoStatus.Information = DeviceName.Length + sizeof(WCHAR);
- Result = STATUS_SUCCESS;
-
- exit:;
- }
- finally
- {
- ExReleaseFastMutex(&FsContext2->FastMutex);
- }
-
- return Result;
-}
-
-static NTSTATUS FspFsctlMountVolume(
- PDEVICE_OBJECT DeviceObject, PIRP Irp, PIO_STACK_LOCATION IrpSp)
-{
- PAGED_CODE();
-
- NTSTATUS Result;
- PVPB Vpb = IrpSp->Parameters.MountVolume.Vpb;
- PDEVICE_OBJECT FsvrtDeviceObject = IrpSp->Parameters.MountVolume.DeviceObject;
- PDEVICE_OBJECT FsvolDeviceObject = 0;
- FSP_FSVOL_DEVICE_EXTENSION *FsvolDeviceExtension = 0;
- PDEVICE_OBJECT *DeviceObjects = 0;
- ULONG DeviceObjectCount = 0;
- KIRQL Irql;
-
- /* check the passed in device object; it must be our own and not marked delete pending */
- Result = FspDeviceCopyList(&DeviceObjects, &DeviceObjectCount);
- if (NT_SUCCESS(Result))
- {
- Result = STATUS_UNRECOGNIZED_VOLUME;
- for (ULONG i = 0; DeviceObjectCount > i; i++)
- if (FspDeviceRetain(DeviceObjects[i]))
- {
- if (FspFsvolDeviceExtensionKind == FspDeviceExtension(DeviceObjects[i])->Kind)
- {
- FsvolDeviceObject = DeviceObjects[i];
- FsvolDeviceExtension = FspFsvolDeviceExtension(FsvolDeviceObject);
- if (FsvolDeviceExtension->FsvrtDeviceObject == FsvrtDeviceObject &&
- !FsvolDeviceExtension->DeletePending)
- {
- Result = STATUS_SUCCESS;
- break;
- }
- }
- FspDeviceRelease(DeviceObjects[i]);
- }
- FspDeviceDeleteList(DeviceObjects, DeviceObjectCount);
- }
- if (!NT_SUCCESS(Result))
- return Result;
-
- /* our volume device object has been FspDeviceRetain'ed */
- ASSERT(0 != FsvolDeviceObject && 0 != FsvolDeviceExtension);
- IoAcquireVpbSpinLock(&Irql);
- Vpb->ReferenceCount++;
- Vpb->DeviceObject = FsvolDeviceObject;
- Vpb->SerialNumber = FsvolDeviceExtension->VolumeParams.SerialNumber;
- IoReleaseVpbSpinLock(Irql);
-
- Irp->IoStatus.Information = 0;
- return STATUS_SUCCESS;
-}
-
-VOID FspFsctlDeleteVolume(
- PDEVICE_OBJECT DeviceObject, PIRP Irp, PIO_STACK_LOCATION IrpSp)
-{
- /* performed during IRP_MJ_CLEANUP! */
- PAGED_CODE();
-
- PDEVICE_OBJECT FsvolDeviceObject;
- FSP_FSVOL_DEVICE_EXTENSION *FsvolDeviceExtension;
-
- FsvolDeviceObject = FspFsvolDeviceObjectFromFileObject(IrpSp->FileObject);
- if (0 == FsvolDeviceObject)
- return;
- FsvolDeviceExtension = FspFsvolDeviceExtension(FsvolDeviceObject);
-
- /* mark the volume device as pending delete */
- FsvolDeviceExtension->DeletePending = TRUE;
-
- /* stop the I/O queue */
- FspIoqStop(&FsvolDeviceExtension->Ioq);
-
- /* do we have a virtual disk device or a MUP handle? */
- if (0 != FsvolDeviceExtension->FsvrtDeviceObject)
- {
- PDEVICE_OBJECT FsvrtDeviceObject = FsvolDeviceExtension->FsvrtDeviceObject;
- PVPB OldVpb;
- KIRQL Irql;
- BOOLEAN DeleteVpb = FALSE;
- BOOLEAN DeleteDly = FALSE;
- LARGE_INTEGER DelayTimeout;
-
- /* swap the virtual disk device VPB with the preallocated one */
-#pragma prefast(push)
-#pragma prefast(disable:28175, "We are a filesystem: ok to access Vpb")
- IoAcquireVpbSpinLock(&Irql);
- OldVpb = FsvrtDeviceObject->Vpb;
- if (0 != OldVpb)
- {
- FsvrtDeviceObject->Vpb = FsvolDeviceExtension->SwapVpb;
- FsvrtDeviceObject->Vpb->Size = sizeof *FsvrtDeviceObject->Vpb;
- FsvrtDeviceObject->Vpb->Type = IO_TYPE_VPB;
- FsvrtDeviceObject->Vpb->Flags = FlagOn(OldVpb->Flags, VPB_REMOVE_PENDING);
- FsvrtDeviceObject->Vpb->RealDevice = OldVpb->RealDevice;
- FsvrtDeviceObject->Vpb->RealDevice->Vpb = FsvrtDeviceObject->Vpb;
- DeleteVpb = 0 == OldVpb->ReferenceCount;
- DeleteDly = 2 <= OldVpb->ReferenceCount;
- }
- IoReleaseVpbSpinLock(Irql);
- if (DeleteVpb)
- {
- /* no more references to the old VPB; delete now! */
- FspFreeExternal(OldVpb);
- FsvolDeviceExtension->SwapVpb = 0;
- }
- else if (!DeleteDly)
- {
- /* there is only the reference from IRP_MN_MOUNT_VOLUME */
- FspFreeExternal(OldVpb);
- FsvolDeviceExtension->SwapVpb = 0;
- FspDeviceRelease(FsvolDeviceObject);
- }
- else
- /* keep VPB around for delayed delete */
- FsvolDeviceExtension->SwapVpb = OldVpb;
-#pragma prefast(pop)
-
- /* release the virtual disk and volume device objects */
- FspDeviceRelease(FsvrtDeviceObject);
- FspDeviceRelease(FsvolDeviceObject);
-
- /* are we doing delayed delete of VPB and volume device object? */
- if (DeleteDly)
- {
- DelayTimeout.QuadPart = 300/*ms*/ * -10000;
- FspInitializeWorkItemWithDelay(&FsvolDeviceExtension->DeleteVolumeWorkItem,
- FspFsctlDeleteVolumeDelayed, FsvolDeviceObject);
- FspQueueWorkItemWithDelay(&FsvolDeviceExtension->DeleteVolumeWorkItem, DelayTimeout);
- }
- }
- else if (0 != FsvolDeviceExtension->MupHandle)
- {
- HANDLE MupHandle = FsvolDeviceExtension->MupHandle;
-
- FsRtlDeregisterUncProvider(MupHandle);
- FsvolDeviceExtension->MupHandle = 0;
-
- /* release the volume device object */
- FspDeviceRelease(FsvolDeviceObject);
- }
-}
-
-static VOID FspFsctlDeleteVolumeDelayed(PVOID Context)
-{
- PAGED_CODE();
-
- PDEVICE_OBJECT FsvolDeviceObject = Context;
- FSP_FSVOL_DEVICE_EXTENSION *FsvolDeviceExtension = FspFsvolDeviceExtension(FsvolDeviceObject);
- KIRQL Irql;
- BOOLEAN DeleteVpb = FALSE;
- LARGE_INTEGER DelayTimeout;
-
- IoAcquireVpbSpinLock(&Irql);
- ASSERT(0 != FsvolDeviceExtension->SwapVpb->ReferenceCount);
- DeleteVpb = 1 == FsvolDeviceExtension->SwapVpb->ReferenceCount;
- if (DeleteVpb)
- FsvolDeviceExtension->SwapVpb->ReferenceCount = 0;
- IoReleaseVpbSpinLock(Irql);
- if (DeleteVpb)
- {
- FspFreeExternal(FsvolDeviceExtension->SwapVpb);
- FsvolDeviceExtension->SwapVpb = 0;
- FspDeviceRelease(FsvolDeviceObject);
- }
- else
- {
- DelayTimeout.QuadPart = 300/*ms*/ * -10000;
- FspQueueWorkItemWithDelay(&FsvolDeviceExtension->DeleteVolumeWorkItem, DelayTimeout);
- }
-}
-
-static NTSTATUS FspFsctlTransact(
- PDEVICE_OBJECT DeviceObject, PIRP Irp, PIO_STACK_LOCATION IrpSp)
-{
- PAGED_CODE();
-
- /* check parameters */
- ULONG InputBufferLength = IrpSp->Parameters.FileSystemControl.InputBufferLength;
- ULONG OutputBufferLength = IrpSp->Parameters.FileSystemControl.OutputBufferLength;
- PVOID SystemBuffer = Irp->AssociatedIrp.SystemBuffer;
- if (0 != InputBufferLength &&
- FSP_FSCTL_DEFAULT_ALIGN_UP(sizeof(FSP_FSCTL_TRANSACT_RSP)) > InputBufferLength)
- return STATUS_INVALID_PARAMETER;
- if (0 != OutputBufferLength &&
- FSP_FSCTL_TRANSACT_REQ_BUFFER_SIZEMIN > OutputBufferLength)
- return STATUS_BUFFER_TOO_SMALL;
-
- NTSTATUS Result;
- PDEVICE_OBJECT FsvolDeviceObject;
- FSP_FSVOL_DEVICE_EXTENSION *FsvolDeviceExtension;
- PVOID MdlBuffer;
- PUINT8 BufferEnd;
- FSP_FSCTL_TRANSACT_RSP *Response, *NextResponse;
- FSP_FSCTL_TRANSACT_REQ *Request, *PendingIrpRequest;
- PIRP ProcessIrp, PendingIrp;
- LARGE_INTEGER Timeout;
-
- FsvolDeviceObject = FspFsvolDeviceObjectFromFileObject(IrpSp->FileObject);
- if (0 == FsvolDeviceObject)
- return STATUS_ACCESS_DENIED;
- FsvolDeviceExtension = FspFsvolDeviceExtension(FsvolDeviceObject);
-
- /* process any user-mode file system responses */
- Response = SystemBuffer;
- BufferEnd = (PUINT8)SystemBuffer + InputBufferLength;
- for (;;)
- {
- NextResponse = FspFsctlTransactConsumeResponse(Response, BufferEnd);
- if (0 == NextResponse)
- break;
-
- ProcessIrp = FspIoqEndProcessingIrp(&FsvolDeviceExtension->Ioq, (UINT_PTR)Response->Hint);
- if (0 == ProcessIrp)
- /* either IRP was canceled or a bogus Hint was provided */
- continue;
-
- FspIopDispatchComplete(ProcessIrp, Response);
-
- Response = NextResponse;
- }
-
- /* were we sent an output buffer? */
- if (0 == Irp->MdlAddress)
- {
- Irp->IoStatus.Information = 0;
- return STATUS_SUCCESS;
- }
- MdlBuffer = MmGetMdlVirtualAddress(Irp->MdlAddress);
- ASSERT(0 != MdlBuffer);
-
- /* wait for an IRP to arrive */
- KeQuerySystemTime(&Timeout);
- Timeout.QuadPart += FsvolDeviceExtension->VolumeParams.TransactTimeout * 10000;
- /* convert millis to nanos and add to absolute time */
- while (0 == (PendingIrp = FspIoqNextPendingIrp(&FsvolDeviceExtension->Ioq, &Timeout)))
- {
- if (FspIoqStopped(&FsvolDeviceExtension->Ioq))
- return STATUS_CANCELLED;
- }
- if (FspIoqTimeout == PendingIrp)
- {
- Irp->IoStatus.Information = 0;
- return STATUS_SUCCESS;
- }
-
- /* send any pending IRP's to the user-mode file system */
- Request = MdlBuffer;
- BufferEnd = (PUINT8)MdlBuffer + OutputBufferLength;
- ASSERT(FspFsctlTransactCanProduceRequest(Request, BufferEnd));
- for (;;)
- {
- PendingIrpRequest = FspIrpRequest(PendingIrp);
-
- Result = FspIopDispatchPrepare(PendingIrp, PendingIrpRequest);
- if (!NT_SUCCESS(Result))
- FspIopCompleteIrp(PendingIrp, Result);
- else
- {
- RtlCopyMemory(Request, PendingIrpRequest, PendingIrpRequest->Size);
- Request = FspFsctlTransactProduceRequest(Request, PendingIrpRequest->Size);
-
- if (!FspIoqStartProcessingIrp(&FsvolDeviceExtension->Ioq, PendingIrp))
- {
- /*
- * This can only happen if the Ioq was stopped. Abandon everything
- * and return STATUS_CANCELLED. Any IRP's in the Pending and Process
- * queues of the Ioq will be cancelled during FspIoqStop(). We must
- * also cancel the PendingIrp we have in our hands.
- */
- ASSERT(FspIoqStopped(&FsvolDeviceExtension->Ioq));
- FspIopCompleteIrp(PendingIrp, STATUS_CANCELLED);
- return STATUS_CANCELLED;
- }
-
- /* check that we have enough space before pulling the next pending IRP off the queue */
- if (!FspFsctlTransactCanProduceRequest(Request, BufferEnd))
- break;
- }
-
- PendingIrp = FspIoqNextPendingIrp(&FsvolDeviceExtension->Ioq, 0);
- if (0 == PendingIrp)
- break;
-
- }
-
- Irp->IoStatus.Information = (PUINT8)Request - (PUINT8)MdlBuffer;
- Result = STATUS_SUCCESS;
-
- return Result;
-}
-
static NTSTATUS FspFsvolFileSystemControl(
PDEVICE_OBJECT DeviceObject, PIRP Irp, PIO_STACK_LOCATION IrpSp)
{
@@ -507,7 +59,7 @@ static NTSTATUS FspFsvolFileSystemControl(
switch (IrpSp->Parameters.FileSystemControl.FsControlCode)
{
case FSP_FSCTL_WORK:
- Result = FspFsvolWork(DeviceObject, Irp, IrpSp);
+ Result = FspVolumeWork(DeviceObject, Irp, IrpSp);
break;
}
break;
@@ -516,45 +68,6 @@ static NTSTATUS FspFsvolFileSystemControl(
return Result;
}
-static NTSTATUS FspFsvolWork(
- PDEVICE_OBJECT DeviceObject, PIRP Irp, PIO_STACK_LOCATION IrpSp)
-{
- PAGED_CODE();
-
- if (KernelMode != Irp->RequestorMode)
- return STATUS_ACCESS_DENIED;
-
- NTSTATUS Result;
- FSP_FSVOL_DEVICE_EXTENSION *FsvolDeviceExtension = FspFsvolDeviceExtension(DeviceObject);
- FSP_FSCTL_TRANSACT_REQ *Request = IrpSp->Parameters.FileSystemControl.Type3InputBuffer;
-
- ASSERT(0 == Request->Hint);
-
- /* associate the passed Request with our Irp; acquire ownership of the Request */
- Request->Hint = (UINT_PTR)Irp;
- FspIrpRequest(Irp) = Request;
-
- /*
- * Post the IRP to our Ioq; we do this here instead of at IRP_LEAVE_MJ time,
- * so that we can disassociate the Request on failure and release ownership
- * back to the caller.
- */
- if (!FspIoqPostIrp(&FsvolDeviceExtension->Ioq, Irp))
- {
- /* this can only happen if the Ioq was stopped */
- ASSERT(FspIoqStopped(&FsvolDeviceExtension->Ioq));
-
- Request->Hint = 0;
- FspIrpRequest(Irp) = 0;
-
- Result = STATUS_CANCELLED;
- }
- else
- Result = STATUS_PENDING;
-
- return Result;
-}
-
VOID FspFsvolFileSystemControlComplete(
PIRP Irp, const FSP_FSCTL_TRANSACT_RSP *Response)
{
diff --git a/src/sys/volume.c b/src/sys/volume.c
new file mode 100644
index 00000000..3548dd5a
--- /dev/null
+++ b/src/sys/volume.c
@@ -0,0 +1,665 @@
+/**
+ * @file sys/volume.c
+ *
+ * @copyright 2015 Bill Zissimopoulos
+ */
+
+#include
+
+NTSTATUS FspVolumeCreate(
+ PDEVICE_OBJECT FsctlDeviceObject, PIRP Irp, PIO_STACK_LOCATION IrpSp);
+VOID FspVolumeDelete(
+ PDEVICE_OBJECT FsctlDeviceObject, PIRP Irp, PIO_STACK_LOCATION IrpSp);
+NTSTATUS FspVolumeGetName(
+ PDEVICE_OBJECT FsctlDeviceObject, PIRP Irp, PIO_STACK_LOCATION IrpSp);
+NTSTATUS FspVolumeMount(
+ PDEVICE_OBJECT FsctlDeviceObject, PIRP Irp, PIO_STACK_LOCATION IrpSp);
+NTSTATUS FspVolumeTransact(
+ PDEVICE_OBJECT FsctlDeviceObject, PIRP Irp, PIO_STACK_LOCATION IrpSp);
+NTSTATUS FspVolumeRedirQueryPathEx(
+ PDEVICE_OBJECT FsvolDeviceObject, PIRP Irp, PIO_STACK_LOCATION IrpSp);
+NTSTATUS FspVolumeWork(
+ PDEVICE_OBJECT FsvolDeviceObject, PIRP Irp, PIO_STACK_LOCATION IrpSp);
+
+#ifdef ALLOC_PRAGMA
+#pragma alloc_text(PAGE, FspVolumeCreate)
+#pragma alloc_text(PAGE, FspVolumeDelete)
+#pragma alloc_text(PAGE, FspVolumeGetName)
+#pragma alloc_text(PAGE, FspVolumeMount)
+#pragma alloc_text(PAGE, FspVolumeTransact)
+#pragma alloc_text(PAGE, FspVolumeRedirQueryPathEx)
+#pragma alloc_text(PAGE, FspVolumeWork)
+#endif
+
+#define PREFIXW L"" FSP_FSCTL_VOLUME_PARAMS_PREFIX
+#define PREFIXW_SIZE (sizeof PREFIXW - sizeof(WCHAR))
+
+NTSTATUS FspVolumeCreate(
+ PDEVICE_OBJECT FsctlDeviceObject, PIRP Irp, PIO_STACK_LOCATION IrpSp)
+{
+ PAGED_CODE();
+
+ NTSTATUS Result;
+ PFILE_OBJECT FileObject = IrpSp->FileObject;
+ FSP_FSCTL_VOLUME_PARAMS VolumeParams = { 0 };
+ GUID Guid;
+ UNICODE_STRING DeviceSddl;
+ UNICODE_STRING VolumeName;
+ WCHAR VolumeNameBuf[FSP_DEVICE_VOLUME_NAME_LENMAX / sizeof(WCHAR)];
+ PDEVICE_OBJECT FsvolDeviceObject;
+ PDEVICE_OBJECT FsvrtDeviceObject;
+ HANDLE MupHandle = 0;
+ FSP_FSVOL_DEVICE_EXTENSION *FsvolDeviceExtension;
+
+ ASSERT(IRP_MJ_CREATE == IrpSp->MajorFunction);
+ ASSERT(0 == FileObject->RelatedFileObject);
+ ASSERT(PREFIXW_SIZE <= FileObject->FileName.Length &&
+ RtlEqualMemory(PREFIXW, FileObject->FileName.Buffer, PREFIXW_SIZE));
+
+ /* check parameters */
+ if (PREFIXW_SIZE + sizeof(FSP_FSCTL_VOLUME_PARAMS) * sizeof(WCHAR) > FileObject->FileName.Length)
+ return STATUS_INVALID_PARAMETER;
+
+ /* copy the VolumeParams */
+ for (USHORT Index = 0, Length = FileObject->FileName.Length / 2; Length > Index; Index++)
+ {
+ WCHAR Value = FileObject->FileName.Buffer[Index];
+ if (0xF000 != (Value & 0xFF00))
+ return STATUS_INVALID_PARAMETER;
+ ((PUINT8)&VolumeParams)[Index] = Value & 0xFF;
+ }
+
+ /* check the VolumeParams */
+ if (FspFsctlIrpTimeoutMinimum > VolumeParams.IrpTimeout ||
+ VolumeParams.IrpTimeout > FspFsctlIrpTimeoutMaximum)
+ {
+#if DBG
+ /* allow the debug timeout value on debug builds */
+ if (FspFsctlIrpTimeoutDebug != VolumeParams.IrpTimeout)
+#endif
+ VolumeParams.IrpTimeout = FspFsctlIrpTimeoutDefault;
+ }
+ if (FspFsctlTransactTimeoutMinimum > VolumeParams.TransactTimeout ||
+ VolumeParams.TransactTimeout > FspFsctlTransactTimeoutMaximum)
+ VolumeParams.TransactTimeout = FspFsctlTransactTimeoutDefault;
+
+ /* create volume guid */
+ Result = FspCreateGuid(&Guid);
+ if (!NT_SUCCESS(Result))
+ return Result;
+
+ /* prepare the device name and SDDL */
+ RtlInitUnicodeString(&DeviceSddl, L"" FSP_FSVRT_DEVICE_SDDL);
+ RtlInitEmptyUnicodeString(&VolumeName, VolumeNameBuf, sizeof VolumeNameBuf);
+ Result = RtlUnicodeStringPrintf(&VolumeName,
+ L"\\Device\\Volume{%08lx-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x}",
+ Guid.Data1, Guid.Data2, Guid.Data3,
+ Guid.Data4[0], Guid.Data4[1], Guid.Data4[2], Guid.Data4[3],
+ Guid.Data4[4], Guid.Data4[5], Guid.Data4[6], Guid.Data4[7]);
+ ASSERT(NT_SUCCESS(Result));
+
+ /* create the volume (and virtual disk) device(s) */
+ Result = FspDeviceCreate(FspFsvolDeviceExtensionKind, 0,
+ FsctlDeviceObject->DeviceType,
+ &FsvolDeviceObject);
+ if (!NT_SUCCESS(Result))
+ return Result;
+ if (FILE_DEVICE_DISK_FILE_SYSTEM == FsctlDeviceObject->DeviceType)
+ {
+ Result = FspDeviceCreateSecure(FspFsvrtDeviceExtensionKind, 0,
+ &VolumeName, FILE_DEVICE_VIRTUAL_DISK,
+ &DeviceSddl, &FspFsvrtDeviceClassGuid,
+ &FsvrtDeviceObject);
+ if (!NT_SUCCESS(Result))
+ {
+ FspDeviceRelease(FsvolDeviceObject);
+ return Result;
+ }
+#pragma prefast(suppress:28175, "We are a filesystem: ok to access SectorSize")
+ FsvrtDeviceObject->SectorSize = VolumeParams.SectorSize;
+ }
+ else
+ FsvrtDeviceObject = 0;
+#pragma prefast(suppress:28175, "We are a filesystem: ok to access SectorSize")
+ FsvolDeviceObject->SectorSize = VolumeParams.SectorSize;
+ FsvolDeviceExtension = FspFsvolDeviceExtension(FsvolDeviceObject);
+ FsvolDeviceExtension->FsctlDeviceObject = FsctlDeviceObject;
+ FsvolDeviceExtension->FsvrtDeviceObject = FsvrtDeviceObject;
+ FsvolDeviceExtension->VolumeParams = VolumeParams;
+ RtlCopyUnicodeString(&FsvolDeviceExtension->VolumeName, &VolumeName);
+ if (0 != FsvrtDeviceObject)
+ FspDeviceInitComplete(FsvrtDeviceObject);
+ FspDeviceInitComplete(FsvolDeviceObject);
+
+ /* do we need to register with MUP? */
+ if (0 == FsvrtDeviceObject)
+ {
+ Result = FsRtlRegisterUncProviderEx(&MupHandle, &VolumeName, FsvolDeviceObject, 0);
+ if (!NT_SUCCESS(Result))
+ {
+ FspDeviceRelease(FsvolDeviceObject);
+ return Result;
+ }
+ FsvolDeviceExtension->MupHandle = MupHandle;
+ }
+
+ /* associate the new volume device with our file object */
+ FileObject->FsContext2 = FsvolDeviceObject;
+
+ Irp->IoStatus.Information = FILE_OPENED;
+ return STATUS_SUCCESS;
+}
+
+VOID FspVolumeDelete(
+ PDEVICE_OBJECT FsctlDeviceObject, PIRP Irp, PIO_STACK_LOCATION IrpSp)
+{
+ PAGED_CODE();
+}
+
+NTSTATUS FspVolumeGetName(
+ PDEVICE_OBJECT FsctlDeviceObject, PIRP Irp, PIO_STACK_LOCATION IrpSp)
+{
+ PAGED_CODE();
+
+ return STATUS_INVALID_DEVICE_REQUEST;
+}
+
+NTSTATUS FspVolumeMount(
+ PDEVICE_OBJECT FsctlDeviceObject, PIRP Irp, PIO_STACK_LOCATION IrpSp)
+{
+ PAGED_CODE();
+
+ return STATUS_INVALID_DEVICE_REQUEST;
+}
+
+NTSTATUS FspVolumeTransact(
+ PDEVICE_OBJECT FsctlDeviceObject, PIRP Irp, PIO_STACK_LOCATION IrpSp)
+{
+ PAGED_CODE();
+
+ return STATUS_INVALID_DEVICE_REQUEST;
+}
+
+NTSTATUS FspVolumeRedirQueryPathEx(
+ PDEVICE_OBJECT FsvolDeviceObject, PIRP Irp, PIO_STACK_LOCATION IrpSp)
+{
+ PAGED_CODE();
+
+ return STATUS_INVALID_DEVICE_REQUEST;
+}
+
+NTSTATUS FspVolumeWork(
+ PDEVICE_OBJECT FsvolDeviceObject, PIRP Irp, PIO_STACK_LOCATION IrpSp)
+{
+ PAGED_CODE();
+
+ return STATUS_INVALID_DEVICE_REQUEST;
+}
+
+#if 0
+static inline PDEVICE_OBJECT FspFsvolDeviceObjectFromFileObject(PFILE_OBJECT FileObject)
+{
+ PDEVICE_OBJECT FsvolDeviceObject;
+ FSP_FSCTL_FILE_CONTEXT2 *FsContext2 = FileObject->FsContext2;
+
+ ExAcquireFastMutex(&FsContext2->FastMutex);
+ FsvolDeviceObject = FsContext2->FsvolDeviceObject;
+ ExReleaseFastMutex(&FsContext2->FastMutex);
+
+ /* no FspDeviceRetain on the volume device, because it exists until the FileObject IRP_MJ_CLEANUP */
+ return FsvolDeviceObject;
+}
+
+NTSTATUS FspFsctlCreateVolume(
+ PDEVICE_OBJECT DeviceObject, PIRP Irp, PIO_STACK_LOCATION IrpSp)
+{
+ PAGED_CODE();
+
+ /* check parameters */
+ ULONG InputBufferLength = IrpSp->Parameters.FileSystemControl.InputBufferLength;
+ ULONG OutputBufferLength = IrpSp->Parameters.FileSystemControl.OutputBufferLength;
+ PVOID SystemBuffer = Irp->AssociatedIrp.SystemBuffer;
+ if (0 == SystemBuffer || sizeof(FSP_FSCTL_VOLUME_PARAMS) > InputBufferLength)
+ return STATUS_INVALID_PARAMETER;
+ if (FSP_FSCTL_CREATE_BUFFER_SIZEMIN > OutputBufferLength)
+ return STATUS_BUFFER_TOO_SMALL;
+
+ NTSTATUS Result;
+ FSP_FSCTL_VOLUME_PARAMS VolumeParams = *(FSP_FSCTL_VOLUME_PARAMS *)SystemBuffer;
+ GUID Guid;
+ UNICODE_STRING DeviceSddl;
+ UNICODE_STRING DeviceName;
+ FSP_FSCTL_FILE_CONTEXT2 *FsContext2;
+ HANDLE MupHandle = 0;
+ PDEVICE_OBJECT FsvrtDeviceObject = 0;
+ PDEVICE_OBJECT FsvolDeviceObject;
+ FSP_FSVOL_DEVICE_EXTENSION *FsvolDeviceExtension;
+
+ /* check the passed in VolumeParams */
+ if (FspFsctlIrpTimeoutMinimum > VolumeParams.IrpTimeout ||
+ VolumeParams.IrpTimeout > FspFsctlIrpTimeoutMaximum)
+ {
+#if DBG
+ /* allow the debug timeout value on debug builds */
+ if (FspFsctlIrpTimeoutDebug != VolumeParams.IrpTimeout)
+#endif
+ VolumeParams.IrpTimeout = FspFsctlIrpTimeoutDefault;
+ }
+ if (FspFsctlTransactTimeoutMinimum > VolumeParams.TransactTimeout ||
+ VolumeParams.TransactTimeout > FspFsctlTransactTimeoutMaximum)
+ VolumeParams.TransactTimeout = FspFsctlTransactTimeoutDefault;
+
+ /* create volume guid */
+ Result = FspCreateGuid(&Guid);
+ if (!NT_SUCCESS(Result))
+ return Result;
+
+ /* prepare the device name and SDDL */
+ RtlInitUnicodeString(&DeviceSddl, L"" FSP_FSVRT_DEVICE_SDDL);
+ RtlInitEmptyUnicodeString(&DeviceName, SystemBuffer, FSP_FSCTL_CREATE_BUFFER_SIZEMIN);
+ Result = RtlUnicodeStringPrintf(&DeviceName,
+ L"\\Device\\Volume{%08lx-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x}",
+ Guid.Data1, Guid.Data2, Guid.Data3,
+ Guid.Data4[0], Guid.Data4[1], Guid.Data4[2], Guid.Data4[3],
+ Guid.Data4[4], Guid.Data4[5], Guid.Data4[6], Guid.Data4[7]);
+ ASSERT(NT_SUCCESS(Result));
+
+ FsContext2 = IrpSp->FileObject->FsContext2;
+ ExAcquireFastMutex(&FsContext2->FastMutex);
+ try
+ {
+ /* check to see if we already have a volume */
+ if (0 != FsContext2->FsvolDeviceObject)
+ {
+ Result = STATUS_ACCESS_DENIED;
+ goto exit;
+ }
+
+ /* create the volume (and virtual disk) device(s) */
+ Result = FspDeviceCreate(FspFsvolDeviceExtensionKind, 0,
+ DeviceObject->DeviceType,
+ &FsvolDeviceObject);
+ if (!NT_SUCCESS(Result))
+ goto exit;
+ if (FILE_DEVICE_DISK_FILE_SYSTEM == DeviceObject->DeviceType)
+ {
+ Result = FspDeviceCreateSecure(FspFsvrtDeviceExtensionKind, 0,
+ &DeviceName, FILE_DEVICE_VIRTUAL_DISK,
+ &DeviceSddl, &FspFsvrtDeviceClassGuid,
+ &FsvrtDeviceObject);
+ if (!NT_SUCCESS(Result))
+ {
+ FspDeviceRelease(FsvolDeviceObject);
+ goto exit;
+ }
+#pragma prefast(suppress:28175, "We are a filesystem: ok to access SectorSize")
+ FsvrtDeviceObject->SectorSize = VolumeParams.SectorSize;
+ }
+#pragma prefast(suppress:28175, "We are a filesystem: ok to access SectorSize")
+ FsvolDeviceObject->SectorSize = VolumeParams.SectorSize;
+ FsvolDeviceExtension = FspFsvolDeviceExtension(FsvolDeviceObject);
+ FsvolDeviceExtension->FsctlDeviceObject = DeviceObject;
+ FsvolDeviceExtension->FsvrtDeviceObject = FsvrtDeviceObject;
+ FsvolDeviceExtension->VolumeParams = VolumeParams;
+ if (0 != FsvrtDeviceObject)
+ FspDeviceInitComplete(FsvrtDeviceObject);
+ FspDeviceInitComplete(FsvolDeviceObject);
+
+ /* do we need to register with MUP? */
+ if (0 == FsvrtDeviceObject)
+ {
+ Result = FsRtlRegisterUncProviderEx(&MupHandle, &DeviceName, FsvolDeviceObject, 0);
+ if (!NT_SUCCESS(Result))
+ {
+ FspDeviceRelease(FsvolDeviceObject);
+ goto exit;
+ }
+ FsvolDeviceExtension->MupHandle = MupHandle;
+ }
+
+ /* associate the new volume device with our file object */
+ FsContext2->FsvolDeviceObject = FsvolDeviceObject;
+
+ Irp->IoStatus.Information = DeviceName.Length + sizeof(WCHAR);
+ Result = STATUS_SUCCESS;
+
+ exit:;
+ }
+ finally
+ {
+ ExReleaseFastMutex(&FsContext2->FastMutex);
+ }
+
+ return Result;
+}
+
+static NTSTATUS FspFsctlMountVolume(
+ PDEVICE_OBJECT DeviceObject, PIRP Irp, PIO_STACK_LOCATION IrpSp)
+{
+ PAGED_CODE();
+
+ NTSTATUS Result;
+ PVPB Vpb = IrpSp->Parameters.MountVolume.Vpb;
+ PDEVICE_OBJECT FsvrtDeviceObject = IrpSp->Parameters.MountVolume.DeviceObject;
+ PDEVICE_OBJECT FsvolDeviceObject = 0;
+ FSP_FSVOL_DEVICE_EXTENSION *FsvolDeviceExtension = 0;
+ PDEVICE_OBJECT *DeviceObjects = 0;
+ ULONG DeviceObjectCount = 0;
+ KIRQL Irql;
+
+ /* check the passed in device object; it must be our own and not marked delete pending */
+ Result = FspDeviceCopyList(&DeviceObjects, &DeviceObjectCount);
+ if (NT_SUCCESS(Result))
+ {
+ Result = STATUS_UNRECOGNIZED_VOLUME;
+ for (ULONG i = 0; DeviceObjectCount > i; i++)
+ if (FspDeviceRetain(DeviceObjects[i]))
+ {
+ if (FspFsvolDeviceExtensionKind == FspDeviceExtension(DeviceObjects[i])->Kind)
+ {
+ FsvolDeviceObject = DeviceObjects[i];
+ FsvolDeviceExtension = FspFsvolDeviceExtension(FsvolDeviceObject);
+ if (FsvolDeviceExtension->FsvrtDeviceObject == FsvrtDeviceObject &&
+ !FsvolDeviceExtension->DeletePending)
+ {
+ Result = STATUS_SUCCESS;
+ break;
+ }
+ }
+ FspDeviceRelease(DeviceObjects[i]);
+ }
+ FspDeviceDeleteList(DeviceObjects, DeviceObjectCount);
+ }
+ if (!NT_SUCCESS(Result))
+ return Result;
+
+ /* our volume device object has been FspDeviceRetain'ed */
+ ASSERT(0 != FsvolDeviceObject && 0 != FsvolDeviceExtension);
+ IoAcquireVpbSpinLock(&Irql);
+ Vpb->ReferenceCount++;
+ Vpb->DeviceObject = FsvolDeviceObject;
+ Vpb->SerialNumber = FsvolDeviceExtension->VolumeParams.SerialNumber;
+ IoReleaseVpbSpinLock(Irql);
+
+ Irp->IoStatus.Information = 0;
+ return STATUS_SUCCESS;
+}
+
+VOID FspFsctlDeleteVolume(
+ PDEVICE_OBJECT DeviceObject, PIRP Irp, PIO_STACK_LOCATION IrpSp)
+{
+ /* performed during IRP_MJ_CLEANUP! */
+ PAGED_CODE();
+
+ PDEVICE_OBJECT FsvolDeviceObject;
+ FSP_FSVOL_DEVICE_EXTENSION *FsvolDeviceExtension;
+
+ FsvolDeviceObject = FspFsvolDeviceObjectFromFileObject(IrpSp->FileObject);
+ if (0 == FsvolDeviceObject)
+ return;
+ FsvolDeviceExtension = FspFsvolDeviceExtension(FsvolDeviceObject);
+
+ /* mark the volume device as pending delete */
+ FsvolDeviceExtension->DeletePending = TRUE;
+
+ /* stop the I/O queue */
+ FspIoqStop(&FsvolDeviceExtension->Ioq);
+
+ /* do we have a virtual disk device or a MUP handle? */
+ if (0 != FsvolDeviceExtension->FsvrtDeviceObject)
+ {
+ PDEVICE_OBJECT FsvrtDeviceObject = FsvolDeviceExtension->FsvrtDeviceObject;
+ PVPB OldVpb;
+ KIRQL Irql;
+ BOOLEAN DeleteVpb = FALSE;
+ BOOLEAN DeleteDly = FALSE;
+ LARGE_INTEGER DelayTimeout;
+
+ /* swap the virtual disk device VPB with the preallocated one */
+#pragma prefast(push)
+#pragma prefast(disable:28175, "We are a filesystem: ok to access Vpb")
+ IoAcquireVpbSpinLock(&Irql);
+ OldVpb = FsvrtDeviceObject->Vpb;
+ if (0 != OldVpb)
+ {
+ FsvrtDeviceObject->Vpb = FsvolDeviceExtension->SwapVpb;
+ FsvrtDeviceObject->Vpb->Size = sizeof *FsvrtDeviceObject->Vpb;
+ FsvrtDeviceObject->Vpb->Type = IO_TYPE_VPB;
+ FsvrtDeviceObject->Vpb->Flags = FlagOn(OldVpb->Flags, VPB_REMOVE_PENDING);
+ FsvrtDeviceObject->Vpb->RealDevice = OldVpb->RealDevice;
+ FsvrtDeviceObject->Vpb->RealDevice->Vpb = FsvrtDeviceObject->Vpb;
+ DeleteVpb = 0 == OldVpb->ReferenceCount;
+ DeleteDly = 2 <= OldVpb->ReferenceCount;
+ }
+ IoReleaseVpbSpinLock(Irql);
+ if (DeleteVpb)
+ {
+ /* no more references to the old VPB; delete now! */
+ FspFreeExternal(OldVpb);
+ FsvolDeviceExtension->SwapVpb = 0;
+ }
+ else if (!DeleteDly)
+ {
+ /* there is only the reference from IRP_MN_MOUNT_VOLUME */
+ FspFreeExternal(OldVpb);
+ FsvolDeviceExtension->SwapVpb = 0;
+ FspDeviceRelease(FsvolDeviceObject);
+ }
+ else
+ /* keep VPB around for delayed delete */
+ FsvolDeviceExtension->SwapVpb = OldVpb;
+#pragma prefast(pop)
+
+ /* release the virtual disk and volume device objects */
+ FspDeviceRelease(FsvrtDeviceObject);
+ FspDeviceRelease(FsvolDeviceObject);
+
+ /* are we doing delayed delete of VPB and volume device object? */
+ if (DeleteDly)
+ {
+ DelayTimeout.QuadPart = 300/*ms*/ * -10000;
+ FspInitializeWorkItemWithDelay(&FsvolDeviceExtension->DeleteVolumeWorkItem,
+ FspFsctlDeleteVolumeDelayed, FsvolDeviceObject);
+ FspQueueWorkItemWithDelay(&FsvolDeviceExtension->DeleteVolumeWorkItem, DelayTimeout);
+ }
+ }
+ else if (0 != FsvolDeviceExtension->MupHandle)
+ {
+ HANDLE MupHandle = FsvolDeviceExtension->MupHandle;
+
+ FsRtlDeregisterUncProvider(MupHandle);
+ FsvolDeviceExtension->MupHandle = 0;
+
+ /* release the volume device object */
+ FspDeviceRelease(FsvolDeviceObject);
+ }
+}
+
+static VOID FspFsctlDeleteVolumeDelayed(PVOID Context)
+{
+ PAGED_CODE();
+
+ PDEVICE_OBJECT FsvolDeviceObject = Context;
+ FSP_FSVOL_DEVICE_EXTENSION *FsvolDeviceExtension = FspFsvolDeviceExtension(FsvolDeviceObject);
+ KIRQL Irql;
+ BOOLEAN DeleteVpb = FALSE;
+ LARGE_INTEGER DelayTimeout;
+
+ IoAcquireVpbSpinLock(&Irql);
+ ASSERT(0 != FsvolDeviceExtension->SwapVpb->ReferenceCount);
+ DeleteVpb = 1 == FsvolDeviceExtension->SwapVpb->ReferenceCount;
+ if (DeleteVpb)
+ FsvolDeviceExtension->SwapVpb->ReferenceCount = 0;
+ IoReleaseVpbSpinLock(Irql);
+ if (DeleteVpb)
+ {
+ FspFreeExternal(FsvolDeviceExtension->SwapVpb);
+ FsvolDeviceExtension->SwapVpb = 0;
+ FspDeviceRelease(FsvolDeviceObject);
+ }
+ else
+ {
+ DelayTimeout.QuadPart = 300/*ms*/ * -10000;
+ FspQueueWorkItemWithDelay(&FsvolDeviceExtension->DeleteVolumeWorkItem, DelayTimeout);
+ }
+}
+
+static NTSTATUS FspFsctlTransact(
+ PDEVICE_OBJECT DeviceObject, PIRP Irp, PIO_STACK_LOCATION IrpSp)
+{
+ PAGED_CODE();
+
+ /* check parameters */
+ ULONG InputBufferLength = IrpSp->Parameters.FileSystemControl.InputBufferLength;
+ ULONG OutputBufferLength = IrpSp->Parameters.FileSystemControl.OutputBufferLength;
+ PVOID SystemBuffer = Irp->AssociatedIrp.SystemBuffer;
+ if (0 != InputBufferLength &&
+ FSP_FSCTL_DEFAULT_ALIGN_UP(sizeof(FSP_FSCTL_TRANSACT_RSP)) > InputBufferLength)
+ return STATUS_INVALID_PARAMETER;
+ if (0 != OutputBufferLength &&
+ FSP_FSCTL_TRANSACT_REQ_BUFFER_SIZEMIN > OutputBufferLength)
+ return STATUS_BUFFER_TOO_SMALL;
+
+ NTSTATUS Result;
+ PDEVICE_OBJECT FsvolDeviceObject;
+ FSP_FSVOL_DEVICE_EXTENSION *FsvolDeviceExtension;
+ PVOID MdlBuffer;
+ PUINT8 BufferEnd;
+ FSP_FSCTL_TRANSACT_RSP *Response, *NextResponse;
+ FSP_FSCTL_TRANSACT_REQ *Request, *PendingIrpRequest;
+ PIRP ProcessIrp, PendingIrp;
+ LARGE_INTEGER Timeout;
+
+ FsvolDeviceObject = FspFsvolDeviceObjectFromFileObject(IrpSp->FileObject);
+ if (0 == FsvolDeviceObject)
+ return STATUS_ACCESS_DENIED;
+ FsvolDeviceExtension = FspFsvolDeviceExtension(FsvolDeviceObject);
+
+ /* process any user-mode file system responses */
+ Response = SystemBuffer;
+ BufferEnd = (PUINT8)SystemBuffer + InputBufferLength;
+ for (;;)
+ {
+ NextResponse = FspFsctlTransactConsumeResponse(Response, BufferEnd);
+ if (0 == NextResponse)
+ break;
+
+ ProcessIrp = FspIoqEndProcessingIrp(&FsvolDeviceExtension->Ioq, (UINT_PTR)Response->Hint);
+ if (0 == ProcessIrp)
+ /* either IRP was canceled or a bogus Hint was provided */
+ continue;
+
+ FspIopDispatchComplete(ProcessIrp, Response);
+
+ Response = NextResponse;
+ }
+
+ /* were we sent an output buffer? */
+ if (0 == Irp->MdlAddress)
+ {
+ Irp->IoStatus.Information = 0;
+ return STATUS_SUCCESS;
+ }
+ MdlBuffer = MmGetMdlVirtualAddress(Irp->MdlAddress);
+ ASSERT(0 != MdlBuffer);
+
+ /* wait for an IRP to arrive */
+ KeQuerySystemTime(&Timeout);
+ Timeout.QuadPart += FsvolDeviceExtension->VolumeParams.TransactTimeout * 10000;
+ /* convert millis to nanos and add to absolute time */
+ while (0 == (PendingIrp = FspIoqNextPendingIrp(&FsvolDeviceExtension->Ioq, &Timeout)))
+ {
+ if (FspIoqStopped(&FsvolDeviceExtension->Ioq))
+ return STATUS_CANCELLED;
+ }
+ if (FspIoqTimeout == PendingIrp)
+ {
+ Irp->IoStatus.Information = 0;
+ return STATUS_SUCCESS;
+ }
+
+ /* send any pending IRP's to the user-mode file system */
+ Request = MdlBuffer;
+ BufferEnd = (PUINT8)MdlBuffer + OutputBufferLength;
+ ASSERT(FspFsctlTransactCanProduceRequest(Request, BufferEnd));
+ for (;;)
+ {
+ PendingIrpRequest = FspIrpRequest(PendingIrp);
+
+ Result = FspIopDispatchPrepare(PendingIrp, PendingIrpRequest);
+ if (!NT_SUCCESS(Result))
+ FspIopCompleteIrp(PendingIrp, Result);
+ else
+ {
+ RtlCopyMemory(Request, PendingIrpRequest, PendingIrpRequest->Size);
+ Request = FspFsctlTransactProduceRequest(Request, PendingIrpRequest->Size);
+
+ if (!FspIoqStartProcessingIrp(&FsvolDeviceExtension->Ioq, PendingIrp))
+ {
+ /*
+ * This can only happen if the Ioq was stopped. Abandon everything
+ * and return STATUS_CANCELLED. Any IRP's in the Pending and Process
+ * queues of the Ioq will be cancelled during FspIoqStop(). We must
+ * also cancel the PendingIrp we have in our hands.
+ */
+ ASSERT(FspIoqStopped(&FsvolDeviceExtension->Ioq));
+ FspIopCompleteIrp(PendingIrp, STATUS_CANCELLED);
+ return STATUS_CANCELLED;
+ }
+
+ /* check that we have enough space before pulling the next pending IRP off the queue */
+ if (!FspFsctlTransactCanProduceRequest(Request, BufferEnd))
+ break;
+ }
+
+ PendingIrp = FspIoqNextPendingIrp(&FsvolDeviceExtension->Ioq, 0);
+ if (0 == PendingIrp)
+ break;
+
+ }
+
+ Irp->IoStatus.Information = (PUINT8)Request - (PUINT8)MdlBuffer;
+ Result = STATUS_SUCCESS;
+
+ return Result;
+}
+
+static NTSTATUS FspFsvolWork(
+ PDEVICE_OBJECT DeviceObject, PIRP Irp, PIO_STACK_LOCATION IrpSp)
+{
+ PAGED_CODE();
+
+ if (KernelMode != Irp->RequestorMode)
+ return STATUS_ACCESS_DENIED;
+
+ NTSTATUS Result;
+ FSP_FSVOL_DEVICE_EXTENSION *FsvolDeviceExtension = FspFsvolDeviceExtension(DeviceObject);
+ FSP_FSCTL_TRANSACT_REQ *Request = IrpSp->Parameters.FileSystemControl.Type3InputBuffer;
+
+ ASSERT(0 == Request->Hint);
+
+ /* associate the passed Request with our Irp; acquire ownership of the Request */
+ Request->Hint = (UINT_PTR)Irp;
+ FspIrpRequest(Irp) = Request;
+
+ /*
+ * Post the IRP to our Ioq; we do this here instead of at IRP_LEAVE_MJ time,
+ * so that we can disassociate the Request on failure and release ownership
+ * back to the caller.
+ */
+ if (!FspIoqPostIrp(&FsvolDeviceExtension->Ioq, Irp))
+ {
+ /* this can only happen if the Ioq was stopped */
+ ASSERT(FspIoqStopped(&FsvolDeviceExtension->Ioq));
+
+ Request->Hint = 0;
+ FspIrpRequest(Irp) = 0;
+
+ Result = STATUS_CANCELLED;
+ }
+ else
+ Result = STATUS_PENDING;
+
+ return Result;
+}
+#endif