diff --git a/src/dll/fuse/fuse.c b/src/dll/fuse/fuse.c index b248d59d..05ad1da8 100644 --- a/src/dll/fuse/fuse.c +++ b/src/dll/fuse/fuse.c @@ -96,6 +96,7 @@ static struct fuse_opt fsp_fuse_core_opts[] = FSP_FUSE_CORE_OPT("VolumeInfoTimeout=", set_VolumeInfoTimeout, 1), FSP_FUSE_CORE_OPT("VolumeInfoTimeout=%d", VolumeParams.VolumeInfoTimeout, 0), FSP_FUSE_CORE_OPT("KeepFileCache=", set_KeepFileCache, 1), + FSP_FUSE_CORE_OPT("LegacyUnlinkRename=", set_LegacyUnlinkRename, 1), FSP_FUSE_CORE_OPT("ThreadCount=%u", ThreadCount, 0), FUSE_OPT_KEY("UNC=", 'U'), FUSE_OPT_KEY("--UNC=", 'U'), @@ -421,6 +422,7 @@ static int fsp_fuse_core_opt_proc(void *opt_data0, const char *arg, int key, " -o EaTimeout=N extended attribute timeout (millis)\n" " -o VolumeInfoTimeout=N volume info timeout (millis)\n" " -o KeepFileCache do not discard cache when files are closed\n" + " -o LegacyUnlinkRename do not support new POSIX unlink/rename\n" " -o ThreadCount number of file system dispatcher threads\n" ); opt_data->help = 1; @@ -563,6 +565,7 @@ FSP_FUSE_API struct fuse *fsp_fuse_new(struct fsp_fuse_env *env, opt_data.VolumeParams.Version = sizeof(FSP_FSCTL_VOLUME_PARAMS); opt_data.VolumeParams.FileInfoTimeout = 1000; opt_data.VolumeParams.FlushAndPurgeOnCleanup = TRUE; + opt_data.VolumeParams.SupportsPosixUnlinkRename = TRUE; if (-1 == fsp_fuse_core_opt_parse(env, args, &opt_data, /*help=*/1)) { @@ -623,6 +626,8 @@ FSP_FUSE_API struct fuse *fsp_fuse_new(struct fsp_fuse_env *env, opt_data.VolumeParams.VolumeInfoTimeoutValid = 1; if (opt_data.set_KeepFileCache) opt_data.VolumeParams.FlushAndPurgeOnCleanup = FALSE; + if (opt_data.set_LegacyUnlinkRename) + opt_data.VolumeParams.SupportsPosixUnlinkRename = FALSE; opt_data.VolumeParams.CaseSensitiveSearch = TRUE; opt_data.VolumeParams.CasePreservedNames = TRUE; opt_data.VolumeParams.PersistentAcls = TRUE; diff --git a/src/dll/fuse/fuse_intf.c b/src/dll/fuse/fuse_intf.c index 8ada5f2c..69635f2d 100644 --- a/src/dll/fuse/fuse_intf.c +++ b/src/dll/fuse/fuse_intf.c @@ -34,7 +34,10 @@ VOID fsp_fuse_op_enter_lock(FSP_FILE_SYSTEM *FileSystem, (FspFsctlTransactCleanupKind == Request->Kind && Request->Req.Cleanup.Delete) || (FspFsctlTransactSetInformationKind == Request->Kind && - 10/*FileRenameInformation*/ == Request->Req.SetInformation.FileInformationClass) || + (10/*FileRenameInformation*/ == Request->Req.SetInformation.FileInformationClass || + 65/*FileRenameInformationEx*/ == Request->Req.SetInformation.FileInformationClass || + (64/*FileDispositionInformationEx*/ == Request->Req.SetInformation.FileInformationClass && + 3/*DELETE|POSIX_SEMANTICS*/ == (3 & Request->Req.SetInformation.Info.DispositionEx.Flags)))) || FspFsctlTransactSetVolumeInformationKind == Request->Kind || (FspFsctlTransactFlushBuffersKind == Request->Kind && 0 == Request->Req.FlushBuffers.UserContext && @@ -48,7 +51,9 @@ VOID fsp_fuse_op_enter_lock(FSP_FILE_SYSTEM *FileSystem, else if (FspFsctlTransactCreateKind == Request->Kind || (FspFsctlTransactSetInformationKind == Request->Kind && - 13/*FileDispositionInformation*/ == Request->Req.SetInformation.FileInformationClass) || + (13/*FileDispositionInformation*/ == Request->Req.SetInformation.FileInformationClass || + (64/*FileDispositionInformationEx*/ == Request->Req.SetInformation.FileInformationClass && + 3/*DELETE|POSIX_SEMANTICS*/ != (3 & Request->Req.SetInformation.Info.DispositionEx.Flags)))) || FspFsctlTransactQueryDirectoryKind == Request->Kind || FspFsctlTransactQueryVolumeInformationKind == Request->Kind || /* FSCTL_GET_REPARSE_POINT may access namespace */ @@ -78,7 +83,10 @@ VOID fsp_fuse_op_leave_unlock(FSP_FILE_SYSTEM *FileSystem, (FspFsctlTransactCleanupKind == Request->Kind && Request->Req.Cleanup.Delete) || (FspFsctlTransactSetInformationKind == Request->Kind && - 10/*FileRenameInformation*/ == Request->Req.SetInformation.FileInformationClass) || + (10/*FileRenameInformation*/ == Request->Req.SetInformation.FileInformationClass || + 65/*FileRenameInformationEx*/ == Request->Req.SetInformation.FileInformationClass || + (64/*FileDispositionInformationEx*/ == Request->Req.SetInformation.FileInformationClass && + 3/*DELETE|POSIX_SEMANTICS*/ == (3 & Request->Req.SetInformation.Info.DispositionEx.Flags)))) || FspFsctlTransactSetVolumeInformationKind == Request->Kind || (FspFsctlTransactFlushBuffersKind == Request->Kind && 0 == Request->Req.FlushBuffers.UserContext && @@ -92,7 +100,9 @@ VOID fsp_fuse_op_leave_unlock(FSP_FILE_SYSTEM *FileSystem, else if (FspFsctlTransactCreateKind == Request->Kind || (FspFsctlTransactSetInformationKind == Request->Kind && - 13/*FileDispositionInformation*/ == Request->Req.SetInformation.FileInformationClass) || + (13/*FileDispositionInformation*/ == Request->Req.SetInformation.FileInformationClass || + (64/*FileDispositionInformationEx*/ == Request->Req.SetInformation.FileInformationClass && + 3/*DELETE|POSIX_SEMANTICS*/ != (3 & Request->Req.SetInformation.Info.DispositionEx.Flags)))) || FspFsctlTransactQueryDirectoryKind == Request->Kind || FspFsctlTransactQueryVolumeInformationKind == Request->Kind || /* FSCTL_GET_REPARSE_POINT may access namespace */ @@ -1157,42 +1167,6 @@ static NTSTATUS fsp_fuse_intf_Overwrite(FSP_FILE_SYSTEM *FileSystem, &Uid, &Gid, &Mode, FileInfo); } -static VOID fsp_fuse_intf_Cleanup(FSP_FILE_SYSTEM *FileSystem, - PVOID FileDesc, PWSTR FileName, ULONG Flags) -{ - struct fuse *f = FileSystem->UserContext; - struct fsp_fuse_file_desc *filedesc = FileDesc; - - /* - * In Windows a DeleteFile/RemoveDirectory is the sequence of the following: - * Create(FILE_OPEN) - * SetInformation(Disposition) - * Cleanup - * Close - * - * The FSD maintains a count of how many handles are currently open for a file. When the - * last handle is closed *and* the disposition flag is set the FSD sends us a Cleanup with - * the Delete flag set. - * - * Notice that when we receive a Cleanup with Delete set there can be no open handles other - * than ours. [Even if there is a concurrent Open of this file, the FSD will fail it with - * STATUS_DELETE_PENDING.] This means that we do not need to worry about the hard_remove - * FUSE option and can safely remove the file at this time. - */ - - if (Flags & FspCleanupDelete) - if (filedesc->IsDirectory && !filedesc->IsReparsePoint) - { - if (0 != f->ops.rmdir) - f->ops.rmdir(filedesc->PosixPath); - } - else - { - if (0 != f->ops.unlink) - f->ops.unlink(filedesc->PosixPath); - } -} - static VOID fsp_fuse_intf_Close(FSP_FILE_SYSTEM *FileSystem, PVOID FileDesc) { @@ -1605,6 +1579,54 @@ static NTSTATUS fsp_fuse_intf_CanDelete(FSP_FILE_SYSTEM *FileSystem, return STATUS_SUCCESS; } +static NTSTATUS fsp_fuse_intf_Delete(FSP_FILE_SYSTEM *FileSystem, + PVOID FileDesc, PWSTR FileName, ULONG Flags) +{ + switch (Flags) + { + case FILE_DISPOSITION_DO_NOT_DELETE: + return STATUS_SUCCESS; + + case FILE_DISPOSITION_DELETE: + return fsp_fuse_intf_CanDelete(FileSystem, FileDesc, FileName); + + case FILE_DISPOSITION_DELETE | FILE_DISPOSITION_POSIX_SEMANTICS: + case -1: + { + struct fuse *f = FileSystem->UserContext; + struct fsp_fuse_file_desc *filedesc = FileDesc; + int err; + NTSTATUS Result = STATUS_SUCCESS; + + if (filedesc->IsDirectory && !filedesc->IsReparsePoint) + { + if (0 != f->ops.rmdir) + { + err = f->ops.rmdir(filedesc->PosixPath); + Result = fsp_fuse_ntstatus_from_errno(f->env, err); + } + else + Result = STATUS_INVALID_DEVICE_REQUEST; + } + else + { + if (0 != f->ops.unlink) + { + err = f->ops.unlink(filedesc->PosixPath); + Result = fsp_fuse_ntstatus_from_errno(f->env, err); + } + else + Result = STATUS_INVALID_DEVICE_REQUEST; + } + + return Result; + } + + default: + return STATUS_INVALID_PARAMETER; + } +} + static NTSTATUS fsp_fuse_intf_Rename(FSP_FILE_SYSTEM *FileSystem, PVOID FileDesc, PWSTR FileName, PWSTR NewFileName, BOOLEAN ReplaceIfExists) @@ -2424,7 +2446,7 @@ FSP_FILE_SYSTEM_INTERFACE fsp_fuse_intf = 0, fsp_fuse_intf_Open, 0, - fsp_fuse_intf_Cleanup, + 0, fsp_fuse_intf_Close, fsp_fuse_intf_Read, fsp_fuse_intf_Write, @@ -2432,7 +2454,7 @@ FSP_FILE_SYSTEM_INTERFACE fsp_fuse_intf = fsp_fuse_intf_GetFileInfo, fsp_fuse_intf_SetBasicInfo, fsp_fuse_intf_SetFileSize, - fsp_fuse_intf_CanDelete, + 0, fsp_fuse_intf_Rename, fsp_fuse_intf_GetSecurity, fsp_fuse_intf_SetSecurity, @@ -2449,6 +2471,7 @@ FSP_FILE_SYSTEM_INTERFACE fsp_fuse_intf = fsp_fuse_intf_Overwrite, fsp_fuse_intf_GetEa, fsp_fuse_intf_SetEa, + fsp_fuse_intf_Delete, }; /* diff --git a/src/dll/fuse/library.h b/src/dll/fuse/library.h index 87edc129..aec9a642 100644 --- a/src/dll/fuse/library.h +++ b/src/dll/fuse/library.h @@ -153,7 +153,8 @@ struct fsp_fuse_core_opt_data set_DirInfoTimeout, set_EaTimeout, set_VolumeInfoTimeout, - set_KeepFileCache; + set_KeepFileCache, + set_LegacyUnlinkRename; unsigned ThreadCount; FSP_FSCTL_VOLUME_PARAMS VolumeParams; UINT16 VolumeLabelLength;