From 24b96e7e1b91312a826d2c7a0cde88b300f7464c Mon Sep 17 00:00:00 2001 From: Bill Zissimopoulos Date: Wed, 29 Aug 2018 15:45:02 -0700 Subject: [PATCH] inc, dll, dotnet: FSP_FILE_SYSTEM_INTERFACE::SetDelete --- inc/winfsp/winfsp.h | 41 +++++++++++++++++++++++- src/dll/fsop.c | 11 ++++++- src/dotnet/FileSystemBase.cs | 62 ++++++++++++++++++++++++++++++++++++ src/dotnet/FileSystemHost.cs | 23 +++++++++++++ src/dotnet/Interop.cs | 8 ++++- 5 files changed, 142 insertions(+), 3 deletions(-) diff --git a/inc/winfsp/winfsp.h b/inc/winfsp/winfsp.h index 0bbad1c2..b299086a 100644 --- a/inc/winfsp/winfsp.h +++ b/inc/winfsp/winfsp.h @@ -384,6 +384,7 @@ typedef struct _FSP_FILE_SYSTEM_INTERFACE * @see * Close * CanDelete + * SetDelete */ VOID (*Cleanup)(FSP_FILE_SYSTEM *FileSystem, PVOID FileContext, PWSTR FileName, ULONG Flags); @@ -567,6 +568,9 @@ typedef struct _FSP_FILE_SYSTEM_INTERFACE * This function gets called when Win32 API's such as DeleteFile or RemoveDirectory are used. * It does not get called when a file or directory is opened with FILE_DELETE_ON_CLOSE. * + * NOTE: If both CanDelete and SetDelete are defined, SetDelete takes precedence. However + * most file systems need only implement the CanDelete operation. + * * @param FileSystem * The file system on which this request is posted. * @param FileContext @@ -577,6 +581,7 @@ typedef struct _FSP_FILE_SYSTEM_INTERFACE * STATUS_SUCCESS or error code. * @see * Cleanup + * SetDelete */ NTSTATUS (*CanDelete)(FSP_FILE_SYSTEM *FileSystem, PVOID FileContext, PWSTR FileName); @@ -855,12 +860,46 @@ typedef struct _FSP_FILE_SYSTEM_INTERFACE PVOID FileContext, UINT32 ControlCode, PVOID InputBuffer, ULONG InputBufferLength, PVOID OutputBuffer, ULONG OutputBufferLength, PULONG PBytesTransferred); + /** + * Set the file delete flag. + * + * 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. + * + * This function should NEVER delete the file or directory in question. Deletion should + * happen during Cleanup with the FspCleanupDelete flag set. + * + * This function gets called when Win32 API's such as DeleteFile or RemoveDirectory are used. + * It does not get called when a file or directory is opened with FILE_DELETE_ON_CLOSE. + * + * NOTE: If both CanDelete and SetDelete are defined, SetDelete takes precedence. However + * most file systems need only implement the CanDelete operation. + * + * @param FileSystem + * The file system on which this request is posted. + * @param FileContext + * The file context of the file or directory to set the delete flag for. + * @param FileName + * The name of the file or directory to set the delete flag for. + * @param DeleteFile + * If set to TRUE the FSD indicates that the file will be deleted on Cleanup; otherwise + * it will not be deleted. It is legal to receive multiple SetDelete calls for the same + * file with different DeleteFile parameters. + * @return + * STATUS_SUCCESS or error code. + * @see + * Cleanup + * CanDelete + */ + NTSTATUS (*SetDelete)(FSP_FILE_SYSTEM *FileSystem, + PVOID FileContext, PWSTR FileName, BOOLEAN DeleteFile); /* * This ensures that this interface will always contain 64 function pointers. * Please update when changing the interface as it is important for future compatibility. */ - NTSTATUS (*Reserved[38])(); + NTSTATUS (*Reserved[37])(); } FSP_FILE_SYSTEM_INTERFACE; FSP_FSCTL_STATIC_ASSERT(sizeof(FSP_FILE_SYSTEM_INTERFACE) == 64 * sizeof(NTSTATUS (*)()), "FSP_FILE_SYSTEM_INTERFACE must have 64 entries."); diff --git a/src/dll/fsop.c b/src/dll/fsop.c index f07536e3..0d3c21df 100644 --- a/src/dll/fsop.c +++ b/src/dll/fsop.c @@ -1047,13 +1047,22 @@ FSP_API NTSTATUS FspFileSystemOpSetInformation(FSP_FILE_SYSTEM *FileSystem, break; } } - if (0 != FileSystem->Interface->CanDelete) + if (0 != FileSystem->Interface->SetDelete) + { + Result = FileSystem->Interface->SetDelete(FileSystem, + (PVOID)ValOfFileContext(Request->Req.SetInformation), + (PWSTR)Request->Buffer, + Request->Req.SetInformation.Info.Disposition.Delete); + } + else if (0 != FileSystem->Interface->CanDelete) + { if (Request->Req.SetInformation.Info.Disposition.Delete) Result = FileSystem->Interface->CanDelete(FileSystem, (PVOID)ValOfFileContext(Request->Req.SetInformation), (PWSTR)Request->Buffer); else Result = STATUS_SUCCESS; + } break; case 10/*FileRenameInformation*/: if (0 != FileSystem->Interface->Rename) diff --git a/src/dotnet/FileSystemBase.cs b/src/dotnet/FileSystemBase.cs index 680cf72b..c5ce8be7 100644 --- a/src/dotnet/FileSystemBase.cs +++ b/src/dotnet/FileSystemBase.cs @@ -341,6 +341,7 @@ namespace Fsp /// These flags determine whether the file was modified and whether to delete the file. /// /// + /// /// public virtual void Cleanup( Object FileNode, @@ -595,6 +596,22 @@ namespace Fsp /// /// Determines whether a file or directory can be deleted. /// + /// + /// + /// 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. + /// + /// This function should NEVER delete the file or directory in question. Deletion should + /// happen during Cleanup with the FspCleanupDelete flag set. + /// + /// This function gets called when Win32 API's such as DeleteFile or RemoveDirectory are used. + /// It does not get called when a file or directory is opened with FILE_DELETE_ON_CLOSE. + /// + /// NOTE: If both CanDelete and SetDelete are defined, SetDelete takes precedence. However + /// most file systems need only implement the CanDelete operation. + /// + /// /// /// The file node of the file or directory to test for deletion. /// @@ -606,6 +623,7 @@ namespace Fsp /// /// STATUS_SUCCESS or error code. /// + /// public virtual Int32 CanDelete( Object FileNode, Object FileDesc, @@ -1013,6 +1031,50 @@ namespace Fsp BytesTransferred = default(UInt32); return STATUS_INVALID_DEVICE_REQUEST; } + /// + /// Sets the file delete flag. + /// + /// + /// + /// 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. + /// + /// This function should NEVER delete the file or directory in question. Deletion should + /// happen during Cleanup with the FspCleanupDelete flag set. + /// + /// This function gets called when Win32 API's such as DeleteFile or RemoveDirectory are used. + /// It does not get called when a file or directory is opened with FILE_DELETE_ON_CLOSE. + /// + /// NOTE: If both CanDelete and SetDelete are defined, SetDelete takes precedence. However + /// most file systems need only implement the CanDelete operation. + /// + /// + /// + /// The file node of the file or directory to set the delete flag for. + /// + /// + /// The file descriptor of the file or directory to set the delete flag for. + /// + /// + /// The name of the file or directory to set the delete flag for. + /// + /// + /// If set to TRUE the FSD indicates that the file will be deleted on Cleanup; otherwise + /// it will not be deleted. It is legal to receive multiple SetDelete calls for the same + /// file with different DeleteFile parameters. + /// + /// STATUS_SUCCESS or error code. + /// + /// + public virtual Int32 SetDelete( + Object FileNode, + Object FileDesc, + String FileName, + Boolean DeleteFile) + { + return STATUS_INVALID_DEVICE_REQUEST; + } /* helpers */ /// diff --git a/src/dotnet/FileSystemHost.cs b/src/dotnet/FileSystemHost.cs index caa4b4f3..03d0013f 100644 --- a/src/dotnet/FileSystemHost.cs +++ b/src/dotnet/FileSystemHost.cs @@ -1065,6 +1065,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); + } + } static FileSystemHost() { @@ -1094,6 +1116,7 @@ namespace Fsp _FileSystemInterface.GetStreamInfo = GetStreamInfo; _FileSystemInterface.GetDirInfoByName = GetDirInfoByName; _FileSystemInterface.Control = Control; + _FileSystemInterface.SetDelete = SetDelete; _FileSystemInterfacePtr = Marshal.AllocHGlobal(FileSystemInterface.Size); Marshal.StructureToPtr(_FileSystemInterface, _FileSystemInterfacePtr, false); diff --git a/src/dotnet/Interop.cs b/src/dotnet/Interop.cs index e32bea0d..63523990 100644 --- a/src/dotnet/Interop.cs +++ b/src/dotnet/Interop.cs @@ -470,6 +470,11 @@ namespace Fsp.Interop IntPtr InputBuffer, UInt32 InputBufferLength, IntPtr OutputBuffer, UInt32 OutputBufferLength, out UInt32 PBytesTransferred); + internal delegate Int32 SetDelete( + IntPtr FileSystem, + ref FullContext FullContext, + [MarshalAs(UnmanagedType.LPWStr)] String FileName, + [MarshalAs(UnmanagedType.U1)] Boolean DeleteFile); } internal static int Size = IntPtr.Size * 64; @@ -500,7 +505,8 @@ namespace Fsp.Interop internal Proto.GetStreamInfo GetStreamInfo; internal Proto.GetDirInfoByName GetDirInfoByName; internal Proto.Control Control; - /* NTSTATUS (*Reserved[38])(); */ + internal Proto.SetDelete SetDelete; + /* NTSTATUS (*Reserved[37])(); */ } [SuppressUnmanagedCodeSecurity]