diff --git a/inc/winfsp/fsctl.h b/inc/winfsp/fsctl.h index cdda8831..cec14557 100644 --- a/inc/winfsp/fsctl.h +++ b/inc/winfsp/fsctl.h @@ -222,7 +222,8 @@ enum UINT32 DirectoryMarkerAsNextOffset:1; /* directory marker is next offset instead of last name */\ UINT32 RejectIrpPriorToTransact0:1; /* reject IRP's prior to FspFsctlTransact with 0 buffers */\ UINT32 SupportsPosixUnlinkRename:1; /* file system supports POSIX-style unlink and rename */\ - UINT32 KmReservedFlags:2;\ + UINT32 PostDispositionForDirOnly:1; /* post SetInformation/Disposition for dirs only */\ + UINT32 KmReservedFlags:1;\ 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\ diff --git a/src/sys/fileinfo.c b/src/sys/fileinfo.c index 7bea7e6b..88a18fd0 100644 --- a/src/sys/fileinfo.c +++ b/src/sys/fileinfo.c @@ -1435,12 +1435,30 @@ static NTSTATUS FspFsvolSetPositionInformation(PFILE_OBJECT FileObject, return STATUS_SUCCESS; } +static inline FspFsvolSetDispositionInformationFlags( + PFILE_OBJECT FileObject, + FSP_FILE_NODE *FileNode, + FSP_FILE_DESC *FileDesc, + UINT32 DispositionFlags) +{ + BOOLEAN Delete = BooleanFlagOn(DispositionFlags, FILE_DISPOSITION_DELETE); + + FspFileNodeSetDeletePending(FileNode, Delete); + FileObject->DeletePending = Delete; + + if (!Delete) + FileDesc->PosixDelete = FALSE; + else if (FlagOn(DispositionFlags, FILE_DISPOSITION_POSIX_SEMANTICS)) + FileDesc->PosixDelete = TRUE; +} + static NTSTATUS FspFsvolSetDispositionInformation( PDEVICE_OBJECT FsvolDeviceObject, PIRP Irp, PIO_STACK_LOCATION IrpSp) { PAGED_CODE(); NTSTATUS Result; + FSP_FSVOL_DEVICE_EXTENSION *FsvolDeviceExtension = FspFsvolDeviceExtension(FsvolDeviceObject); PFILE_OBJECT FileObject = IrpSp->FileObject; FILE_INFORMATION_CLASS FileInformationClass = IrpSp->Parameters.SetFile.FileInformationClass; UINT32 DispositionFlags; @@ -1465,7 +1483,7 @@ static NTSTATUS FspFsvolSetDispositionInformation( } else { - if (!FspFsvolDeviceExtension(FsvolDeviceObject)->VolumeParams.SupportsPosixUnlinkRename) + if (!FsvolDeviceExtension->VolumeParams.SupportsPosixUnlinkRename) return STATUS_INVALID_PARAMETER; if (sizeof(FILE_DISPOSITION_INFORMATION_EX) > Length) return STATUS_INVALID_PARAMETER; @@ -1589,6 +1607,29 @@ retry: } FileDesc->DispositionStatus = STATUS_SUCCESS; + if (!FileNode->IsDirectory && FsvolDeviceExtension->VolumeParams.PostDispositionForDirOnly) + { + if (FILE_DISPOSITION_DELETE == + (DispositionFlags & (FILE_DISPOSITION_DELETE | FILE_DISPOSITION_IGNORE_READONLY_ATTRIBUTE))) + { + FSP_FSCTL_FILE_INFO FileInfoBuf; + if (!FspFileNodeTryGetFileInfo(FileNode, &FileInfoBuf)) + goto slow; + + if (0 != (FileInfoBuf.FileAttributes & FILE_ATTRIBUTE_READONLY)) + { + Result = STATUS_CANNOT_DELETE; + goto unlock_exit; + } + } + + FspFsvolSetDispositionInformationFlags(FileObject, FileNode, FileDesc, DispositionFlags); + + Result = STATUS_SUCCESS; + goto unlock_exit; + } +slow:; + Result = FspIopCreateRequestEx(Irp, &FileNode->FileName, 0, FspFsvolSetInformationRequestFini, &Request); if (!NT_SUCCESS(Result)) @@ -1622,19 +1663,12 @@ static NTSTATUS FspFsvolSetDispositionInformationSuccess( FSP_FILE_DESC *FileDesc = FileObject->FsContext2; FSP_FSCTL_TRANSACT_REQ *Request = FspIrpRequest(Irp); UINT32 DispositionFlags = Request->Req.SetInformation.Info.DispositionEx.Flags; - BOOLEAN Delete = BooleanFlagOn(DispositionFlags, FILE_DISPOSITION_DELETE); - FspFileNodeSetDeletePending(FileNode, Delete); - FileObject->DeletePending = Delete; - - if (!Delete) - FileDesc->PosixDelete = FALSE; - else if (FlagOn(DispositionFlags, FILE_DISPOSITION_POSIX_SEMANTICS)) - FileDesc->PosixDelete = TRUE; + FspFsvolSetDispositionInformationFlags(FileObject, FileNode, FileDesc, DispositionFlags); /* fastfat does this, although it seems unnecessary */ #if 1 - if (FileNode->IsDirectory && Delete) + if (FileNode->IsDirectory && FlagOn(DispositionFlags, FILE_DISPOSITION_DELETE)) { FSP_FSVOL_DEVICE_EXTENSION *FsvolDeviceExtension = FspFsvolDeviceExtension(IrpSp->DeviceObject); diff --git a/tst/memfs/memfs.cpp b/tst/memfs/memfs.cpp index 1f645827..f1be24bb 100644 --- a/tst/memfs/memfs.cpp +++ b/tst/memfs/memfs.cpp @@ -2404,6 +2404,7 @@ NTSTATUS MemfsCreateFunnel( VolumeParams.RejectIrpPriorToTransact0 = 1; #endif VolumeParams.SupportsPosixUnlinkRename = SupportsPosixUnlinkRename; + VolumeParams.PostDispositionForDirOnly = 1; if (0 != VolumePrefix) wcscpy_s(VolumeParams.Prefix, sizeof VolumeParams.Prefix / sizeof(WCHAR), VolumePrefix); wcscpy_s(VolumeParams.FileSystemName, sizeof VolumeParams.FileSystemName / sizeof(WCHAR), diff --git a/tst/ntptfs/ptfs.c b/tst/ntptfs/ptfs.c index 37556e61..93ef7a36 100644 --- a/tst/ntptfs/ptfs.c +++ b/tst/ntptfs/ptfs.c @@ -1279,6 +1279,7 @@ NTSTATUS PtfsCreate( /*FILE_SUPPORTS_POSIX_UNLINK_RENAME*/); VolumeParams.ReadOnlyVolume = !!(FsAttrInfo.V.FileSystemAttributes & FILE_READ_ONLY_VOLUME); VolumeParams.PostCleanupWhenModifiedOnly = 1; + VolumeParams.PostDispositionForDirOnly = 1; VolumeParams.PassQueryDirectoryPattern = 1; VolumeParams.FlushAndPurgeOnCleanup = !!(FsAttributeMask & PtfsFlushAndPurgeOnCleanup); VolumeParams.WslFeatures = !!(FsAttributeMask & PtfsWslFeatures);