mirror of
https://github.com/winfsp/winfsp.git
synced 2025-07-02 17:02:57 -05:00
Compare commits
10 Commits
Author | SHA1 | Date | |
---|---|---|---|
d491031fda | |||
75a3d97c62 | |||
a2ed9f2b1a | |||
fdaf1da778 | |||
06ee833740 | |||
fbcefe6339 | |||
637a1dac7e | |||
05f622f2de | |||
ef5c947168 | |||
894ae7b8f3 |
12
.github/ISSUE_TEMPLATE.md
vendored
12
.github/ISSUE_TEMPLATE.md
vendored
@ -1,12 +0,0 @@
|
||||
(Enter your issue here.)
|
||||
|
||||
----
|
||||
|
||||
Before submitting this issue please review this checklist. Ideally all checkmarks should be checked upon submitting. (Use an x inside square brackets like so: [x])
|
||||
|
||||
- [ ] **Issue type**: Please consider posting only bug reports or enhancement requests. Questions are better in the [WinFsp Google Group](https://groups.google.com/forum/#!forum/winfsp). Please also consult the [WinFsp Frequently Asked Questions](https://github.com/billziss-gh/winfsp/wiki/Frequently-Asked-Questions).
|
||||
- [ ] **No Duplicate**: Ensure that your issue has not been filed before. (Check open and closed issues.)
|
||||
- [ ] **Description**: Provide a descriptive title and a detailed explanation of the problem you are experiencing (for a bug report) or you are trying to solve (for an enhancement request).
|
||||
- [ ] **Reproduce**: For bug reports provide detailed information on how to reproduce the problem. For enhancement requests you do not need to provide this information, unless you find it relevant.
|
||||
- [ ] **Behaviors**: Provide information on the expected and actual behaviors.
|
||||
- [ ] **Environment**: For bug reports provide information about your OS version and build (e.g. 10.0.14393) and WinFsp version and build (e.g. 2017.2 or 1.2.17341). For enhancement requests you do not need to provide this information, unless you find it relevant.
|
21
.github/ISSUE_TEMPLATE/bug.md
vendored
Normal file
21
.github/ISSUE_TEMPLATE/bug.md
vendored
Normal file
@ -0,0 +1,21 @@
|
||||
---
|
||||
name: Bug Report
|
||||
about: File a bug report.
|
||||
---
|
||||
|
||||
## Bug Report
|
||||
|
||||
_Provide a descriptive title and a detailed explanation of the problem you are experiencing. Ensure that your issue has not been filed before._
|
||||
|
||||
### How to Reproduce
|
||||
|
||||
_Provide detailed information on how to reproduce the problem._
|
||||
|
||||
### Behaviors
|
||||
|
||||
_Provide information on the expected and actual behaviors._
|
||||
|
||||
### Environment
|
||||
|
||||
- OS version and build: _e.g. 10.0.14393_
|
||||
- WinFsp version and build: _e.g. 2017.2 or 1.2.17341_
|
8
.github/ISSUE_TEMPLATE/enhancement.md
vendored
Normal file
8
.github/ISSUE_TEMPLATE/enhancement.md
vendored
Normal file
@ -0,0 +1,8 @@
|
||||
---
|
||||
name: Enhancement Request
|
||||
about: File an enhancement request.
|
||||
---
|
||||
|
||||
## Enhancement Request
|
||||
|
||||
_Provide a descriptive title and a detailed explanation of the problem the requested enhancement would solve. Ensure that your issue has not been filed before._
|
8
.github/ISSUE_TEMPLATE/question.md
vendored
Normal file
8
.github/ISSUE_TEMPLATE/question.md
vendored
Normal file
@ -0,0 +1,8 @@
|
||||
---
|
||||
name: Question
|
||||
about: Questions are better asked in the WinFsp Google Group. However you may ask a question here.
|
||||
---
|
||||
|
||||
## Question
|
||||
|
||||
_Please consider asking questions in the [WinFsp Google Group](https://groups.google.com/forum/#!forum/winfsp) instead. Before asking a question please also consult the [WinFsp Frequently Asked Questions](https://github.com/billziss-gh/winfsp/wiki/Frequently-Asked-Questions)._
|
@ -1,6 +1,13 @@
|
||||
= Changelog
|
||||
|
||||
|
||||
v1.4B1 (2018.2 B1)::
|
||||
|
||||
Changes since v1.3:
|
||||
|
||||
* New `Control` file system operation allows sending custom control codes to the file system using the Windows `DeviceIoControl` API.
|
||||
|
||||
|
||||
v1.3 (2018.1)::
|
||||
|
||||
Changes since v1.2POST1:
|
||||
|
@ -182,6 +182,7 @@
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\..\tst\memfs\memfs.cpp" />
|
||||
<ClCompile Include="..\..\..\tst\winfsp-tests\create-test.c" />
|
||||
<ClCompile Include="..\..\..\tst\winfsp-tests\devctl-test.c" />
|
||||
<ClCompile Include="..\..\..\tst\winfsp-tests\dirbuf-test.c" />
|
||||
<ClCompile Include="..\..\..\tst\winfsp-tests\dirctl-test.c" />
|
||||
<ClCompile Include="..\..\..\tst\winfsp-tests\eventlog-test.c" />
|
||||
|
@ -88,6 +88,9 @@
|
||||
<ClCompile Include="..\..\..\tst\winfsp-tests\launch-test.c">
|
||||
<Filter>Source</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\..\tst\winfsp-tests\devctl-test.c">
|
||||
<Filter>Source</Filter>
|
||||
</ClCompile>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="..\..\..\ext\tlib\testsuite.h">
|
||||
|
@ -16,10 +16,10 @@
|
||||
<MyCompanyName>Navimatics Corporation</MyCompanyName>
|
||||
<MyCopyright>2015-$([System.DateTime]::Now.ToString(`yyyy`)) Bill Zissimopoulos</MyCopyright>
|
||||
|
||||
<MyCanonicalVersion>1.3</MyCanonicalVersion>
|
||||
<MyCanonicalVersion>1.4</MyCanonicalVersion>
|
||||
|
||||
<MyProductVersion>2018.1</MyProductVersion>
|
||||
<MyProductStage>Gold</MyProductStage>
|
||||
<MyProductVersion>2018.2 B1</MyProductVersion>
|
||||
<MyProductStage>Beta</MyProductStage>
|
||||
|
||||
<MyVersion>$(MyCanonicalVersion).$(MyBuildNumber)</MyVersion>
|
||||
<MyVersionWithCommas>$(MyVersion.Replace('.',',')),0</MyVersionWithCommas>
|
||||
|
@ -87,7 +87,7 @@ struct fuse_operations
|
||||
/* _ */ unsigned int flag_nopath:1;
|
||||
/* _ */ unsigned int flag_utime_omit_ok:1;
|
||||
/* _ */ unsigned int flag_reserved:29;
|
||||
/* _ */ int (*ioctl)(const char *path, int cmd, void *arg, struct fuse_file_info *fi,
|
||||
/* S */ int (*ioctl)(const char *path, int cmd, void *arg, struct fuse_file_info *fi,
|
||||
unsigned int flags, void *data);
|
||||
/* _ */ int (*poll)(const char *path, struct fuse_file_info *fi,
|
||||
struct fuse_pollhandle *ph, unsigned *reventsp);
|
||||
|
@ -53,6 +53,17 @@ extern "C" {
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#define FSP_FUSE_DEVICE_TYPE (0x8000 | 'W' | 'F' * 0x100) /* DeviceIoControl -> ioctl */
|
||||
#define FSP_FUSE_CTLCODE_FROM_IOCTL(cmd)\
|
||||
(FSP_FUSE_DEVICE_TYPE << 16) | (((c) & 0x0fff) << 2)
|
||||
#define FSP_FUSE_IOCTL(cmd, isiz, osiz) \
|
||||
( \
|
||||
(((osiz) != 0) << 31) | \
|
||||
(((isiz) != 0) << 30) | \
|
||||
(((isiz) | (osiz)) << 16) | \
|
||||
(cmd) \
|
||||
)
|
||||
|
||||
/*
|
||||
* FUSE uses a number of types (notably: struct stat) that are OS specific.
|
||||
* Furthermore there are sometimes multiple definitions of the same type even
|
||||
|
@ -82,6 +82,8 @@ FSP_FSCTL_STATIC_ASSERT(FSP_FSCTL_VOLUME_NAME_SIZEMAX <= 260 * sizeof(WCHAR),
|
||||
#define FSP_FSCTL_TRANSACT_REQ_TOKEN_HANDLE(T) ((HANDLE)((T) & 0xffffffff))
|
||||
#define FSP_FSCTL_TRANSACT_REQ_TOKEN_PID(T) ((UINT32)(((T) >> 32) & 0xffffffff))
|
||||
|
||||
#define FSP_FSCTL_DEVICECONTROL_SIZEMAX (4 * 1024) /* must be < FSP_FSCTL_TRANSACT_{REQ,RSP}_SIZEMAX */
|
||||
|
||||
/* marshalling */
|
||||
#pragma warning(push)
|
||||
#pragma warning(disable:4200) /* zero-sized array in struct/union */
|
||||
@ -154,11 +156,13 @@ enum
|
||||
UINT32 AlwaysUseDoubleBuffering:1;\
|
||||
UINT32 PassQueryDirectoryFileName:1; /* pass FileName during QueryDirectory (GetDirInfoByName) */\
|
||||
UINT32 FlushAndPurgeOnCleanup:1; /* keeps file off "standby" list */\
|
||||
UINT32 KmReservedFlags:1;\
|
||||
UINT32 DeviceControl:1; /* support user-mode ioctl handling */\
|
||||
/* user-mode flags */\
|
||||
UINT32 UmFileContextIsUserContext2:1; /* user mode: FileContext parameter is UserContext2 */\
|
||||
UINT32 UmFileContextIsFullContext:1; /* user mode: FileContext parameter is FullContext */\
|
||||
UINT32 UmReservedFlags:14;\
|
||||
UINT32 UmReservedFlags:6;\
|
||||
/* additional kernel-mode flags */\
|
||||
UINT32 KmReservedFlags:8;\
|
||||
WCHAR Prefix[FSP_FSCTL_VOLUME_PREFIX_SIZE / sizeof(WCHAR)]; /* UNC prefix (\Server\Share) */\
|
||||
WCHAR FileSystemName[FSP_FSCTL_VOLUME_FSNAME_SIZE / sizeof(WCHAR)];
|
||||
#define FSP_FSCTL_VOLUME_PARAMS_V1_FIELD_DEFN\
|
||||
@ -381,6 +385,14 @@ typedef struct
|
||||
UINT16 TargetOnFileSystem; /* the target of the symbolic link is on this file system */
|
||||
} FileSystemControl;
|
||||
struct
|
||||
{
|
||||
UINT64 UserContext;
|
||||
UINT64 UserContext2;
|
||||
UINT32 IoControlCode;
|
||||
FSP_FSCTL_TRANSACT_BUF Buffer;
|
||||
UINT32 OutputLength;
|
||||
} DeviceControl;
|
||||
struct
|
||||
{
|
||||
UINT64 UserContext;
|
||||
UINT64 UserContext2;
|
||||
@ -466,6 +478,10 @@ typedef struct
|
||||
FSP_FSCTL_TRANSACT_BUF Buffer;
|
||||
} FileSystemControl;
|
||||
struct
|
||||
{
|
||||
FSP_FSCTL_TRANSACT_BUF Buffer;
|
||||
} DeviceControl;
|
||||
struct
|
||||
{
|
||||
FSP_FSCTL_TRANSACT_BUF SecurityDescriptor;
|
||||
} QuerySecurity;
|
||||
|
@ -822,12 +822,41 @@ typedef struct _FSP_FILE_SYSTEM_INTERFACE
|
||||
NTSTATUS (*GetDirInfoByName)(FSP_FILE_SYSTEM *FileSystem,
|
||||
PVOID FileContext, PWSTR FileName,
|
||||
FSP_FSCTL_DIR_INFO *DirInfo);
|
||||
/**
|
||||
* Process control code.
|
||||
*
|
||||
* This function is called when a program uses the DeviceIoControl API.
|
||||
*
|
||||
* @param FileSystem
|
||||
* The file system on which this request is posted.
|
||||
* @param FileContext
|
||||
* The file context of the file or directory to be controled.
|
||||
* @param 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 InputBuffer
|
||||
* Pointer to a buffer that contains the input data.
|
||||
* @param InputBufferLength
|
||||
* Input data length.
|
||||
* @param OutputBuffer
|
||||
* Pointer to a buffer that will receive the output data.
|
||||
* @param OutputBufferLength
|
||||
* Output data length.
|
||||
* @param PBytesTransferred [out]
|
||||
* Pointer to a memory location that will receive the actual number of bytes transferred.
|
||||
* @return
|
||||
* STATUS_SUCCESS or error code.
|
||||
*/
|
||||
NTSTATUS (*Control)(FSP_FILE_SYSTEM *FileSystem,
|
||||
PVOID FileContext, UINT32 ControlCode,
|
||||
PVOID InputBuffer, ULONG InputBufferLength,
|
||||
PVOID OutputBuffer, ULONG OutputBufferLength, PULONG PBytesTransferred);
|
||||
|
||||
/*
|
||||
* This ensures that this interface will always contain 64 function pointers.
|
||||
* Please update when changing the interface as it is important for future compatibility.
|
||||
*/
|
||||
NTSTATUS (*Reserved[39])();
|
||||
NTSTATUS (*Reserved[38])();
|
||||
} FSP_FILE_SYSTEM_INTERFACE;
|
||||
FSP_FSCTL_STATIC_ASSERT(sizeof(FSP_FILE_SYSTEM_INTERFACE) == 64 * sizeof(NTSTATUS (*)()),
|
||||
"FSP_FILE_SYSTEM_INTERFACE must have 64 entries.");
|
||||
@ -1141,6 +1170,8 @@ FSP_API NTSTATUS FspFileSystemOpQueryDirectory(FSP_FILE_SYSTEM *FileSystem,
|
||||
FSP_FSCTL_TRANSACT_REQ *Request, FSP_FSCTL_TRANSACT_RSP *Response);
|
||||
FSP_API NTSTATUS FspFileSystemOpFileSystemControl(FSP_FILE_SYSTEM *FileSystem,
|
||||
FSP_FSCTL_TRANSACT_REQ *Request, FSP_FSCTL_TRANSACT_RSP *Response);
|
||||
FSP_API NTSTATUS FspFileSystemOpDeviceControl(FSP_FILE_SYSTEM *FileSystem,
|
||||
FSP_FSCTL_TRANSACT_REQ *Request, FSP_FSCTL_TRANSACT_RSP *Response);
|
||||
FSP_API NTSTATUS FspFileSystemOpQuerySecurity(FSP_FILE_SYSTEM *FileSystem,
|
||||
FSP_FSCTL_TRANSACT_REQ *Request, FSP_FSCTL_TRANSACT_RSP *Response);
|
||||
FSP_API NTSTATUS FspFileSystemOpSetSecurity(FSP_FILE_SYSTEM *FileSystem,
|
||||
|
@ -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)
|
||||
{
|
||||
|
@ -55,6 +55,11 @@ FSP_FSCTL_STATIC_ASSERT(MEMFS_MAX_PATH > MAX_PATH,
|
||||
*/
|
||||
#define MEMFS_SLOWIO
|
||||
|
||||
/*
|
||||
* Define the MEMFS_CONTROL macro to include DeviceControl support.
|
||||
*/
|
||||
#define MEMFS_CONTROL
|
||||
|
||||
/*
|
||||
* Define the DEBUG_BUFFER_CHECK macro on Windows 8 or above. This includes
|
||||
* a check for the Write buffer to ensure that it is read-only.
|
||||
@ -1870,6 +1875,38 @@ static NTSTATUS GetStreamInfo(FSP_FILE_SYSTEM *FileSystem,
|
||||
}
|
||||
#endif
|
||||
|
||||
#if defined(MEMFS_CONTROL)
|
||||
static NTSTATUS Control(FSP_FILE_SYSTEM *FileSystem,
|
||||
PVOID FileContext, UINT32 ControlCode,
|
||||
PVOID InputBuffer, ULONG InputBufferLength,
|
||||
PVOID OutputBuffer, ULONG OutputBufferLength, PULONG PBytesTransferred)
|
||||
{
|
||||
/* MEMFS also supports encryption! See below :) */
|
||||
if (CTL_CODE(0x8000 + 'M', 'R', METHOD_BUFFERED, FILE_ANY_ACCESS) == ControlCode)
|
||||
{
|
||||
if (OutputBufferLength != InputBufferLength)
|
||||
return STATUS_INVALID_PARAMETER;
|
||||
|
||||
for (PUINT8 P = (PUINT8)InputBuffer, Q = (PUINT8)OutputBuffer, EndP = P + InputBufferLength;
|
||||
EndP > P; P++, Q++)
|
||||
{
|
||||
if (('A' <= *P && *P <= 'M') || ('a' <= *P && *P <= 'm'))
|
||||
*Q = *P + 13;
|
||||
else
|
||||
if (('N' <= *P && *P <= 'Z') || ('n' <= *P && *P <= 'z'))
|
||||
*Q = *P - 13;
|
||||
else
|
||||
*Q = *P;
|
||||
}
|
||||
|
||||
*PBytesTransferred = InputBufferLength;
|
||||
return STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
return STATUS_INVALID_DEVICE_REQUEST;
|
||||
}
|
||||
#endif
|
||||
|
||||
static FSP_FILE_SYSTEM_INTERFACE MemfsInterface =
|
||||
{
|
||||
GetVolumeInfo,
|
||||
@ -1912,6 +1949,11 @@ static FSP_FILE_SYSTEM_INTERFACE MemfsInterface =
|
||||
#else
|
||||
0,
|
||||
#endif
|
||||
#if defined(MEMFS_CONTROL)
|
||||
Control,
|
||||
#else
|
||||
0,
|
||||
#endif
|
||||
};
|
||||
|
||||
/*
|
||||
@ -2003,6 +2045,9 @@ NTSTATUS MemfsCreateFunnel(
|
||||
VolumeParams.PassQueryDirectoryFileName = 1;
|
||||
#endif
|
||||
VolumeParams.FlushAndPurgeOnCleanup = FlushAndPurgeOnCleanup;
|
||||
#if defined(MEMFS_CONTROL)
|
||||
VolumeParams.DeviceControl = 1;
|
||||
#endif
|
||||
if (0 != VolumePrefix)
|
||||
wcscpy_s(VolumeParams.Prefix, sizeof VolumeParams.Prefix / sizeof(WCHAR), VolumePrefix);
|
||||
wcscpy_s(VolumeParams.FileSystemName, sizeof VolumeParams.FileSystemName / sizeof(WCHAR),
|
||||
|
74
tst/winfsp-tests/devctl-test.c
Normal file
74
tst/winfsp-tests/devctl-test.c
Normal file
@ -0,0 +1,74 @@
|
||||
/**
|
||||
* @file devctl-test.c
|
||||
*
|
||||
* @copyright 2015-2018 Bill Zissimopoulos
|
||||
*/
|
||||
/*
|
||||
* This file is part of WinFsp.
|
||||
*
|
||||
* You can redistribute it and/or modify it under the terms of the GNU
|
||||
* General Public License version 3 as published by the Free Software
|
||||
* Foundation.
|
||||
*
|
||||
* Licensees holding a valid commercial license may use this file in
|
||||
* accordance with the commercial license agreement provided with the
|
||||
* software.
|
||||
*/
|
||||
|
||||
#include <winfsp/winfsp.h>
|
||||
#include <tlib/testsuite.h>
|
||||
#include <strsafe.h>
|
||||
#include "memfs.h"
|
||||
|
||||
#include "winfsp-tests.h"
|
||||
|
||||
static void devctl_dotest(ULONG Flags, PWSTR Prefix, PWSTR Drive)
|
||||
{
|
||||
void *memfs = memfs_start(Flags);
|
||||
|
||||
WCHAR FilePath[1024];
|
||||
HANDLE Handle;
|
||||
BOOL Success;
|
||||
CHAR Buffer[26];
|
||||
DWORD BytesTransferred;
|
||||
|
||||
StringCbPrintfW(FilePath, sizeof FilePath, L"%s%s\\",
|
||||
Prefix ? L"" : L"\\\\?\\GLOBALROOT", Prefix ? Prefix : memfs_volumename(memfs));
|
||||
|
||||
Handle = CreateFileW(FilePath,
|
||||
GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE, 0, OPEN_EXISTING,
|
||||
FILE_FLAG_BACKUP_SEMANTICS, 0);
|
||||
ASSERT(INVALID_HANDLE_VALUE != Handle);
|
||||
|
||||
Success = DeviceIoControl(Handle,
|
||||
CTL_CODE(0x8000 + 'M', 'R', METHOD_BUFFERED, FILE_ANY_ACCESS),
|
||||
"ABCDEFghijklmNOPQRStuvwxyz", 26,
|
||||
Buffer, sizeof Buffer,
|
||||
&BytesTransferred,
|
||||
0);
|
||||
ASSERT(Success);
|
||||
|
||||
ASSERT(26 == BytesTransferred);
|
||||
ASSERT(0 == memcmp("NOPQRStuvwxyzABCDEFghijklm", Buffer, BytesTransferred));
|
||||
|
||||
Success = CloseHandle(Handle);
|
||||
ASSERT(Success);
|
||||
|
||||
memfs_stop(memfs);
|
||||
}
|
||||
|
||||
static void devctl_test(void)
|
||||
{
|
||||
if (WinFspDiskTests)
|
||||
devctl_dotest(MemfsDisk, 0, 0);
|
||||
if (WinFspNetTests)
|
||||
devctl_dotest(MemfsNet, L"\\\\memfs\\share", L"\\\\memfs\\share");
|
||||
}
|
||||
|
||||
void devctl_tests(void)
|
||||
{
|
||||
if (OptExternal)
|
||||
return;
|
||||
|
||||
TEST(devctl_test);
|
||||
}
|
@ -199,6 +199,7 @@ int main(int argc, char *argv[])
|
||||
TESTSUITE(lock_tests);
|
||||
TESTSUITE(dirctl_tests);
|
||||
TESTSUITE(exec_tests);
|
||||
TESTSUITE(devctl_tests);
|
||||
TESTSUITE(reparse_tests);
|
||||
TESTSUITE(stream_tests);
|
||||
TESTSUITE(oplock_tests);
|
||||
|
Reference in New Issue
Block a user