mirror of
https://github.com/winfsp/winfsp.git
synced 2025-04-22 16:33:02 -05:00
Major refactoring: WIP
This commit is contained in:
parent
f3699716eb
commit
1ed7575316
@ -167,6 +167,7 @@
|
||||
<ClCompile Include="..\..\src\sys\shutdown.c" />
|
||||
<ClCompile Include="..\..\src\sys\util.c" />
|
||||
<ClCompile Include="..\..\src\sys\volinfo.c" />
|
||||
<ClCompile Include="..\..\src\sys\volume.c" />
|
||||
<ClCompile Include="..\..\src\sys\write.c" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
|
@ -80,6 +80,9 @@
|
||||
<ClCompile Include="..\..\src\sys\util.c">
|
||||
<Filter>Source</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\src\sys\volume.c">
|
||||
<Filter>Source</Filter>
|
||||
</ClCompile>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="..\..\src\sys\driver.h">
|
||||
|
@ -9,6 +9,11 @@
|
||||
|
||||
#include <devioctl.h>
|
||||
|
||||
#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! */
|
||||
|
@ -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;
|
||||
|
@ -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(
|
||||
|
@ -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'
|
||||
|
@ -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)
|
||||
{
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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
|
||||
|
497
src/sys/fsctl.c
497
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)
|
||||
{
|
||||
|
665
src/sys/volume.c
Normal file
665
src/sys/volume.c
Normal file
@ -0,0 +1,665 @@
|
||||
/**
|
||||
* @file sys/volume.c
|
||||
*
|
||||
* @copyright 2015 Bill Zissimopoulos
|
||||
*/
|
||||
|
||||
#include <sys/driver.h>
|
||||
|
||||
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
|
Loading…
x
Reference in New Issue
Block a user