mirror of
https://github.com/winfsp/winfsp.git
synced 2025-06-14 15:52:47 -05:00
Merge branch 'pvt-devctl'
This commit is contained in:
@ -162,6 +162,7 @@ FSP_API NTSTATUS FspFileSystemCreate(PWSTR DevicePath,
|
||||
FileSystem->Operations[FspFsctlTransactSetVolumeInformationKind] = FspFileSystemOpSetVolumeInformation;
|
||||
FileSystem->Operations[FspFsctlTransactQueryDirectoryKind] = FspFileSystemOpQueryDirectory;
|
||||
FileSystem->Operations[FspFsctlTransactFileSystemControlKind] = FspFileSystemOpFileSystemControl;
|
||||
FileSystem->Operations[FspFsctlTransactDeviceControlKind] = FspFileSystemOpDeviceControl;
|
||||
FileSystem->Operations[FspFsctlTransactQuerySecurityKind] = FspFileSystemOpQuerySecurity;
|
||||
FileSystem->Operations[FspFsctlTransactSetSecurityKind] = FspFileSystemOpSetSecurity;
|
||||
FileSystem->Operations[FspFsctlTransactQueryStreamInformationKind] = FspFileSystemOpQueryStreamInformation;
|
||||
|
@ -1247,6 +1247,30 @@ FSP_API NTSTATUS FspFileSystemOpFileSystemControl(FSP_FILE_SYSTEM *FileSystem,
|
||||
return Result;
|
||||
}
|
||||
|
||||
FSP_API NTSTATUS FspFileSystemOpDeviceControl(FSP_FILE_SYSTEM *FileSystem,
|
||||
FSP_FSCTL_TRANSACT_REQ *Request, FSP_FSCTL_TRANSACT_RSP *Response)
|
||||
{
|
||||
NTSTATUS Result;
|
||||
ULONG BytesTransferred;
|
||||
|
||||
if (0 == FileSystem->Interface->Control)
|
||||
return STATUS_INVALID_DEVICE_REQUEST;
|
||||
|
||||
Result = FileSystem->Interface->Control(FileSystem,
|
||||
(PVOID)ValOfFileContext(Request->Req.DeviceControl),
|
||||
Request->Req.DeviceControl.IoControlCode,
|
||||
Request->Buffer, Request->Req.DeviceControl.Buffer.Size,
|
||||
Response->Buffer, Request->Req.DeviceControl.OutputLength/* FSD guarantees correct size! */,
|
||||
&BytesTransferred);
|
||||
if (!NT_SUCCESS(Result))
|
||||
return STATUS_BUFFER_OVERFLOW != Result ? Result : STATUS_BUFFER_TOO_SMALL;
|
||||
|
||||
Response->Size = (UINT16)(sizeof *Response + BytesTransferred);
|
||||
Response->Rsp.DeviceControl.Buffer.Offset = 0;
|
||||
Response->Rsp.DeviceControl.Buffer.Size = (UINT16)BytesTransferred;
|
||||
return STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
FSP_API NTSTATUS FspFileSystemOpQuerySecurity(FSP_FILE_SYSTEM *FileSystem,
|
||||
FSP_FSCTL_TRANSACT_REQ *Request, FSP_FSCTL_TRANSACT_RSP *Response)
|
||||
{
|
||||
|
@ -649,6 +649,7 @@ FSP_FUSE_API struct fuse *fsp_fuse_new(struct fsp_fuse_env *env,
|
||||
opt_data.VolumeParams.ReadOnlyVolume = FALSE;
|
||||
opt_data.VolumeParams.PostCleanupWhenModifiedOnly = TRUE;
|
||||
opt_data.VolumeParams.PassQueryDirectoryFileName = TRUE;
|
||||
opt_data.VolumeParams.DeviceControl = TRUE;
|
||||
opt_data.VolumeParams.UmFileContextIsUserContext2 = TRUE;
|
||||
if (L'\0' == opt_data.VolumeParams.FileSystemName[0])
|
||||
memcpy(opt_data.VolumeParams.FileSystemName, L"FUSE", 5 * sizeof(WCHAR));
|
||||
|
@ -2125,6 +2125,47 @@ static NTSTATUS fsp_fuse_intf_DeleteReparsePoint(FSP_FILE_SYSTEM *FileSystem,
|
||||
return STATUS_ACCESS_DENIED;
|
||||
}
|
||||
|
||||
static NTSTATUS fsp_fuse_intf_Control(FSP_FILE_SYSTEM *FileSystem,
|
||||
PVOID FileNode, UINT32 ControlCode,
|
||||
PVOID InputBuffer, ULONG InputBufferLength,
|
||||
PVOID OutputBuffer, ULONG OutputBufferLength, PULONG PBytesTransferred)
|
||||
{
|
||||
struct fuse *f = FileSystem->UserContext;
|
||||
struct fsp_fuse_file_desc *filedesc = FileNode;
|
||||
struct fuse_file_info fi;
|
||||
int cmd;
|
||||
int err;
|
||||
|
||||
if (0 == f->ops.ioctl)
|
||||
return STATUS_INVALID_DEVICE_REQUEST;
|
||||
|
||||
if (FSP_FUSE_DEVICE_TYPE != DEVICE_TYPE_FROM_CTL_CODE(ControlCode))
|
||||
return STATUS_INVALID_DEVICE_REQUEST;
|
||||
|
||||
if (0 != InputBufferLength && 0 != OutputBufferLength &&
|
||||
InputBufferLength != OutputBufferLength)
|
||||
return STATUS_INVALID_DEVICE_REQUEST;
|
||||
|
||||
memset(&fi, 0, sizeof fi);
|
||||
fi.flags = filedesc->OpenFlags;
|
||||
fi.fh = filedesc->FileHandle;
|
||||
|
||||
/* construct a Linux compatible ioctl code */
|
||||
cmd = FSP_FUSE_IOCTL((ControlCode >> 2) & 0xfff, InputBufferLength, OutputBufferLength);
|
||||
|
||||
if (0 == OutputBufferLength)
|
||||
err = f->ops.ioctl(filedesc->PosixPath, cmd, 0, &fi, 0, InputBuffer);
|
||||
else
|
||||
{
|
||||
if (0 != InputBufferLength)
|
||||
// OutputBuffer points to Response->Buffer which is FSP_FSCTL_TRANSACT_RSP_BUFFER_SIZEMAX long
|
||||
memcpy(OutputBuffer, InputBuffer, InputBufferLength);
|
||||
err = f->ops.ioctl(filedesc->PosixPath, cmd, 0, &fi, 0, OutputBuffer);
|
||||
}
|
||||
|
||||
return fsp_fuse_ntstatus_from_errno(f->env, err);
|
||||
}
|
||||
|
||||
FSP_FILE_SYSTEM_INTERFACE fsp_fuse_intf =
|
||||
{
|
||||
fsp_fuse_intf_GetVolumeInfo,
|
||||
@ -2152,6 +2193,7 @@ FSP_FILE_SYSTEM_INTERFACE fsp_fuse_intf =
|
||||
fsp_fuse_intf_DeleteReparsePoint,
|
||||
0,
|
||||
fsp_fuse_intf_GetDirInfoByName,
|
||||
fsp_fuse_intf_Control,
|
||||
};
|
||||
|
||||
/*
|
||||
|
@ -966,6 +966,49 @@ namespace Fsp
|
||||
FileInfo = default(FileInfo);
|
||||
return STATUS_INVALID_DEVICE_REQUEST;
|
||||
}
|
||||
/// <summary>
|
||||
/// Processes a control code.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// This function is called when a program uses the DeviceIoControl API.
|
||||
/// </remarks>
|
||||
/// <param name="FileNode">
|
||||
/// The file node of the file or directory to be controled.
|
||||
/// </param>
|
||||
/// <param name="FileDesc">
|
||||
/// The file descriptor of the file or directory to be controled.
|
||||
/// </param>
|
||||
/// <param name="ControlCode">
|
||||
/// The control code for the operation. This code must have a DeviceType with bit
|
||||
/// 0x8000 set and must have a TransferType of METHOD_BUFFERED.
|
||||
/// </param>
|
||||
/// <param name="InputBuffer">
|
||||
/// Pointer to a buffer that contains the input data.
|
||||
/// </param>
|
||||
/// <param name="InputBufferLength">
|
||||
/// Input data length.
|
||||
/// </param>
|
||||
/// <param name="OutputBuffer">
|
||||
/// Pointer to a buffer that will receive the output data.
|
||||
/// </param>
|
||||
/// <param name="OutputBufferLength">
|
||||
/// Output data length.
|
||||
/// </param>
|
||||
/// <param name="BytesTransferred">
|
||||
/// Receives the actual number of bytes transferred.
|
||||
/// </param>
|
||||
/// <returns>STATUS_SUCCESS or error code.</returns>
|
||||
public virtual Int32 Control(
|
||||
Object FileNode,
|
||||
Object FileDesc,
|
||||
UInt32 ControlCode,
|
||||
IntPtr InputBuffer, UInt32 InputBufferLength,
|
||||
IntPtr OutputBuffer, UInt32 OutputBufferLength,
|
||||
out UInt32 BytesTransferred)
|
||||
{
|
||||
BytesTransferred = default(UInt32);
|
||||
return STATUS_INVALID_DEVICE_REQUEST;
|
||||
}
|
||||
|
||||
/* helpers */
|
||||
/// <summary>
|
||||
|
@ -1020,6 +1020,35 @@ namespace Fsp
|
||||
return ExceptionHandler(FileSystem, ex);
|
||||
}
|
||||
}
|
||||
private static Int32 Control(
|
||||
IntPtr FileSystemPtr,
|
||||
ref FullContext FullContext,
|
||||
UInt32 ControlCode,
|
||||
IntPtr InputBuffer, UInt32 InputBufferLength,
|
||||
IntPtr OutputBuffer, UInt32 OutputBufferLength,
|
||||
out UInt32 PBytesTransferred)
|
||||
{
|
||||
FileSystemBase FileSystem = (FileSystemBase)Api.GetUserContext(FileSystemPtr);
|
||||
try
|
||||
{
|
||||
Object FileNode, FileDesc;
|
||||
Api.GetFullContext(ref FullContext, out FileNode, out FileDesc);
|
||||
return FileSystem.Control(
|
||||
FileNode,
|
||||
FileDesc,
|
||||
ControlCode,
|
||||
InputBuffer,
|
||||
InputBufferLength,
|
||||
OutputBuffer,
|
||||
OutputBufferLength,
|
||||
out PBytesTransferred);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
PBytesTransferred = default(UInt32);
|
||||
return ExceptionHandler(FileSystem, ex);
|
||||
}
|
||||
}
|
||||
|
||||
static FileSystemHost()
|
||||
{
|
||||
@ -1048,6 +1077,7 @@ namespace Fsp
|
||||
_FileSystemInterface.DeleteReparsePoint = DeleteReparsePoint;
|
||||
_FileSystemInterface.GetStreamInfo = GetStreamInfo;
|
||||
_FileSystemInterface.GetDirInfoByName = GetDirInfoByName;
|
||||
_FileSystemInterface.Control = Control;
|
||||
|
||||
_FileSystemInterfacePtr = Marshal.AllocHGlobal(FileSystemInterface.Size);
|
||||
Marshal.StructureToPtr(_FileSystemInterface, _FileSystemInterfacePtr, false);
|
||||
|
@ -457,6 +457,14 @@ namespace Fsp.Interop
|
||||
ref FullContext FullContext,
|
||||
[MarshalAs(UnmanagedType.LPWStr)] String FileName,
|
||||
out DirInfo DirInfo);
|
||||
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
||||
internal delegate Int32 Control(
|
||||
IntPtr FileSystem,
|
||||
ref FullContext FullContext,
|
||||
UInt32 ControlCode,
|
||||
IntPtr InputBuffer, UInt32 InputBufferLength,
|
||||
IntPtr OutputBuffer, UInt32 OutputBufferLength,
|
||||
out UInt32 PBytesTransferred);
|
||||
}
|
||||
|
||||
internal static int Size = IntPtr.Size * 64;
|
||||
@ -486,7 +494,8 @@ namespace Fsp.Interop
|
||||
internal Proto.DeleteReparsePoint DeleteReparsePoint;
|
||||
internal Proto.GetStreamInfo GetStreamInfo;
|
||||
internal Proto.GetDirInfoByName GetDirInfoByName;
|
||||
/* NTSTATUS (*Reserved[39])(); */
|
||||
internal Proto.Control Control;
|
||||
/* NTSTATUS (*Reserved[38])(); */
|
||||
}
|
||||
|
||||
[SuppressUnmanagedCodeSecurity]
|
||||
|
@ -20,20 +20,81 @@
|
||||
static NTSTATUS FspFsvolDeviceControl(
|
||||
PDEVICE_OBJECT DeviceObject, PIRP Irp, PIO_STACK_LOCATION IrpSp);
|
||||
FSP_IOCMPL_DISPATCH FspFsvolDeviceControlComplete;
|
||||
static FSP_IOP_REQUEST_FINI FspFsvolDeviceControlRequestFini;
|
||||
FSP_DRIVER_DISPATCH FspDeviceControl;
|
||||
|
||||
#ifdef ALLOC_PRAGMA
|
||||
#pragma alloc_text(PAGE, FspFsvolDeviceControl)
|
||||
#pragma alloc_text(PAGE, FspFsvolDeviceControlComplete)
|
||||
#pragma alloc_text(PAGE, FspFsvolDeviceControlRequestFini)
|
||||
#pragma alloc_text(PAGE, FspDeviceControl)
|
||||
#endif
|
||||
|
||||
enum
|
||||
{
|
||||
RequestFileNode = 0,
|
||||
};
|
||||
|
||||
static NTSTATUS FspFsvolDeviceControl(
|
||||
PDEVICE_OBJECT DeviceObject, PIRP Irp, PIO_STACK_LOCATION IrpSp)
|
||||
PDEVICE_OBJECT FsvolDeviceObject, PIRP Irp, PIO_STACK_LOCATION IrpSp)
|
||||
{
|
||||
PAGED_CODE();
|
||||
|
||||
return STATUS_INVALID_DEVICE_REQUEST;
|
||||
FSP_FSVOL_DEVICE_EXTENSION *FsvolDeviceExtension = FspFsvolDeviceExtension(FsvolDeviceObject);
|
||||
PFILE_OBJECT FileObject = IrpSp->FileObject;
|
||||
ULONG IoControlCode = IrpSp->Parameters.DeviceIoControl.IoControlCode;
|
||||
|
||||
/* do we support DeviceControl? */
|
||||
if (!FsvolDeviceExtension->VolumeParams.DeviceControl)
|
||||
return STATUS_INVALID_DEVICE_REQUEST;
|
||||
|
||||
/* do not forward IRP's originating in the kernel! */
|
||||
if (KernelMode == Irp->RequestorMode)
|
||||
return STATUS_INVALID_DEVICE_REQUEST;
|
||||
|
||||
/* only allow custom devices and METHOD_BUFFERED */
|
||||
if (0 == (DEVICE_TYPE_FROM_CTL_CODE(IoControlCode) & 0x8000) ||
|
||||
METHOD_BUFFERED != METHOD_FROM_CTL_CODE(IoControlCode))
|
||||
return STATUS_INVALID_DEVICE_REQUEST;
|
||||
|
||||
/* is this a valid FileObject? */
|
||||
if (!FspFileNodeIsValid(FileObject->FsContext))
|
||||
return STATUS_INVALID_PARAMETER;
|
||||
|
||||
NTSTATUS Result;
|
||||
FSP_FILE_NODE *FileNode = FileObject->FsContext;
|
||||
FSP_FILE_DESC *FileDesc = FileObject->FsContext2;
|
||||
PVOID InputBuffer = Irp->AssociatedIrp.SystemBuffer;
|
||||
ULONG InputBufferLength = IrpSp->Parameters.DeviceIoControl.InputBufferLength;
|
||||
ULONG OutputBufferLength = IrpSp->Parameters.DeviceIoControl.OutputBufferLength;
|
||||
FSP_FSCTL_TRANSACT_REQ *Request;
|
||||
|
||||
ASSERT(FileNode == FileDesc->FileNode);
|
||||
|
||||
if (FSP_FSCTL_DEVICECONTROL_SIZEMAX < InputBufferLength ||
|
||||
FSP_FSCTL_DEVICECONTROL_SIZEMAX < OutputBufferLength)
|
||||
return STATUS_INVALID_BUFFER_SIZE;
|
||||
|
||||
Result = FspIopCreateRequestEx(Irp, 0, InputBufferLength,
|
||||
FspFsvolDeviceControlRequestFini, &Request);
|
||||
if (!NT_SUCCESS(Result))
|
||||
return Result;
|
||||
|
||||
FspFileNodeAcquireShared(FileNode, Full);
|
||||
|
||||
Request->Kind = FspFsctlTransactDeviceControlKind;
|
||||
Request->Req.DeviceControl.UserContext = FileNode->UserContext;
|
||||
Request->Req.DeviceControl.UserContext2 = FileDesc->UserContext2;
|
||||
Request->Req.DeviceControl.IoControlCode = IoControlCode;
|
||||
Request->Req.DeviceControl.Buffer.Offset = 0;
|
||||
Request->Req.DeviceControl.Buffer.Size = (UINT16)InputBufferLength;
|
||||
Request->Req.DeviceControl.OutputLength = OutputBufferLength;
|
||||
RtlCopyMemory(Request->Buffer, InputBuffer, InputBufferLength);
|
||||
|
||||
FspFileNodeSetOwner(FileNode, Full, Request);
|
||||
FspIopRequestContext(Request, RequestFileNode) = FileNode;
|
||||
|
||||
return FSP_STATUS_IOQ_POST;
|
||||
}
|
||||
|
||||
NTSTATUS FspFsvolDeviceControlComplete(
|
||||
@ -41,12 +102,46 @@ NTSTATUS FspFsvolDeviceControlComplete(
|
||||
{
|
||||
FSP_ENTER_IOC(PAGED_CODE());
|
||||
|
||||
if (!NT_SUCCESS(Response->IoStatus.Status))
|
||||
{
|
||||
Irp->IoStatus.Information = 0;
|
||||
Result = Response->IoStatus.Status;
|
||||
FSP_RETURN();
|
||||
}
|
||||
|
||||
PVOID OutputBuffer = Irp->AssociatedIrp.SystemBuffer;
|
||||
ULONG OutputBufferLength = IrpSp->Parameters.DeviceIoControl.OutputBufferLength;
|
||||
|
||||
if (Response->Buffer + Response->Rsp.DeviceControl.Buffer.Offset +
|
||||
Response->Rsp.DeviceControl.Buffer.Size > (PUINT8)Response + Response->Size)
|
||||
FSP_RETURN(Result = STATUS_INTERNAL_ERROR);
|
||||
|
||||
if (OutputBufferLength >= Response->Rsp.DeviceControl.Buffer.Size)
|
||||
OutputBufferLength = Response->Rsp.DeviceControl.Buffer.Size;
|
||||
else
|
||||
Result = STATUS_BUFFER_OVERFLOW;
|
||||
|
||||
RtlCopyMemory(OutputBuffer, Response->Buffer + Response->Rsp.DeviceControl.Buffer.Offset,
|
||||
OutputBufferLength);
|
||||
|
||||
Irp->IoStatus.Information = OutputBufferLength;
|
||||
|
||||
FSP_LEAVE_IOC(
|
||||
"%s, FileObject=%p",
|
||||
IoctlCodeSym(IrpSp->Parameters.DeviceIoControl.IoControlCode),
|
||||
IrpSp->FileObject);
|
||||
}
|
||||
|
||||
static VOID FspFsvolDeviceControlRequestFini(FSP_FSCTL_TRANSACT_REQ *Request, PVOID Context[4])
|
||||
{
|
||||
PAGED_CODE();
|
||||
|
||||
FSP_FILE_NODE *FileNode = Context[RequestFileNode];
|
||||
|
||||
if (0 != FileNode)
|
||||
FspFileNodeReleaseOwner(FileNode, Full, Request);
|
||||
}
|
||||
|
||||
NTSTATUS FspDeviceControl(
|
||||
PDEVICE_OBJECT DeviceObject, PIRP Irp)
|
||||
{
|
||||
|
Reference in New Issue
Block a user