From 826a514fe39b2e4caf18259780a921adbb855412 Mon Sep 17 00:00:00 2001 From: Bill Zissimopoulos Date: Mon, 22 Nov 2021 13:55:32 +0000 Subject: [PATCH] dll: dotnet: revert the Delete redesign --- src/dll/fsop.c | 13 +---- src/dotnet/FileSystemBase+Const.cs | 8 --- src/dotnet/FileSystemBase.cs | 89 ------------------------------ src/dotnet/FileSystemHost.cs | 46 +++++++-------- src/dotnet/Interop.cs | 10 +--- tst/memfs-dotnet/Program.cs | 65 +++++++++------------- 6 files changed, 54 insertions(+), 177 deletions(-) diff --git a/src/dll/fsop.c b/src/dll/fsop.c index 0c6eba37..97d90334 100644 --- a/src/dll/fsop.c +++ b/src/dll/fsop.c @@ -1001,20 +1001,11 @@ FSP_API NTSTATUS FspFileSystemOpCleanup(FSP_FILE_SYSTEM *FileSystem, if (Request->Req.Cleanup.Delete && 0 != FileSystem->Interface->Delete) { - NTSTATUS Result = FileSystem->Interface->Delete(FileSystem, + FileSystem->Interface->Delete(FileSystem, (PVOID)ValOfFileContext(Request->Req.Cleanup), 0 != Request->FileName.Size ? (PWSTR)Request->Buffer : 0, (ULONG)-1); - /* - * If Delete returns STATUS_NOT_IMPLEMENTED it means that it is unable - * to handle file deletion during the Cleanup phase. In this case we - * will handle file deletion in Cleanup with the FspCleanupDelete flag. - * - * This is necessary for file systems like the .NET layer where Delete - * may be implemented but unable to handle all file deletion cases. - */ - if (STATUS_NOT_IMPLEMENTED != Result) - CleanupFlags &= ~FspCleanupDelete; + CleanupFlags &= ~FspCleanupDelete; } if (0 != FileSystem->Interface->Cleanup) diff --git a/src/dotnet/FileSystemBase+Const.cs b/src/dotnet/FileSystemBase+Const.cs index 5211f4e9..3674e040 100644 --- a/src/dotnet/FileSystemBase+Const.cs +++ b/src/dotnet/FileSystemBase+Const.cs @@ -57,14 +57,6 @@ namespace Fsp public const UInt32 CleanupSetLastWriteTime = 0x40; public const UInt32 CleanupSetChangeTime = 0x80; - /* Disposition */ - public const UInt32 FILE_DISPOSITION_DO_NOT_DELETE = 0x00000000; - public const UInt32 FILE_DISPOSITION_DELETE = 0x00000001; - public const UInt32 FILE_DISPOSITION_POSIX_SEMANTICS = 0x00000002; - public const UInt32 FILE_DISPOSITION_FORCE_IMAGE_SECTION_CHECK = 0x00000004; - public const UInt32 FILE_DISPOSITION_ON_CLOSE = 0x00000008; - public const UInt32 FILE_DISPOSITION_IGNORE_READONLY_ATTRIBUTE = 0x00000010; - /* NTSTATUS */ public const Int32 STATUS_SUCCESS = unchecked((Int32)0x00000000); public const Int32 STATUS_WAIT_1 = unchecked((Int32)0x00000001); diff --git a/src/dotnet/FileSystemBase.cs b/src/dotnet/FileSystemBase.cs index 140934ed..e40e3eb8 100644 --- a/src/dotnet/FileSystemBase.cs +++ b/src/dotnet/FileSystemBase.cs @@ -289,9 +289,6 @@ namespace Fsp /// /// /// - /// (NOTE: use of this function with the CleanupDelete flag is not recommended; - /// use Delete instead.) - /// /// When CreateFile is used to open or create a file the kernel creates a kernel mode file /// object (type FILE_OBJECT) and a handle for it, which it returns to user-mode. The handle may /// be duplicated (using DuplicateHandle), but all duplicate handles always refer to the same @@ -345,7 +342,6 @@ namespace Fsp /// /// /// - /// /// public virtual void Cleanup( Object FileNode, @@ -602,8 +598,6 @@ namespace Fsp /// /// /// - /// (NOTE: use of this function is not recommended; use Delete instead.) - /// /// This function tests whether a file or directory can be safely deleted. This function does /// not need to perform access checks, but may performs tasks such as check for empty /// directories, etc. @@ -630,7 +624,6 @@ namespace Fsp /// STATUS_SUCCESS or error code. /// /// - /// public virtual Int32 CanDelete( Object FileNode, Object FileDesc, @@ -1043,8 +1036,6 @@ namespace Fsp /// /// /// - /// (NOTE: use of this function is not recommended; use Delete instead.) - /// /// This function sets a flag to indicates whether the FSD file should delete a file /// when it is closed. This function does not need to perform access checks, but may /// performs tasks such as check for empty directories, etc. @@ -1076,7 +1067,6 @@ namespace Fsp /// STATUS_SUCCESS or error code. /// /// - /// public virtual Int32 SetDelete( Object FileNode, Object FileDesc, @@ -1198,85 +1188,6 @@ namespace Fsp { return STATUS_INVALID_DEVICE_REQUEST; } - /// - /// Sets the file delete flag or deletes a file or directory. - /// - /// - /// - /// This function replaces CanDelete, SetDelete and uses of Cleanup with the CleanupDelete flag - /// and is recommended for use in all new code. - /// - /// Due to the complexity of file deletion in the Windows file system this function is used - /// in many scenarios. Its usage is controlled by the Flags parameter: - /// - /// FILE_DISPOSITION_DO_NOT_DELETE: Unmark the file for deletion. - /// Do NOT delete the file either now or at Cleanup time. - /// FILE_DISPOSITION_DELETE: Mark the file for deletion, - /// but do NOT delete the file. The file will be deleted at Cleanup time - /// (via a call to Delete with Flags = -1). - /// This function does not need to perform access checks, but may - /// performs tasks such as check for empty directories, etc. - /// FILE_DISPOSITION_DELETE | FILE_DISPOSITION_POSIX_SEMANTICS: Delete the file - /// NOW using POSIX semantics. Open user mode handles to the file remain valid. - /// This case will be received only when SupportsPosixUnlinkRename is set. - /// -1: Delete the file NOW using regular Windows semantics. - /// Called during Cleanup with no open user mode handles remaining. - /// If a file system implements Delete, Cleanup should NOT be used for deletion anymore. - /// - /// - /// This function gets called in all file deletion scenarios: - /// - /// When the DeleteFile or RemoveDirectory API's are used. - /// When the SetInformationByHandle API with FileDispositionInfo or FileDispositionInfoEx is used. - /// When a file is opened using FILE_DELETE_ON_CLOSE. - /// Etc. - /// - /// - /// NOTE: Delete takes precedence over CanDelete, SetDelete and Cleanup with the CleanupDelete flag. - /// This means that if Delete is defined, CanDelete and SetDelete will never be called and - /// Cleanup will never be called with the CleanupDelete flag. - /// - /// - /// - /// The file node of the file or directory. - /// - /// - /// The file descriptor of the file or directory. - /// - /// - /// The name of the file or directory. - /// - /// - /// File disposition flags. - /// - /// STATUS_SUCCESS or error code. - /// - /// - /// - public virtual Int32 Delete( - Object FileNode, - Object FileDesc, - String FileName, - UInt32 Flags) - { - switch (Flags) - { - case FILE_DISPOSITION_DO_NOT_DELETE: - return SetDelete(FileNode, FileDesc, FileName, false); - - case FILE_DISPOSITION_DELETE: - return SetDelete(FileNode, FileDesc, FileName, true); - - case FILE_DISPOSITION_DELETE | FILE_DISPOSITION_POSIX_SEMANTICS: - return STATUS_INVALID_PARAMETER; - - case ~(UInt32)0: - return STATUS_NOT_IMPLEMENTED; - - default: - return STATUS_INVALID_PARAMETER; - } - } /* helpers */ /// diff --git a/src/dotnet/FileSystemHost.cs b/src/dotnet/FileSystemHost.cs index 5866faa9..0dd68e96 100644 --- a/src/dotnet/FileSystemHost.cs +++ b/src/dotnet/FileSystemHost.cs @@ -1348,6 +1348,28 @@ namespace Fsp return ExceptionHandler(FileSystem, ex); } } + private static Int32 SetDelete( + IntPtr FileSystemPtr, + ref FullContext FullContext, + String FileName, + Boolean DeleteFile) + { + FileSystemBase FileSystem = (FileSystemBase)Api.GetUserContext(FileSystemPtr); + try + { + Object FileNode, FileDesc; + Api.GetFullContext(ref FullContext, out FileNode, out FileDesc); + return FileSystem.SetDelete( + FileNode, + FileDesc, + FileName, + DeleteFile); + } + catch (Exception ex) + { + return ExceptionHandler(FileSystem, ex); + } + } private static Int32 GetEa( IntPtr FileSystemPtr, ref FullContext FullContext, @@ -1398,28 +1420,6 @@ namespace Fsp return ExceptionHandler(FileSystem, ex); } } - private static Int32 Delete( - IntPtr FileSystemPtr, - ref FullContext FullContext, - String FileName, - UInt32 Flags) - { - FileSystemBase FileSystem = (FileSystemBase)Api.GetUserContext(FileSystemPtr); - try - { - Object FileNode, FileDesc; - Api.GetFullContext(ref FullContext, out FileNode, out FileDesc); - return FileSystem.Delete( - FileNode, - FileDesc, - FileName, - Flags); - } - catch (Exception ex) - { - return ExceptionHandler(FileSystem, ex); - } - } static FileSystemHost() { @@ -1448,9 +1448,9 @@ namespace Fsp _FileSystemInterface.GetStreamInfo = GetStreamInfo; _FileSystemInterface.GetDirInfoByName = GetDirInfoByName; _FileSystemInterface.Control = Control; + _FileSystemInterface.SetDelete = SetDelete; _FileSystemInterface.GetEa = GetEa; _FileSystemInterface.SetEa = SetEa; - _FileSystemInterface.Delete = Delete; _FileSystemInterfacePtr = Marshal.AllocHGlobal(FileSystemInterface.Size); /* Marshal.AllocHGlobal does not zero memory; we must do it ourselves! */ diff --git a/src/dotnet/Interop.cs b/src/dotnet/Interop.cs index afaecbf6..797d5b6a 100644 --- a/src/dotnet/Interop.cs +++ b/src/dotnet/Interop.cs @@ -743,11 +743,7 @@ namespace Fsp.Interop UInt32 EaLength, out FileInfo FileInfo); [UnmanagedFunctionPointer(CallingConvention.Cdecl)] - internal delegate Int32 Delete( - IntPtr FileSystem, - ref FullContext FullContext, - [MarshalAs(UnmanagedType.LPWStr)] String FileName, - UInt32 Flags); + internal delegate Int32 Obsolete0(); } internal static int Size = IntPtr.Size * 64; @@ -783,8 +779,8 @@ namespace Fsp.Interop internal Proto.OverwriteEx OverwriteEx; internal Proto.GetEa GetEa; internal Proto.SetEa SetEa; - internal Proto.Delete Delete; - /* NTSTATUS (*Reserved[32])(); */ + internal Proto.Obsolete0 Obsolete0; + /* NTSTATUS (*Reserved[33])(); */ } [SuppressUnmanagedCodeSecurity] diff --git a/tst/memfs-dotnet/Program.cs b/tst/memfs-dotnet/Program.cs index 97492ba9..fd61e385 100644 --- a/tst/memfs-dotnet/Program.cs +++ b/tst/memfs-dotnet/Program.cs @@ -564,6 +564,19 @@ namespace memfs AllocationUnit * AllocationUnit; SetFileSizeInternal(FileNode, AllocationSize, true); } + + if (0 != (Flags & CleanupDelete) && !FileNodeMap.HasChild(FileNode)) + { + List StreamFileNames = new List(FileNodeMap.GetStreamFileNames(FileNode)); + foreach (String StreamFileName in StreamFileNames) + { + FileNode StreamNode = FileNodeMap.Get(StreamFileName); + if (null == StreamNode) + continue; /* should not happen */ + FileNodeMap.Remove(StreamNode); + } + FileNodeMap.Remove(FileNode); + } } public override void Close( @@ -908,6 +921,19 @@ namespace memfs return STATUS_SUCCESS; } + public override Int32 CanDelete( + Object FileNode0, + Object FileDesc, + String FileName) + { + FileNode FileNode = (FileNode)FileNode0; + + if (FileNodeMap.HasChild(FileNode)) + return STATUS_DIRECTORY_NOT_EMPTY; + + return STATUS_SUCCESS; + } + public override Int32 Rename( Object FileNode0, Object FileDesc, @@ -1305,45 +1331,6 @@ namespace memfs FileNode.FileInfo.EaSize = FileNode.FileInfo.EaSize + EaSizePlus - EaSizeMinus; return STATUS_SUCCESS; } - public override Int32 Delete( - Object FileNode0, - Object FileDesc, - String FileName, - UInt32 Flags) - { - FileNode FileNode = (FileNode)FileNode0; - - switch (Flags) - { - case FILE_DISPOSITION_DO_NOT_DELETE: - return STATUS_SUCCESS; - - case FILE_DISPOSITION_DELETE: - if (FileNodeMap.HasChild(FileNode)) - return STATUS_DIRECTORY_NOT_EMPTY; - return STATUS_SUCCESS; - - case FILE_DISPOSITION_DELETE | FILE_DISPOSITION_POSIX_SEMANTICS: - case ~(UInt32)0: - if (FileNodeMap.HasChild(FileNode)) - return STATUS_DIRECTORY_NOT_EMPTY; - - List StreamFileNames = new List(FileNodeMap.GetStreamFileNames(FileNode)); - foreach (String StreamFileName in StreamFileNames) - { - FileNode StreamNode = FileNodeMap.Get(StreamFileName); - if (null == StreamNode) - continue; /* should not happen */ - FileNodeMap.Remove(StreamNode); - } - - FileNodeMap.Remove(FileNode); - return STATUS_SUCCESS; - - default: - return STATUS_INVALID_PARAMETER; - } - } private FileNodeMap FileNodeMap; private UInt32 MaxFileNodes;