winfsp / winfsp

Windows File System Proxy - FUSE for Windows
https://winfsp.dev
Other
6.93k stars 496 forks source link

FUSE: Allow mounting in existing (empty) folders #320

Open JaniruTEC opened 4 years ago

JaniruTEC commented 4 years ago

FUSE on MacOS and Linux require the user to mount a filesystem in an existing, empty folder. FUSE over WinFSP requires the folder to not exist and therefore "breaches" the contract defined by the original FUSE implementation(s). Aligning this to the Linux/MacOS implementations therefore seems desirable.

Maybe adding a WinFSP-specific Mountflag to toggle this behavior would be the best solution for this problem.

billziss-gh commented 4 years ago

Please see the rationale at the FAQ of why this was done like this:

https://github.com/billziss-gh/winfsp/wiki/Frequently-Asked-Questions#fuse

JaniruTEC commented 4 years ago

Thanks for the info! From my point of view this approach is definitely understandable and should stay the default. But as I suggested adding an alternative-mode (via a flag, let's call it "FUSE-Mode-Flag") doesn't seem to be covered by that. The main argument for following the "fuse"-road is that applications that use FUSE expect the provider to behave like FUSE. This is not the case at the moment, but should be possible, IMO. Instead WinFSP behaves more like a Windows-Application. If you view WinFSP as FUSE-Application these decisions appear in a different light:

Symmetry with mounting on a drive. On Windows drives are created when the file system comes into existence and deleted when it is gone. On Linux the same is the case for classic mounts (sda, sdb, etc.), but when using FUSE this is overruled in favor of using existing folders. The same reasoning could be applied for Windows.

Inability to mount over a non-empty directory on Windows. On FUSE/UNIX this is possible, but not on Windows because NTFS disallows the creation of (mountpoint) reparse points on non-empty directories. Most applications disallow mounting on non-empty directories, even if FUSE allows it in theory. Also smaller differences between those two seem more desirable than the current big difference in design. So this doesn't seem like a problem to me.

Most importantly: inability to guarantee that the mount point will cease to exist if the file system crashes. WinFsp attempts to guarantee that all resources used by a file system will get cleaned up. This is certainly true for the kernel-mode FSD, but an attempt is made to do so also in user mode. For this reason, drive symbolic links are marked as temporary and (importantly for our discussion) mount directories are opened with FILE_FLAG_DELETE_ON_CLOSE. There is no way to guarantee the removal of a reparse point in the same way. What's the worst case scenario if a reparse point is not deleted? IMO if an application decides to use the "FUSE-Mode-Flag" handling the deletion of a "lost folder" seems resonable.

In conclusion: If you can spare the time, please consider making a "FUSE-Mode(-Flag)" possible.

billziss-gh commented 4 years ago

Understood.

One point to consider is that if we do this via an option flag, this would be a de-facto incompatibility with FUSE on UNIX (although admittedly a smaller incompatibility). It might be better to relax the rules for FUSE only (not the native WinFsp API) to allow mounting even if the directory exists. The issue of removing the reparse point remains; ideally we could eventually resolve this with help from the kernel mode FSD, which of course survives a process crash.

I am marking this as enhancement, although I cannot promise if/when I will get to it. (Right now I am focused on getting FUSE for WSL1 to work and I am really REALLY close.)

Perhaps you might consider looking into some of the required changes yourself? Admittedly this is not the easiest change to make for someone who does not understand WinFsp quite well, although I would provide full support and guidance, including any necessary kernel mode changes if we decide to introduce those (for guaranteed removal of the reparse point in case of a process crash).

The thing to do might be to use a bit from the Reserved field in FSP_MOUNT_DESC and then populate that bit when mounting from FUSE. For example:

typedef struct
{
    /* in */
    HANDLE VolumeHandle;                /* volume handle returned by FspFsctlCreateVolume */
    PWSTR VolumeName;                   /* volume name returned by FspFsctlCreateVolume */
    PSECURITY_DESCRIPTOR Security;      /* optional: security descriptor for directories */
    UINT64 AllowMountOnExistingDirectory:1;
    UINT64 Reserved:63;                 /* reserved for future use */
    /* in/out */
    PWSTR MountPoint;                   /* FspMountSet sets drive in buffer when passed "*:" */
    HANDLE MountHandle;                 /* FspMountSet sets, FspMountRemove uses */
} FSP_MOUNT_DESC;

The places to change are:

JaniruTEC commented 4 years ago

Hey! Thanks for the detailed answer and sorry for not getting back at you. Long, detailed answers require time to read as well. 😆 I appreciate that you take the time to deal with this and add this as enhancement.

One point to consider is that if we do this via an option flag, this would be a de-facto incompatibility with FUSE on UNIX (although admittedly a smaller incompatibility).

Aren't there already a few flags, that are specific to FUSE over WinFSP?

It might be better to relax the rules for FUSE only (not the native WinFsp API) to allow mounting even if the directory exists.

I don't see a reason to do that. If you were to implement this, the native WinFSP API could profit from it as well. I would expect this to introduce more overhead than implementing it in both APIs?

The issue of removing the reparse point remains; ideally we could eventually resolve this with help from the kernel mode FSD, which of course survives a process crash.

As I already suggested I would delegate this to the user for the time being. I'm sadly not familiar with anything kernel-related, so I have to take your word on this.

Perhaps you might consider looking into some of the required changes yourself?

I'm considering this and proposed it on the last Cryptomator-Team-Call; I hope to get an answer to the request by next weekend.

Admittedly this is not the easiest change to make for someone who does not understand WinFsp quite well, although I would provide full support and guidance, including any necessary kernel mode changes if we decide to introduce those (for guaranteed removal of the reparse point in case of a process crash).

I'm not a C developer, but understand a fair bit and should be able to implement it with your help. Thanks for the offer. 😀

Also thank you for the directions in terms of possible implementation!