mirror of
https://github.com/winfsp/winfsp.git
synced 2025-04-22 08:23:05 -05:00
sys,dll: mount improvements
- sys: FspFsvolFileSystemControl: FSCTL_IS_VOLUME_MOUNTED - dll: mount: Transact0, FspMountNotifyShellDriveChange
This commit is contained in:
parent
c04e3d9534
commit
db319bc3c1
@ -21,6 +21,7 @@
|
|||||||
|
|
||||||
#include <dll/library.h>
|
#include <dll/library.h>
|
||||||
#include <dbt.h>
|
#include <dbt.h>
|
||||||
|
#include <shlobj.h>
|
||||||
|
|
||||||
static INIT_ONCE FspMountInitOnce = INIT_ONCE_STATIC_INIT;
|
static INIT_ONCE FspMountInitOnce = INIT_ONCE_STATIC_INIT;
|
||||||
static NTSTATUS (NTAPI *FspNtOpenSymbolicLinkObject)(
|
static NTSTATUS (NTAPI *FspNtOpenSymbolicLinkObject)(
|
||||||
@ -350,6 +351,19 @@ exit:
|
|||||||
return Result;
|
return Result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static VOID FspMountNotifyShellDriveChange(VOID)
|
||||||
|
{
|
||||||
|
HRESULT HResult;
|
||||||
|
LPITEMIDLIST Pidl;
|
||||||
|
|
||||||
|
HResult = SHGetKnownFolderIDList(&FOLDERID_ComputerFolder, KF_FLAG_DEFAULT, 0, &Pidl);
|
||||||
|
if (SUCCEEDED(HResult))
|
||||||
|
{
|
||||||
|
SHChangeNotify(SHCNE_UPDATEDIR, SHCNF_IDLIST, Pidl, 0);
|
||||||
|
CoTaskMemFree(Pidl);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static NTSTATUS FspMountSet_Drive(PWSTR VolumeName, PWSTR MountPoint, PHANDLE PMountHandle)
|
static NTSTATUS FspMountSet_Drive(PWSTR VolumeName, PWSTR MountPoint, PHANDLE PMountHandle)
|
||||||
{
|
{
|
||||||
NTSTATUS Result;
|
NTSTATUS Result;
|
||||||
@ -568,7 +582,7 @@ static NTSTATUS FspMountRemove_Directory(HANDLE MountHandle)
|
|||||||
return CloseHandle(MountHandle) ? STATUS_SUCCESS : FspNtStatusFromWin32(GetLastError());
|
return CloseHandle(MountHandle) ? STATUS_SUCCESS : FspNtStatusFromWin32(GetLastError());
|
||||||
}
|
}
|
||||||
|
|
||||||
FSP_API NTSTATUS FspMountSet(FSP_MOUNT_DESC *Desc)
|
NTSTATUS FspMountSet_Internal(FSP_MOUNT_DESC *Desc)
|
||||||
{
|
{
|
||||||
InitOnceExecuteOnce(&FspMountInitOnce, FspMountInitialize, 0, 0);
|
InitOnceExecuteOnce(&FspMountInitOnce, FspMountInitialize, 0, 0);
|
||||||
|
|
||||||
@ -609,7 +623,7 @@ FSP_API NTSTATUS FspMountSet(FSP_MOUNT_DESC *Desc)
|
|||||||
&Desc->MountHandle);
|
&Desc->MountHandle);
|
||||||
}
|
}
|
||||||
|
|
||||||
FSP_API NTSTATUS FspMountRemove(FSP_MOUNT_DESC *Desc)
|
NTSTATUS FspMountRemove_Internal(FSP_MOUNT_DESC *Desc)
|
||||||
{
|
{
|
||||||
InitOnceExecuteOnce(&FspMountInitOnce, FspMountInitialize, 0, 0);
|
InitOnceExecuteOnce(&FspMountInitOnce, FspMountInitialize, 0, 0);
|
||||||
|
|
||||||
@ -623,3 +637,81 @@ FSP_API NTSTATUS FspMountRemove(FSP_MOUNT_DESC *Desc)
|
|||||||
else
|
else
|
||||||
return FspMountRemove_Directory(Desc->MountHandle);
|
return FspMountRemove_Directory(Desc->MountHandle);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
FSP_API NTSTATUS FspMountSet(FSP_MOUNT_DESC *Desc)
|
||||||
|
{
|
||||||
|
NTSTATUS Result;
|
||||||
|
BOOLEAN IsDrive;
|
||||||
|
|
||||||
|
IsDrive =
|
||||||
|
(L'*' == Desc->MountPoint[0] && ':' == Desc->MountPoint[1] && L'\0' == Desc->MountPoint[2]) ||
|
||||||
|
FspPathIsMountmgrDrive(Desc->MountPoint) ||
|
||||||
|
FspPathIsDrive(Desc->MountPoint);
|
||||||
|
|
||||||
|
#if defined(FSP_CFG_REJECT_EARLY_IRP)
|
||||||
|
/*
|
||||||
|
* In the original WinFsp design the FSD could accept incoming file system requests
|
||||||
|
* immediately after the in-kernel file system instance was created. Such requests would
|
||||||
|
* be queued in the internal FSD queues and only delivered to the user mode file system
|
||||||
|
* when its dispatcher was started and actively receiving them.
|
||||||
|
*
|
||||||
|
* At the same time the original WinFsp API design was that a user mode file system first
|
||||||
|
* calls FspFileSystemSetMountPoint to create the file system mount point and then calls
|
||||||
|
* FspFileSystemStartDispatcher to start the dispatcher. This design made sense at the time:
|
||||||
|
* creating a mount point involved the creation of a symbolic link of one kind or another,
|
||||||
|
* which could fail for a number of reasons (e.g. drive already exists), so there was no
|
||||||
|
* point to start the dispatcher if the mounting did not succeed. Compatibility with FUSE
|
||||||
|
* and the Unix mounting protocol was another consideration.
|
||||||
|
*
|
||||||
|
* Unfortunately this API design has proved problematic. The problem is that with the
|
||||||
|
* proliferation of ways to mount a file system in WinFsp more and more system components and
|
||||||
|
* third party filters may attempt to access the mount point upon its creation and before the
|
||||||
|
* file system dispatcher is ready. This can result in various consequences.
|
||||||
|
*
|
||||||
|
* In order to properly fix this problem we should probably mandate that a user mode file
|
||||||
|
* system should start its dispatcher first and then create its mountpoint. This way the user
|
||||||
|
* mode file system would be ready to handle any requests from system components or third
|
||||||
|
* party filters during mount point creation. Unfortunately we cannot easily do so because
|
||||||
|
* of backwards compatibility.
|
||||||
|
*
|
||||||
|
* This problem first appeared as an incompatibility with Avast AntiVirus (GitHub issue #221).
|
||||||
|
* In order to avoid backwards incompatible API changes the "Transact0" work around was
|
||||||
|
* devised: when the FSD first creates an in-kernel file system it remains inoperative and any
|
||||||
|
* requests posted to it will fail with STATUS_CANCELLED, until it receives a Transact0
|
||||||
|
* message (an FSP_FSCTL_TRANSACT message with 0 buffers). In order to enable this work around
|
||||||
|
* a user mode file system would specify the RejectIrpPriorToTransact0 flag upon creation.
|
||||||
|
*
|
||||||
|
* Another instance of this problem appeared when support for directory mounting via the Mount
|
||||||
|
* Manager was added: mounting would not complete unless the RejectIrpPriorToTransact0 flag
|
||||||
|
* was set. At this point the RejectIrpPriorToTransact0 was hard coded to 1 in the FSD.
|
||||||
|
*
|
||||||
|
* However if we are creating a drive the Transact0 work around is unnecessary and perhaps
|
||||||
|
* harmful. So in this case send a Transact0 message to the FSD to allow file system requests
|
||||||
|
* to be queued rather than rejected with STATUS_CANCELLED.
|
||||||
|
*/
|
||||||
|
if (IsDrive)
|
||||||
|
FspFsctlTransact(Desc->VolumeHandle, 0, 0, 0, 0, FALSE);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
Result = FspMountSet_Internal(Desc);
|
||||||
|
|
||||||
|
return Result;
|
||||||
|
}
|
||||||
|
|
||||||
|
FSP_API NTSTATUS FspMountRemove(FSP_MOUNT_DESC *Desc)
|
||||||
|
{
|
||||||
|
NTSTATUS Result;
|
||||||
|
BOOLEAN IsDrive;
|
||||||
|
|
||||||
|
IsDrive =
|
||||||
|
FspPathIsMountmgrDrive(Desc->MountPoint) ||
|
||||||
|
FspPathIsDrive(Desc->MountPoint);
|
||||||
|
|
||||||
|
Result = FspMountRemove_Internal(Desc);
|
||||||
|
|
||||||
|
if (NT_SUCCESS(Result) && IsDrive)
|
||||||
|
/* send an extra notification to remove the "ghost" drive in the shell's navigation pane */
|
||||||
|
FspMountNotifyShellDriveChange();
|
||||||
|
|
||||||
|
return Result;
|
||||||
|
}
|
||||||
|
@ -731,6 +731,7 @@ static NTSTATUS FspFsvolFileSystemControl(
|
|||||||
Result = FspVolumeWork(FsvolDeviceObject, Irp, IrpSp);
|
Result = FspVolumeWork(FsvolDeviceObject, Irp, IrpSp);
|
||||||
break;
|
break;
|
||||||
case FSP_FSCTL_QUERY_WINFSP:
|
case FSP_FSCTL_QUERY_WINFSP:
|
||||||
|
case FSCTL_IS_VOLUME_MOUNTED:
|
||||||
Irp->IoStatus.Information = 0;
|
Irp->IoStatus.Information = 0;
|
||||||
Result = STATUS_SUCCESS;
|
Result = STATUS_SUCCESS;
|
||||||
break;
|
break;
|
||||||
|
Loading…
x
Reference in New Issue
Block a user