mirror of
https://github.com/winfsp/winfsp.git
synced 2025-04-23 08:53:01 -05:00
495 lines
18 KiB
C
495 lines
18 KiB
C
/**
|
|
* @file sys/fsctl.c
|
|
*
|
|
* @copyright 2015 Bill Zissimopoulos
|
|
*/
|
|
|
|
#include <sys/driver.h>
|
|
|
|
/*
|
|
* Overview
|
|
*
|
|
* The fsctl module provides the IOCTL interface to interact with the
|
|
* user-mode file system. The user-mode file system can use the IOCTL's
|
|
* to create new volumes, delete them (while they are live!) and transact
|
|
* with them.
|
|
*
|
|
*
|
|
* Volume Creation
|
|
*
|
|
* The creation of a new volume is performed using an FSP_FSCTL_CREATE
|
|
* IOCTL code. Creation is simple: a new device \Device\Volume{GUID} is
|
|
* created and its path is returned to the user-mode file system. The
|
|
* user-mode file system also passes a security descriptor to associate
|
|
* with the new virtual volume device so that only the creating user-mode
|
|
* file system can control the new volume.
|
|
*
|
|
*
|
|
* Volume Deletion
|
|
*
|
|
* Deletion of an existing volume is performed using FSP_FSCTL_DELETE and
|
|
* is quite a bit more involved. We must protect against the following two
|
|
* eventualities: (1) that the volume is currently in use and cannot simply
|
|
* go away, and (2) that a simultaneous mount operation is taking place
|
|
* while we are deleting the volume.
|
|
*
|
|
* To protect against the first eventuality we maintain a reference count
|
|
* on all our device extensions. Every time an MJ function is entered,
|
|
* the reference count is incremented (FspDeviceRetain). Every time
|
|
* an IRP is completed, the reference count is decremented (FspDeviceRelease).
|
|
* When the reference count reaches 0 the device is deleted using
|
|
* IoDeleteDevice. This ensures that a device will not go away while an
|
|
* IRP is being pending/processed.
|
|
*
|
|
* To protect against the second eventuality we use the lock (ERESOURCE)
|
|
* on the root Fsctl device to wrap volume deletion and attempts from the
|
|
* system to mount the same volume. We also mark the virtual volume device
|
|
* as Deleted in case we attempt to delete it (FspDeviceRelease) but we
|
|
* cannot because it is currently in use.
|
|
*
|
|
* A sticky point is our use of the Windows VPB. It is not well documented
|
|
* how one should handle this structure during forcible dismount. The fastfat
|
|
* and cdfs samples use a technique where they keep a spare VPB and they swap
|
|
* it with the volume one during forcible dismount. We do something similar.
|
|
* The issue is what to do with the old VPB, because we can delete a volume
|
|
* that is not currently being used. We check the VPB's ReferenceCount and
|
|
* we free the VPB in this case.
|
|
*
|
|
*
|
|
* Volume Transact
|
|
*
|
|
* The user-mode file system's primary interaction with the kernel-mode driver
|
|
* is by using the FSP_FSCTL_TRANSACT IOCTL code. Every virtual volume device
|
|
* maintains an FSP_IOQ (refer to ioq.c for more). When an FSP_FSCTL_TRANSACT
|
|
* arrives it first processes any responses (FSP_FSCTL_TRANSACT_RSP) that the
|
|
* user-mode file system has sent to handle requests sent to it using a prior
|
|
* FSP_FSCTL_TRANSACT. It then proceeds to handle any pending IRP requests by
|
|
* sending the corresponding requests (FSP_FSCTL_TRANSACT_REQ) to the user-
|
|
* mode file system.
|
|
*/
|
|
|
|
static NTSTATUS FspFsctlCreateVolume(
|
|
PDEVICE_OBJECT DeviceObject, PIRP Irp, PIO_STACK_LOCATION IrpSp);
|
|
static NTSTATUS FspFsctlMountVolume(
|
|
PDEVICE_OBJECT DeviceObject, PIRP Irp, PIO_STACK_LOCATION IrpSp);
|
|
static NTSTATUS FspFsvrtDeleteVolume(
|
|
PDEVICE_OBJECT DeviceObject, PIRP Irp, PIO_STACK_LOCATION IrpSp);
|
|
static NTSTATUS FspFsvrtTransact(
|
|
PDEVICE_OBJECT DeviceObject, PIRP Irp, PIO_STACK_LOCATION IrpSp);
|
|
static NTSTATUS FspFsctlFileSystemControl(
|
|
PDEVICE_OBJECT DeviceObject, PIRP Irp, PIO_STACK_LOCATION IrpSp);
|
|
static NTSTATUS FspFsvrtFileSystemControl(
|
|
PDEVICE_OBJECT DeviceObject, PIRP Irp, PIO_STACK_LOCATION IrpSp);
|
|
static NTSTATUS FspFsvolFileSystemControl(
|
|
PDEVICE_OBJECT DeviceObject, PIRP Irp, PIO_STACK_LOCATION IrpSp);
|
|
FSP_DRIVER_DISPATCH FspFileSystemControl;
|
|
FSP_IOCMPL_DISPATCH FspFileSystemControlComplete;
|
|
|
|
#ifdef ALLOC_PRAGMA
|
|
#pragma alloc_text(PAGE, FspFsctlCreateVolume)
|
|
#pragma alloc_text(PAGE, FspFsctlMountVolume)
|
|
#pragma alloc_text(PAGE, FspFsvrtDeleteVolume)
|
|
#pragma alloc_text(PAGE, FspFsvrtTransact)
|
|
#pragma alloc_text(PAGE, FspFsctlFileSystemControl)
|
|
#pragma alloc_text(PAGE, FspFsvrtFileSystemControl)
|
|
#pragma alloc_text(PAGE, FspFsvolFileSystemControl)
|
|
#pragma alloc_text(PAGE, FspFileSystemControl)
|
|
#pragma alloc_text(PAGE, FspFileSystemControlComplete)
|
|
#endif
|
|
|
|
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;
|
|
const FSP_FSCTL_VOLUME_PARAMS *Params = SystemBuffer;
|
|
PSECURITY_DESCRIPTOR SecurityDescriptor = (PVOID)(Params + 1);
|
|
DWORD SecurityDescriptorSize = InputBufferLength - sizeof *Params;
|
|
if (sizeof *Params >= InputBufferLength || 0 == SystemBuffer ||
|
|
!RtlValidRelativeSecurityDescriptor(SecurityDescriptor, SecurityDescriptorSize,
|
|
OWNER_SECURITY_INFORMATION | DACL_SECURITY_INFORMATION))
|
|
return STATUS_INVALID_PARAMETER;
|
|
if (FSP_FSCTL_CREATE_BUFFER_SIZE > OutputBufferLength)
|
|
return STATUS_BUFFER_TOO_SMALL;
|
|
|
|
NTSTATUS Result;
|
|
PVOID SecurityDescriptorBuf = 0;
|
|
FSP_FSVRT_DEVICE_EXTENSION *FsvrtDeviceExtension;
|
|
|
|
/* create volume guid */
|
|
GUID Guid;
|
|
Result = FspCreateGuid(&Guid);
|
|
if (!NT_SUCCESS(Result))
|
|
return Result;
|
|
|
|
/* copy the security descriptor from the system buffer to a temporary one */
|
|
SecurityDescriptorBuf = ExAllocatePoolWithTag(PagedPool, SecurityDescriptorSize, FSP_TAG);
|
|
if (0 == SecurityDescriptorBuf)
|
|
return STATUS_INSUFFICIENT_RESOURCES;
|
|
RtlCopyMemory(SecurityDescriptorBuf, SecurityDescriptor, SecurityDescriptorSize);
|
|
|
|
/* create the virtual volume device */
|
|
PDEVICE_OBJECT FsvrtDeviceObject;
|
|
UNICODE_STRING DeviceSddl;
|
|
UNICODE_STRING DeviceName;
|
|
RtlInitUnicodeString(&DeviceSddl, L"" FSP_FSVRT_DEVICE_SDDL);
|
|
RtlInitEmptyUnicodeString(&DeviceName, SystemBuffer, FSP_FSCTL_CREATE_BUFFER_SIZE);
|
|
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));
|
|
Result = FspDeviceCreateSecure(FspFsvrtDeviceExtensionKind, SecurityDescriptorSize,
|
|
&DeviceName, FILE_DEVICE_VIRTUAL_DISK,
|
|
&DeviceSddl, &FspFsvrtDeviceClassGuid,
|
|
&FsvrtDeviceObject);
|
|
if (NT_SUCCESS(Result))
|
|
{
|
|
FsvrtDeviceExtension = FspFsvrtDeviceExtension(FsvrtDeviceObject);
|
|
FsvrtDeviceExtension->FsctlDeviceObject = DeviceObject;
|
|
FsvrtDeviceExtension->VolumeParams = *Params;
|
|
RtlCopyMemory(FsvrtDeviceExtension->SecurityDescriptorBuf,
|
|
SecurityDescriptorBuf, SecurityDescriptorSize);
|
|
ClearFlag(FsvrtDeviceObject->Flags, DO_DEVICE_INITIALIZING);
|
|
Irp->IoStatus.Information = DeviceName.Length + 1;
|
|
}
|
|
|
|
/* free the temporary security descriptor */
|
|
if (0 != SecurityDescriptorBuf)
|
|
ExFreePoolWithTag(SecurityDescriptorBuf, FSP_TAG);
|
|
|
|
return Result;
|
|
}
|
|
|
|
static NTSTATUS FspFsctlMountVolume(
|
|
PDEVICE_OBJECT DeviceObject, PIRP Irp, PIO_STACK_LOCATION IrpSp)
|
|
{
|
|
PAGED_CODE();
|
|
|
|
NTSTATUS Result;
|
|
FSP_FSCTL_DEVICE_EXTENSION *FsctlDeviceExtension = FspFsctlDeviceExtension(DeviceObject);
|
|
|
|
ExAcquireResourceExclusiveLite(&FsctlDeviceExtension->Base.Resource, TRUE);
|
|
try
|
|
{
|
|
PVPB Vpb = IrpSp->Parameters.MountVolume.Vpb;
|
|
PDEVICE_OBJECT FsvrtDeviceObject = Vpb->RealDevice;
|
|
PDEVICE_OBJECT FsvolDeviceObject;
|
|
FSP_FSVRT_DEVICE_EXTENSION *FsvrtDeviceExtension =
|
|
FspFsvrtDeviceExtension(FsvrtDeviceObject);
|
|
FSP_FSVOL_DEVICE_EXTENSION *FsvolDeviceExtension;
|
|
|
|
/* check the passed in volume object; it must be one of our own */
|
|
Result = FspDeviceOwned(FsvrtDeviceObject);
|
|
if (!NT_SUCCESS(Result))
|
|
{
|
|
if (STATUS_NO_SUCH_DEVICE == Result)
|
|
Result = STATUS_UNRECOGNIZED_VOLUME;
|
|
goto exit;
|
|
}
|
|
if (FspDeviceDeleted(FsvrtDeviceObject) || FsvrtDeviceExtension->Deleted ||
|
|
FILE_DEVICE_VIRTUAL_DISK != FsvrtDeviceObject->DeviceType)
|
|
{
|
|
Result = STATUS_UNRECOGNIZED_VOLUME;
|
|
goto exit;
|
|
}
|
|
|
|
/* create the file system device object */
|
|
Result = FspDeviceCreate(FspFsvolDeviceExtensionKind, 0,
|
|
DeviceObject->DeviceType,
|
|
&FsvolDeviceObject);
|
|
if (NT_SUCCESS(Result))
|
|
{
|
|
FsvolDeviceExtension = FspFsvolDeviceExtension(FsvolDeviceObject);
|
|
#pragma prefast(suppress:28175, "We are a filesystem: ok to access SectorSize")
|
|
FsvolDeviceObject->SectorSize = FsvrtDeviceExtension->VolumeParams.SectorSize;
|
|
FsvolDeviceExtension->FsvrtDeviceObject = FsvrtDeviceObject;
|
|
FsvrtDeviceExtension->FsvolDeviceObject = FsvolDeviceObject;
|
|
ClearFlag(FsvolDeviceObject->Flags, DO_DEVICE_INITIALIZING);
|
|
Vpb->DeviceObject = FsvolDeviceObject;
|
|
Irp->IoStatus.Information = 0;
|
|
}
|
|
|
|
exit:;
|
|
}
|
|
finally
|
|
{
|
|
ExReleaseResourceLite(&FsctlDeviceExtension->Base.Resource);
|
|
}
|
|
|
|
return Result;
|
|
}
|
|
|
|
static NTSTATUS FspFsvrtDeleteVolume(
|
|
PDEVICE_OBJECT DeviceObject, PIRP Irp, PIO_STACK_LOCATION IrpSp)
|
|
{
|
|
PAGED_CODE();
|
|
|
|
FSP_FSVRT_DEVICE_EXTENSION *FsvrtDeviceExtension = FspFsvrtDeviceExtension(DeviceObject);
|
|
FSP_FSCTL_DEVICE_EXTENSION *FsctlDeviceExtension =
|
|
FspFsctlDeviceExtension(FsvrtDeviceExtension->FsctlDeviceObject);
|
|
|
|
ExAcquireResourceExclusiveLite(&FsctlDeviceExtension->Base.Resource, TRUE);
|
|
try
|
|
{
|
|
NTSTATUS Result;
|
|
PVPB OldVpb;
|
|
BOOLEAN FreeVpb = FALSE;
|
|
KIRQL Irql;
|
|
|
|
/* access check */
|
|
Result = FspSecuritySubjectContextAccessCheck(
|
|
FsvrtDeviceExtension->SecurityDescriptorBuf, FILE_WRITE_DATA, Irp->RequestorMode);
|
|
if (!NT_SUCCESS(Result))
|
|
goto exit;
|
|
|
|
/* mark the virtual volume device as deleted */
|
|
FsvrtDeviceExtension->Deleted = TRUE;
|
|
|
|
/* stop the I/O queue */
|
|
FspIoqStop(&FsvrtDeviceExtension->Ioq);
|
|
|
|
/* swap the preallocated VPB */
|
|
#pragma prefast(push)
|
|
#pragma prefast(disable:28175, "We are a filesystem: ok to access Vpb")
|
|
IoAcquireVpbSpinLock(&Irql);
|
|
OldVpb = DeviceObject->Vpb;
|
|
if (0 != OldVpb && 0 != FsvrtDeviceExtension->SwapVpb)
|
|
{
|
|
DeviceObject->Vpb = FsvrtDeviceExtension->SwapVpb;
|
|
DeviceObject->Vpb->Size = sizeof *DeviceObject->Vpb;
|
|
DeviceObject->Vpb->Type = IO_TYPE_VPB;
|
|
DeviceObject->Vpb->Flags = FlagOn(OldVpb->Flags, VPB_REMOVE_PENDING);
|
|
DeviceObject->Vpb->RealDevice = OldVpb->RealDevice;
|
|
DeviceObject->Vpb->RealDevice->Vpb = DeviceObject->Vpb;
|
|
FsvrtDeviceExtension->SwapVpb = 0;
|
|
FreeVpb = 0 == OldVpb->ReferenceCount;
|
|
}
|
|
IoReleaseVpbSpinLock(Irql);
|
|
if (FreeVpb)
|
|
ExFreePool(OldVpb);
|
|
#pragma prefast(pop)
|
|
|
|
/* release the file system device and virtual volume objects */
|
|
PDEVICE_OBJECT FsvolDeviceObject = FsvrtDeviceExtension->FsvolDeviceObject;
|
|
FsvrtDeviceExtension->FsvolDeviceObject = 0;
|
|
if (0 != FsvolDeviceObject)
|
|
FspDeviceRelease(FsvolDeviceObject);
|
|
FspDeviceRelease(DeviceObject);
|
|
|
|
exit:;
|
|
}
|
|
finally
|
|
{
|
|
ExReleaseResourceLite(&FsctlDeviceExtension->Base.Resource);
|
|
}
|
|
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
static NTSTATUS FspFsvrtTransact(
|
|
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 (sizeof(FSP_FSCTL_TRANSACT_RSP) > InputBufferLength || 0 == SystemBuffer)
|
|
return STATUS_INVALID_PARAMETER;
|
|
if (FSP_FSCTL_TRANSACT_BUFFER_SIZE > OutputBufferLength)
|
|
return STATUS_BUFFER_TOO_SMALL;
|
|
|
|
NTSTATUS Result;
|
|
FSP_FSVRT_DEVICE_EXTENSION *FsvrtDeviceExtension = FspFsvrtDeviceExtension(DeviceObject);
|
|
PUINT8 SystemBufferEnd;
|
|
const FSP_FSCTL_TRANSACT_RSP *Response, *NextResponse;
|
|
FSP_FSCTL_TRANSACT_REQ *Request, *NextRequest, *PendingIrpRequest;
|
|
PIRP ProcessIrp, PendingIrp;
|
|
|
|
/* access check */
|
|
Result = FspSecuritySubjectContextAccessCheck(
|
|
FsvrtDeviceExtension->SecurityDescriptorBuf, FILE_WRITE_DATA, Irp->RequestorMode);
|
|
if (!NT_SUCCESS(Result))
|
|
return Result;
|
|
|
|
/* process any user-mode file system responses */
|
|
Response = SystemBuffer;
|
|
SystemBufferEnd = (PUINT8)SystemBuffer + InputBufferLength;
|
|
for (;;)
|
|
{
|
|
NextResponse = FspFsctlTransactConsumeResponse(Response, SystemBufferEnd);
|
|
if (0 == NextResponse)
|
|
break;
|
|
|
|
ProcessIrp = FspIoqEndProcessingIrp(&FsvrtDeviceExtension->Ioq, (UINT_PTR)Response->Hint);
|
|
if (0 == ProcessIrp)
|
|
/* either IRP was canceled or a bogus Hint was provided */
|
|
continue;
|
|
|
|
FspIopDispatchComplete(ProcessIrp, Response);
|
|
|
|
Response = NextResponse;
|
|
}
|
|
|
|
/* wait for an IRP to arrive */
|
|
while (0 == (PendingIrp = FspIoqNextPendingIrp(&FsvrtDeviceExtension->Ioq, (ULONG)-1L)))
|
|
{
|
|
if (FspIoqStopped(&FsvrtDeviceExtension->Ioq))
|
|
return STATUS_CANCELLED;
|
|
}
|
|
|
|
/* send any pending IRP's to the user-mode file system */
|
|
Request = SystemBuffer;
|
|
SystemBufferEnd = (PUINT8)SystemBuffer + OutputBufferLength;
|
|
ASSERT((PUINT8)Request + FSP_FSCTL_TRANSACT_REQ_SIZEMAX <= SystemBufferEnd);
|
|
for (;;)
|
|
{
|
|
PendingIrpRequest = PendingIrp->Tail.Overlay.DriverContext[0];
|
|
|
|
NextRequest = FspFsctlTransactProduceRequest(
|
|
Request, PendingIrpRequest->Size, SystemBufferEnd);
|
|
/* this should not fail as we have already checked that we have enough space */
|
|
ASSERT(0 != NextRequest);
|
|
|
|
RtlCopyMemory(Request, PendingIrpRequest, PendingIrpRequest->Size);
|
|
Request = NextRequest;
|
|
|
|
if (!FspIoqStartProcessingIrp(&FsvrtDeviceExtension->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(&FsvrtDeviceExtension->Ioq));
|
|
FspIopCompleteRequest(PendingIrp, STATUS_CANCELLED);
|
|
return STATUS_CANCELLED;
|
|
}
|
|
|
|
/* check that we have enough space before pulling the next pending IRP off the queue */
|
|
if ((PUINT8)Request + FSP_FSCTL_TRANSACT_REQ_SIZEMAX > SystemBufferEnd)
|
|
break;
|
|
|
|
PendingIrp = FspIoqNextPendingIrp(&FsvrtDeviceExtension->Ioq, 0);
|
|
if (0 == PendingIrp)
|
|
break;
|
|
|
|
}
|
|
RtlZeroMemory(Request, SystemBufferEnd - (PUINT8)Request);
|
|
Irp->IoStatus.Information = (PUINT8)Request - (PUINT8)SystemBuffer;
|
|
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
static NTSTATUS FspFsctlFileSystemControl(
|
|
PDEVICE_OBJECT DeviceObject, PIRP Irp, PIO_STACK_LOCATION IrpSp)
|
|
{
|
|
PAGED_CODE();
|
|
|
|
NTSTATUS Result = STATUS_INVALID_DEVICE_REQUEST;
|
|
switch (IrpSp->MinorFunction)
|
|
{
|
|
case IRP_MN_USER_FS_REQUEST:
|
|
switch (IrpSp->Parameters.FileSystemControl.FsControlCode)
|
|
{
|
|
case FSP_FSCTL_CREATE:
|
|
Result = FspFsctlCreateVolume(DeviceObject, Irp, IrpSp);
|
|
break;
|
|
}
|
|
break;
|
|
case IRP_MN_MOUNT_VOLUME:
|
|
Result = FspFsctlMountVolume(DeviceObject, Irp, IrpSp);
|
|
break;
|
|
#if 0
|
|
case IRP_MN_VERIFY_VOLUME:
|
|
break;
|
|
#endif
|
|
}
|
|
return Result;
|
|
}
|
|
|
|
static NTSTATUS FspFsvrtFileSystemControl(
|
|
PDEVICE_OBJECT DeviceObject, PIRP Irp, PIO_STACK_LOCATION IrpSp)
|
|
{
|
|
PAGED_CODE();
|
|
|
|
NTSTATUS Result = STATUS_INVALID_DEVICE_REQUEST;
|
|
switch (IrpSp->MinorFunction)
|
|
{
|
|
case IRP_MN_USER_FS_REQUEST:
|
|
switch (IrpSp->Parameters.FileSystemControl.FsControlCode)
|
|
{
|
|
case FSP_FSCTL_DELETE:
|
|
Result = FspFsvrtDeleteVolume(DeviceObject, Irp, IrpSp);
|
|
break;
|
|
case FSP_FSCTL_TRANSACT:
|
|
Result = FspFsvrtTransact(DeviceObject, Irp, IrpSp);
|
|
break;
|
|
}
|
|
break;
|
|
}
|
|
return Result;
|
|
}
|
|
|
|
static NTSTATUS FspFsvolFileSystemControl(
|
|
PDEVICE_OBJECT DeviceObject, PIRP Irp, PIO_STACK_LOCATION IrpSp)
|
|
{
|
|
PAGED_CODE();
|
|
|
|
NTSTATUS Result = STATUS_INVALID_DEVICE_REQUEST;
|
|
switch (IrpSp->MinorFunction)
|
|
{
|
|
case IRP_MN_USER_FS_REQUEST:
|
|
break;
|
|
}
|
|
return Result;
|
|
}
|
|
|
|
NTSTATUS FspFileSystemControl(
|
|
PDEVICE_OBJECT DeviceObject, PIRP Irp)
|
|
{
|
|
FSP_ENTER_MJ(PAGED_CODE());
|
|
|
|
ASSERT(IRP_MJ_FILE_SYSTEM_CONTROL == IrpSp->MajorFunction);
|
|
|
|
switch (FspDeviceExtension(DeviceObject)->Kind)
|
|
{
|
|
case FspFsvolDeviceExtensionKind:
|
|
FSP_RETURN(Result = FspFsctlFileSystemControl(DeviceObject, Irp, IrpSp));
|
|
case FspFsvrtDeviceExtensionKind:
|
|
FSP_RETURN(Result = FspFsvrtFileSystemControl(DeviceObject, Irp, IrpSp));
|
|
case FspFsctlDeviceExtensionKind:
|
|
FSP_RETURN(Result = FspFsvolFileSystemControl(DeviceObject, Irp, IrpSp));
|
|
default:
|
|
FSP_RETURN(Result = STATUS_INVALID_DEVICE_REQUEST);
|
|
}
|
|
|
|
FSP_LEAVE_MJ(
|
|
"FileObject=%p%s%s",
|
|
IrpSp->FileObject,
|
|
IRP_MN_USER_FS_REQUEST == IrpSp->MinorFunction ? ", " : "",
|
|
IRP_MN_USER_FS_REQUEST == IrpSp->MinorFunction ?
|
|
IoctlCodeSym(IrpSp->Parameters.FileSystemControl.FsControlCode) : "");
|
|
}
|
|
|
|
VOID FspFileSystemControlComplete(
|
|
PIRP Irp, const FSP_FSCTL_TRANSACT_RSP *Response)
|
|
{
|
|
FSP_ENTER_IOC(PAGED_CODE());
|
|
|
|
FSP_LEAVE_IOC(
|
|
"FileObject=%p%s%s",
|
|
IrpSp->FileObject,
|
|
IRP_MN_USER_FS_REQUEST == IrpSp->MinorFunction ? ", " : "",
|
|
IRP_MN_USER_FS_REQUEST == IrpSp->MinorFunction ?
|
|
IoctlCodeSym(IrpSp->Parameters.FileSystemControl.FsControlCode) : "");
|
|
}
|