/*
* dotnet/FileSystemBase.cs
*
* Copyright 2015-2021 Bill Zissimopoulos
*/
/*
* This file is part of WinFsp.
*
* You can redistribute it and/or modify it under the terms of the GNU
* General Public License version 3 as published by the Free Software
* Foundation.
*
* Licensees holding a valid commercial license may use this software
* in accordance with the commercial license agreement provided in
* conjunction with the software. The terms and conditions of any such
* commercial license agreement shall govern, supersede, and render
* ineffective any application of the GPLv3 license to this software,
* notwithstanding of any reference thereto in the software or
* associated repository.
*/
using System;
using System.Runtime.InteropServices;
using System.Security.AccessControl;
using Fsp.Interop;
namespace Fsp
{
///
/// Provides the base class that user mode file systems must inherit from.
///
public partial class FileSystemBase
{
/* types */
public class DirectoryBuffer : IDisposable
{
~DirectoryBuffer()
{
Dispose(false);
}
public void Dispose()
{
lock (this)
Dispose(true);
GC.SuppressFinalize(true);
}
protected virtual void Dispose(bool disposing)
{
Api.FspFileSystemDeleteDirectoryBuffer(ref DirBuffer);
}
internal IntPtr DirBuffer;
}
/* operations */
///
/// Provides a means to customize the returned status code when an exception happens.
///
///
/// STATUS_SUCCESS or error code.
public virtual Int32 ExceptionHandler(Exception ex)
{
Api.FspDebugLog("%s\n", ex.ToString());
return STATUS_UNEXPECTED_IO_ERROR;
}
///
/// Occurs just before the file system is mounted.
/// File systems may override this method to configure the file system host.
///
///
/// The file system host that is mounting this file system.
///
/// STATUS_SUCCESS or error code.
public virtual Int32 Init(Object Host)
{
return STATUS_SUCCESS;
}
///
/// Occurs just after the file system is mounted,
/// but prior to receiving any file system operation.
///
///
/// The file system host that is mounting this file system.
///
/// STATUS_SUCCESS or error code.
public virtual Int32 Mounted(Object Host)
{
return STATUS_SUCCESS;
}
///
/// Occurs just after the file system is unmounted.
/// No other file system operations will be received on this file system.
///
///
/// The file system host that is mounting this file system.
///
public virtual void Unmounted(Object Host)
{
}
///
/// Gets the volume information.
///
///
/// Receives the volume information.
///
/// STATUS_SUCCESS or error code.
public virtual Int32 GetVolumeInfo(
out VolumeInfo VolumeInfo)
{
VolumeInfo = default(VolumeInfo);
return STATUS_INVALID_DEVICE_REQUEST;
}
///
/// Sets the volume label.
///
///
/// The new label for the volume.
///
///
/// Receives the updated volume information.
///
/// STATUS_SUCCESS or error code.
public virtual Int32 SetVolumeLabel(
String VolumeLabel,
out VolumeInfo VolumeInfo)
{
VolumeInfo = default(VolumeInfo);
return STATUS_INVALID_DEVICE_REQUEST;
}
///
/// Gets file or directory attributes and security descriptor given a file name.
///
///
/// The name of the file or directory to get the attributes and security descriptor for.
///
///
/// Receives the file attributes on successful return.
/// If this call returns STATUS_REPARSE, the file system may place here the index of the
/// first reparse point within FileName.
///
///
/// Receives the file security descriptor. If the SecurityDescriptor parameter is null
/// on input the file system should not fill this value.
///
///
/// STATUS_SUCCESS, STATUS_REPARSE or error code.
/// STATUS_REPARSE should be returned by file systems that support reparse points when
/// they encounter a FileName that contains reparse points anywhere but the final path
/// component.
///
public virtual Int32 GetSecurityByName(
String FileName,
out UInt32 FileAttributes/* or ReparsePointIndex */,
ref Byte[] SecurityDescriptor)
{
FileAttributes = default(UInt32);
return STATUS_INVALID_DEVICE_REQUEST;
}
///
/// Creates a new file or directory.
///
///
/// The name of the file or directory to be created.
///
///
/// Create options for this request.
///
///
/// Determines the specific access rights that have been granted for this request.
///
///
/// File attributes to apply to the newly created file or directory.
///
///
/// Security descriptor to apply to the newly created file or directory.
///
///
/// Allocation size for the newly created file.
///
///
/// Receives the file node for the newly created file.
///
///
/// Receives the file descriptor for the newly created file.
///
///
/// Receives the file information for the newly created file.
///
///
/// Receives the normalized name for the newly created file.
///
/// STATUS_SUCCESS or error code.
public virtual Int32 Create(
String FileName,
UInt32 CreateOptions,
UInt32 GrantedAccess,
UInt32 FileAttributes,
Byte[] SecurityDescriptor,
UInt64 AllocationSize,
out Object FileNode,
out Object FileDesc,
out FileInfo FileInfo,
out String NormalizedName)
{
FileNode = default(Object);
FileDesc = default(Object);
FileInfo = default(FileInfo);
NormalizedName = default(String);
return STATUS_INVALID_DEVICE_REQUEST;
}
///
/// Opens a file or directory.
///
///
/// The name of the file or directory to be opened.
///
///
/// Create options for this request.
///
///
/// Determines the specific access rights that have been granted for this request.
///
///
/// Receives the file node for the newly opened file.
///
///
/// Receives the file descriptor for the newly opened file.
///
///
/// Receives the file information for the newly opened file.
///
///
/// Receives the normalized name for the newly opened file.
///
/// STATUS_SUCCESS or error code.
public virtual Int32 Open(
String FileName,
UInt32 CreateOptions,
UInt32 GrantedAccess,
out Object FileNode,
out Object FileDesc,
out FileInfo FileInfo,
out String NormalizedName)
{
FileNode = default(Object);
FileDesc = default(Object);
FileInfo = default(FileInfo);
NormalizedName = default(String);
return STATUS_INVALID_DEVICE_REQUEST;
}
///
/// Overwrites a file.
///
///
/// The file node for the file to be overwritten.
///
///
/// The file descriptor for the file to be overwritten.
///
///
/// File attributes to apply to the overwritten file.
///
///
/// When true the existing file attributes should be replaced with the new ones.
/// When false the existing file attributes should be merged (or'ed) with the new ones.
///
///
/// Allocation size for the overwritten file.
///
///
/// Receives the updated file information.
///
/// STATUS_SUCCESS or error code.
public virtual Int32 Overwrite(
Object FileNode,
Object FileDesc,
UInt32 FileAttributes,
Boolean ReplaceFileAttributes,
UInt64 AllocationSize,
out FileInfo FileInfo)
{
FileInfo = default(FileInfo);
return STATUS_INVALID_DEVICE_REQUEST;
}
///
/// Cleans up a file or directory.
///
///
///
/// 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
/// file object. When all handles for a particular file object get closed (using CloseHandle)
/// the system sends a Cleanup request to the file system.
///
/// There will be a Cleanup operation for every Create or Open operation posted to the user mode
/// file system. However the Cleanup operation is not the final close operation on a file.
/// The file system must be ready to receive additional operations until close time. This is true
/// even when the file is being deleted!
///
/// The Flags parameter contains information about the cleanup operation:
///
/// - CleanupDelete -
/// An important function of the Cleanup operation is to complete a delete operation. Deleting
/// a file or directory in Windows is a three-stage process where the file is first opened, then
/// tested to see if the delete can proceed and if the answer is positive the file is then
/// deleted during Cleanup.
/// When this flag is set, this is the last outstanding cleanup for this particular file node.
///
/// - CleanupSetAllocationSize -
/// The NTFS and FAT file systems reset a file's allocation size when they receive the last
/// outstanding cleanup for a particular file node. User mode file systems that implement
/// allocation size and wish to duplicate the NTFS and FAT behavior can use this flag.
///
/// - CleanupSetArchiveBit -
/// File systems that support the archive bit should set the file node's archive bit when this
/// flag is set.
///
/// - CleanupSetLastAccessTime, CleanupSetLastWriteTime, CleanupSetChangeTime -
/// File systems should set the corresponding file time when each one of these flags is set.
/// Note that updating the last access time is expensive and a file system may choose to not
/// implement it.
///
///
///
/// There is no way to report failure of this operation. This is a Windows limitation.
///
///
///
/// The file node of the file or directory to cleanup.
///
///
/// The file descriptor of the file or directory to cleanup.
///
///
/// The name of the file or directory to cleanup. Sent only when a Delete is requested.
///
///
/// These flags determine whether the file was modified and whether to delete the file.
///
///
///
///
public virtual void Cleanup(
Object FileNode,
Object FileDesc,
String FileName,
UInt32 Flags)
{
}
///
/// Closes a file or directory.
///
///
/// The file node of the file or directory to close.
///
///
/// The file descriptor of the file or directory to close.
///
public virtual void Close(
Object FileNode,
Object FileDesc)
{
}
///
/// Reads a file.
///
///
/// The file node of the file to read.
///
///
/// The file descriptor of the file to read.
///
///
/// Pointer to a buffer that receives the results of the read operation.
///
///
/// Offset within the file to read from.
///
///
/// Length of data to read.
///
///
/// Receives the actual number of bytes read.
///
/// STATUS_SUCCESS or error code.
public virtual Int32 Read(
Object FileNode,
Object FileDesc,
IntPtr Buffer,
UInt64 Offset,
UInt32 Length,
out UInt32 BytesTransferred)
{
BytesTransferred = default(UInt32);
return STATUS_INVALID_DEVICE_REQUEST;
}
///
/// Writes a file.
///
///
/// The file node of the file to write.
///
///
/// The file descriptor of the file to write.
///
///
/// Pointer to a buffer that receives the results of the write operation.
///
///
/// Offset within the file to write to.
///
///
/// Length of data to write.
///
///
/// When true the file system must write to the current end of file. In this case the Offset
/// parameter will contain the value -1.
///
///
/// When true the file system must not extend the file (i.e. change the file size).
///
///
/// Receives the actual number of bytes written.
///
///
/// Receives the updated file information.
///
/// STATUS_SUCCESS or error code.
public virtual Int32 Write(
Object FileNode,
Object FileDesc,
IntPtr Buffer,
UInt64 Offset,
UInt32 Length,
Boolean WriteToEndOfFile,
Boolean ConstrainedIo,
out UInt32 BytesTransferred,
out FileInfo FileInfo)
{
BytesTransferred = default(UInt32);
FileInfo = default(FileInfo);
return STATUS_INVALID_DEVICE_REQUEST;
}
///
/// Flushes a file or volume.
///
///
/// Note that the FSD will also flush all file/volume caches prior to invoking this operation.
///
///
/// The file node of the file to flush.
/// When this and the FileDesc parameter are null the whole volume is being flushed.
///
///
/// The file descriptor of the file to flush.
/// When this and the FileNode parameter are null the whole volume is being flushed.
///
///
/// Receives the updated file information.
///
/// STATUS_SUCCESS or error code.
public virtual Int32 Flush(
Object FileNode,
Object FileDesc,
out FileInfo FileInfo)
{
FileInfo = default(FileInfo);
return STATUS_INVALID_DEVICE_REQUEST;
}
///
/// Gets file or directory information.
///
///
/// The file node of the file to get information for.
///
///
/// The file descriptor of the file to get information for.
///
///
/// Receives the file information.
///
/// STATUS_SUCCESS or error code.
public virtual Int32 GetFileInfo(
Object FileNode,
Object FileDesc,
out FileInfo FileInfo)
{
FileInfo = default(FileInfo);
return STATUS_INVALID_DEVICE_REQUEST;
}
///
/// Sets file or directory basic information.
///
///
/// The file node of the file to set information for.
///
///
/// The file descriptor of the file to set information for.
///
///
/// File attributes to apply to the file or directory.
/// If the value -1 is sent, the file attributes should not be changed.
///
///
/// Creation time to apply to the file or directory.
/// If the value 0 is sent, the creation time should not be changed.
///
///
/// Last access time to apply to the file or directory.
/// If the value 0 is sent, the last access time should not be changed.
///
///
/// Last write time to apply to the file or directory.
/// If the value 0 is sent, the last write time should not be changed.
///
///
/// Change time to apply to the file or directory.
/// If the value 0 is sent, the change time should not be changed.
///
///
/// Receives the updated file information.
///
/// STATUS_SUCCESS or error code.
public virtual Int32 SetBasicInfo(
Object FileNode,
Object FileDesc,
UInt32 FileAttributes,
UInt64 CreationTime,
UInt64 LastAccessTime,
UInt64 LastWriteTime,
UInt64 ChangeTime,
out FileInfo FileInfo)
{
FileInfo = default(FileInfo);
return STATUS_INVALID_DEVICE_REQUEST;
}
///
/// Sets file/allocation size.
///
///
///
/// This function is used to change a file's sizes. Windows file systems maintain two kinds
/// of sizes: the file size is where the End Of File (EOF) is, and the allocation size is the
/// actual size that a file takes up on the "disk".
///
/// The rules regarding file/allocation size are:
///
/// -
/// Allocation size must always be aligned to the allocation unit boundary. The allocation
/// unit is the product SectorSize * SectorsPerAllocationUnit. The FSD will always send
/// properly aligned allocation sizes when setting the allocation size.
///
/// -
/// Allocation size is always greater or equal to the file size.
///
/// -
/// A file size of more than the current allocation size will also extend the allocation
/// size to the next allocation unit boundary.
///
/// -
/// An allocation size of less than the current file size should also truncate the current
/// file size.
///
///
///
///
///
/// The file node of the file to set the file/allocation size for.
///
///
/// The file descriptor of the file to set the file/allocation size for.
///
///
/// New file/allocation size to apply to the file.
///
///
/// If true, then the allocation size is being set. if false, then the file size is being set.
///
///
/// Receives the updated file information.
///
/// STATUS_SUCCESS or error code.
public virtual Int32 SetFileSize(
Object FileNode,
Object FileDesc,
UInt64 NewSize,
Boolean SetAllocationSize,
out FileInfo FileInfo)
{
FileInfo = default(FileInfo);
return STATUS_INVALID_DEVICE_REQUEST;
}
///
/// 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.
///
///
/// The file descriptor of the file or directory to test for deletion.
///
///
/// The name of the file or directory to test for deletion.
///
/// STATUS_SUCCESS or error code.
///
///
public virtual Int32 CanDelete(
Object FileNode,
Object FileDesc,
String FileName)
{
return STATUS_INVALID_DEVICE_REQUEST;
}
///
/// Renames a file or directory.
///
///
/// The kernel mode FSD provides certain guarantees prior to posting a rename operation:
///
/// -
/// A file cannot be renamed if a file with the same name exists and has open handles.
///
/// -
/// A directory cannot be renamed if it or any of its subdirectories contains a file that
/// has open handles.
///
///
///
///
/// The file node of the file or directory to be renamed.
///
///
/// The file descriptor of the file or directory to be renamed.
///
///
/// The current name of the file or directory to rename.
///
///
/// The new name for the file or directory.
///
///
/// Whether to replace a file that already exists at NewFileName.
///
/// STATUS_SUCCESS or error code.
public virtual Int32 Rename(
Object FileNode,
Object FileDesc,
String FileName,
String NewFileName,
Boolean ReplaceIfExists)
{
return STATUS_INVALID_DEVICE_REQUEST;
}
///
/// Gets file or directory security descriptor.
///
///
/// The file node of the file or directory to get the security descriptor for.
///
///
/// The file descriptor of the file or directory to get the security descriptor for.
///
///
/// Receives the file security descriptor.
///
/// STATUS_SUCCESS or error code.
public virtual Int32 GetSecurity(
Object FileNode,
Object FileDesc,
ref Byte[] SecurityDescriptor)
{
return STATUS_INVALID_DEVICE_REQUEST;
}
///
/// Sets file or directory security descriptor.
///
///
/// The file node of the file or directory to set the security descriptor for.
///
///
/// The file descriptor of the file or directory to set the security descriptor for.
///
///
/// Describes what parts of the file or directory security descriptor should be modified.
///
///
/// Describes the modifications to apply to the file or directory security descriptor.
///
/// STATUS_SUCCESS or error code.
///
public virtual Int32 SetSecurity(
Object FileNode,
Object FileDesc,
AccessControlSections Sections,
Byte[] SecurityDescriptor)
{
return STATUS_INVALID_DEVICE_REQUEST;
}
///
/// Reads a directory.
///
///
public virtual Int32 ReadDirectory(
Object FileNode,
Object FileDesc,
String Pattern,
String Marker,
IntPtr Buffer,
UInt32 Length,
out UInt32 BytesTransferred)
{
return SeekableReadDirectory(FileNode, FileDesc, Pattern, Marker, Buffer, Length,
out BytesTransferred);
}
///
/// Reads a directory entry.
///
///
/// The file node of the directory to be read.
///
///
/// The file descriptor of the directory to be read.
///
///
/// The pattern to match against files in this directory. Can be null. The file system
/// can choose to ignore this parameter as the FSD will always perform its own pattern
/// matching on the returned results.
///
///
/// A file name that marks where in the directory to start reading. Files with names
/// that are greater than (not equal to) this marker (in the directory order determined
/// by the file system) should be returned. Can be null.
///
///
/// Can be used by the file system to track the ReadDirectory operation.
///
///
/// Receives the file name for the directory entry.
///
///
/// Receives the file information for the directory entry.
///
/// True if there are additional directory entries to return. False otherwise.
///
public virtual Boolean ReadDirectoryEntry(
Object FileNode,
Object FileDesc,
String Pattern,
String Marker,
ref Object Context,
out String FileName,
out FileInfo FileInfo)
{
FileName = default(String);
FileInfo = default(FileInfo);
return false;
}
///
/// Resolves reparse points.
///
public virtual Int32 ResolveReparsePoints(
String FileName,
UInt32 ReparsePointIndex,
Boolean ResolveLastPathComponent,
out IoStatusBlock IoStatus,
IntPtr Buffer,
IntPtr PSize)
{
GCHandle Handle = GCHandle.Alloc(this, GCHandleType.Normal);
try
{
return Api.FspFileSystemResolveReparsePoints(
IntPtr.Zero,
GetReparsePointByName,
(IntPtr)Handle,
FileName,
ReparsePointIndex,
ResolveLastPathComponent,
out IoStatus,
Buffer,
PSize);
}
finally
{
Handle.Free();
}
}
///
/// Gets a reparse point given a file name.
///
///
/// The name of the file or directory to get the reparse point for.
///
///
/// Determines whether the passed file name is assumed to be a directory.
///
///
/// Receives the reparse data for the file or directory.
///
/// STATUS_SUCCESS or error code.
public virtual Int32 GetReparsePointByName(
String FileName,
Boolean IsDirectory,
ref Byte[] ReparseData)
{
return STATUS_INVALID_DEVICE_REQUEST;
}
///
/// Gets a reparse point.
///
///
/// The file node of the reparse point.
///
///
/// The file descriptor of the reparse point.
///
///
/// The file name of the reparse point.
///
///
/// Receives the reparse data for the reparse point.
///
/// STATUS_SUCCESS or error code.
public virtual Int32 GetReparsePoint(
Object FileNode,
Object FileDesc,
String FileName,
ref Byte[] ReparseData)
{
return STATUS_INVALID_DEVICE_REQUEST;
}
///
/// Sets a reparse point.
///
///
/// The file node of the reparse point.
///
///
/// The file descriptor of the reparse point.
///
///
/// The file name of the reparse point.
///
///
/// The new reparse data for the reparse point.
///
/// STATUS_SUCCESS or error code.
public virtual Int32 SetReparsePoint(
Object FileNode,
Object FileDesc,
String FileName,
Byte[] ReparseData)
{
return STATUS_INVALID_DEVICE_REQUEST;
}
///
/// Deletes a reparse point.
///
///
/// The file node of the reparse point.
///
///
/// The file descriptor of the reparse point.
///
///
/// The file name of the reparse point.
///
///
/// The reparse data for the reparse point.
///
/// STATUS_SUCCESS or error code.
public virtual Int32 DeleteReparsePoint(
Object FileNode,
Object FileDesc,
String FileName,
Byte[] ReparseData)
{
return STATUS_INVALID_DEVICE_REQUEST;
}
///
/// Gets named streams information.
///
public virtual Int32 GetStreamInfo(
Object FileNode,
Object FileDesc,
IntPtr Buffer,
UInt32 Length,
out UInt32 BytesTransferred)
{
Object Context = null;
String StreamName;
StreamInfo StreamInfo = default(StreamInfo);
BytesTransferred = default(UInt32);
while (GetStreamEntry(FileNode, FileDesc, ref Context,
out StreamName, out StreamInfo.StreamSize, out StreamInfo.StreamAllocationSize))
{
StreamInfo.SetStreamNameBuf(StreamName);
if (!Api.FspFileSystemAddStreamInfo(ref StreamInfo, Buffer, Length,
out BytesTransferred))
return STATUS_SUCCESS;
}
Api.FspFileSystemEndStreamInfo(Buffer, Length, out BytesTransferred);
return STATUS_SUCCESS;
}
///
/// Gets named streams information entry.
///
///
/// The file node of the file or directory to get stream information for.
///
///
/// The file descriptor of the file or directory to get stream information for.
///
///
/// Can be used by the file system to track the GetStreamInfo operation.
///
///
/// Receives the stream name for the stream entry.
///
///
/// Receives the stream size for the stream entry.
///
///
/// Receives the stream allocation size for the stream entry.
///
/// True if there are additional stream entries to return. False otherwise.
public virtual Boolean GetStreamEntry(
Object FileNode,
Object FileDesc,
ref Object Context,
out String StreamName,
out UInt64 StreamSize,
out UInt64 StreamAllocationSize)
{
StreamName = default(String);
StreamSize = default(UInt64);
StreamAllocationSize = default(UInt64);
return false;
}
///
/// Gets directory information for a single file or directory within a parent directory.
///
///
/// The file node of the parent directory.
///
///
/// The file descriptor of the parent directory.
///
///
/// The name of the file or directory to get information for. This name is relative
/// to the parent directory and is a single path component.
///
///
/// Receives the normalized name from the directory entry.
///
///
/// Receives the file information.
///
/// STATUS_SUCCESS or error code.
public virtual Int32 GetDirInfoByName(
Object FileNode,
Object FileDesc,
String FileName,
out String NormalizedName,
out FileInfo FileInfo)
{
NormalizedName = default(String);
FileInfo = default(FileInfo);
return STATUS_INVALID_DEVICE_REQUEST;
}
///
/// Processes a control code.
///
///
/// This function is called when a program uses the DeviceIoControl API.
///
///
/// The file node of the file or directory to be controled.
///
///
/// The file descriptor of the file or directory to be controled.
///
///
/// The control code for the operation. This code must have a DeviceType with bit
/// 0x8000 set and must have a TransferType of METHOD_BUFFERED.
///
///
/// Pointer to a buffer that contains the input data.
///
///
/// Input data length.
///
///
/// Pointer to a buffer that will receive the output data.
///
///
/// Output data length.
///
///
/// Receives the actual number of bytes transferred.
///
/// STATUS_SUCCESS or error code.
public virtual Int32 Control(
Object FileNode,
Object FileDesc,
UInt32 ControlCode,
IntPtr InputBuffer, UInt32 InputBufferLength,
IntPtr OutputBuffer, UInt32 OutputBufferLength,
out UInt32 BytesTransferred)
{
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)
{
if (DeleteFile)
return CanDelete(FileNode, FileDesc, FileName);
else
return STATUS_SUCCESS;
}
public virtual Int32 CreateEx(
String FileName,
UInt32 CreateOptions,
UInt32 GrantedAccess,
UInt32 FileAttributes,
Byte[] SecurityDescriptor,
UInt64 AllocationSize,
IntPtr ExtraBuffer,
UInt32 ExtraLength,
Boolean ExtraBufferIsReparsePoint,
out Object FileNode,
out Object FileDesc,
out FileInfo FileInfo,
out String NormalizedName)
{
return Create(
FileName,
CreateOptions,
GrantedAccess,
FileAttributes,
SecurityDescriptor,
AllocationSize,
out FileNode,
out FileDesc,
out FileInfo,
out NormalizedName);
}
public virtual Int32 OverwriteEx(
Object FileNode,
Object FileDesc,
UInt32 FileAttributes,
Boolean ReplaceFileAttributes,
UInt64 AllocationSize,
IntPtr Ea,
UInt32 EaLength,
out FileInfo FileInfo)
{
return Overwrite(
FileNode,
FileDesc,
FileAttributes,
ReplaceFileAttributes,
AllocationSize,
out FileInfo);
}
public virtual Int32 GetEa(
Object FileNode,
Object FileDesc,
IntPtr Ea,
UInt32 EaLength,
out UInt32 BytesTransferred)
{
Object Context = null;
String EaName;
Byte[] EaValue;
Boolean NeedEa;
FullEaInformation EaInfo = new FullEaInformation();
BytesTransferred = default(UInt32);
while (GetEaEntry(FileNode, FileDesc, ref Context, out EaName, out EaValue, out NeedEa))
{
EaInfo.Set(EaName, EaValue, NeedEa);
if (!Api.FspFileSystemAddEa(ref EaInfo, Ea, EaLength, out BytesTransferred))
return STATUS_SUCCESS;
}
Api.FspFileSystemEndEa(Ea, EaLength, out BytesTransferred);
return STATUS_SUCCESS;
}
public virtual Boolean GetEaEntry(
Object FileNode,
Object FileDesc,
ref Object Context,
out String EaName,
out Byte[] EaValue,
out Boolean NeedEa)
{
EaName = default(String);
EaValue = default(Byte[]);
NeedEa = default(Boolean);
return false;
}
public virtual Int32 SetEa(
Object FileNode,
Object FileDesc,
IntPtr Ea,
UInt32 EaLength,
out FileInfo FileInfo)
{
Int32 Result;
Result = SetEaEntries(
FileNode,
FileDesc,
Ea,
EaLength);
if (0 > Result)
{
FileInfo = default(FileInfo);
return Result;
}
return GetFileInfo(FileNode, FileDesc, out FileInfo);
}
public virtual Int32 SetEaEntry(
Object FileNode,
Object FileDesc,
ref Object Context,
String EaName,
Byte[] EaValue,
Boolean NeedEa)
{
return STATUS_INVALID_DEVICE_REQUEST;
}
/* helpers */
///
/// Converts a Win32 error code to a Windows kernel status code.
///
public static Int32 NtStatusFromWin32(UInt32 Error)
{
return Api.FspNtStatusFromWin32(Error);
}
///
/// Converts a Windows kernel status code to a Win32 error code.
///
public static UInt32 Win32FromNtStatus(Int32 Status)
{
return Api.FspWin32FromNtStatus(Status);
}
///
/// Gets the originating process ID.
///
///
/// Valid only during Create, Open and Rename requests when the target exists.
///
public static int GetOperationProcessId()
{
return (int)Api.FspFileSystemOperationProcessId();
}
///
/// Modifies a security descriptor. [OBSOLETE]
///
///
/// This is a helper for implementing the SetSecurity operation.
///
///
/// The original security descriptor.
///
///
/// Describes what parts of the file or directory security descriptor should be modified.
///
///
/// Describes the modifications to apply to the file or directory security descriptor.
///
/// The modified security descriptor.
///
[Obsolete("use ModifySecurityDescriptorEx")]
public static byte[] ModifySecurityDescriptor(
Byte[] SecurityDescriptor,
AccessControlSections Sections,
Byte[] ModificationDescriptor)
{
UInt32 SecurityInformation = 0;
if (0 != (Sections & AccessControlSections.Owner))
SecurityInformation |= 1/*OWNER_SECURITY_INFORMATION*/;
if (0 != (Sections & AccessControlSections.Group))
SecurityInformation |= 2/*GROUP_SECURITY_INFORMATION*/;
if (0 != (Sections & AccessControlSections.Access))
SecurityInformation |= 4/*DACL_SECURITY_INFORMATION*/;
if (0 != (Sections & AccessControlSections.Audit))
SecurityInformation |= 8/*SACL_SECURITY_INFORMATION*/;
return Api.ModifySecurityDescriptor(
SecurityDescriptor,
SecurityInformation,
ModificationDescriptor);
}
///
/// Modifies a security descriptor.
///
///
/// This is a helper for implementing the SetSecurity operation.
///
///
/// The original security descriptor.
///
///
/// Describes what parts of the file or directory security descriptor should be modified.
///
///
/// Describes the modifications to apply to the file or directory security descriptor.
///
///
/// The modified security descriptor. This parameter is modified only on success.
///
/// STATUS_SUCCESS or error code.
///
public static Int32 ModifySecurityDescriptorEx(
Byte[] SecurityDescriptor,
AccessControlSections Sections,
Byte[] ModificationDescriptor,
ref Byte[] ModifiedDescriptor)
{
UInt32 SecurityInformation = 0;
if (0 != (Sections & AccessControlSections.Owner))
SecurityInformation |= 1/*OWNER_SECURITY_INFORMATION*/;
if (0 != (Sections & AccessControlSections.Group))
SecurityInformation |= 2/*GROUP_SECURITY_INFORMATION*/;
if (0 != (Sections & AccessControlSections.Access))
SecurityInformation |= 4/*DACL_SECURITY_INFORMATION*/;
if (0 != (Sections & AccessControlSections.Audit))
SecurityInformation |= 8/*SACL_SECURITY_INFORMATION*/;
return Api.ModifySecurityDescriptorEx(
SecurityDescriptor,
SecurityInformation,
ModificationDescriptor,
ref ModifiedDescriptor);
}
public Int32 SeekableReadDirectory(
Object FileNode,
Object FileDesc,
String Pattern,
String Marker,
IntPtr Buffer,
UInt32 Length,
out UInt32 BytesTransferred)
{
Object Context = null;
String FileName;
DirInfo DirInfo = default(DirInfo);
BytesTransferred = default(UInt32);
while (ReadDirectoryEntry(FileNode, FileDesc, Pattern, Marker,
ref Context, out FileName, out DirInfo.FileInfo))
{
DirInfo.SetFileNameBuf(FileName);
if (!Api.FspFileSystemAddDirInfo(ref DirInfo, Buffer, Length,
out BytesTransferred))
return STATUS_SUCCESS;
}
Api.FspFileSystemEndDirInfo(Buffer, Length, out BytesTransferred);
return STATUS_SUCCESS;
}
public Int32 BufferedReadDirectory(
DirectoryBuffer DirectoryBuffer,
Object FileNode,
Object FileDesc,
String Pattern,
String Marker,
IntPtr Buffer,
UInt32 Length,
out UInt32 BytesTransferred)
{
Object Context = null;
String FileName;
DirInfo DirInfo = default(DirInfo);
Int32 DirBufferResult = STATUS_SUCCESS;
BytesTransferred = default(UInt32);
if (Api.FspFileSystemAcquireDirectoryBuffer(ref DirectoryBuffer.DirBuffer, null == Marker,
out DirBufferResult))
try
{
while (ReadDirectoryEntry(FileNode, FileDesc, Pattern, Marker,
ref Context, out FileName, out DirInfo.FileInfo))
{
DirInfo.SetFileNameBuf(FileName);
if (!Api.FspFileSystemFillDirectoryBuffer(
ref DirectoryBuffer.DirBuffer, ref DirInfo, out DirBufferResult))
break;
}
}
finally
{
Api.FspFileSystemReleaseDirectoryBuffer(ref DirectoryBuffer.DirBuffer);
}
if (0 > DirBufferResult)
{
BytesTransferred = default(UInt32);
return DirBufferResult;
}
Api.FspFileSystemReadDirectoryBuffer(ref DirectoryBuffer.DirBuffer,
Marker, Buffer, Length, out BytesTransferred);
return STATUS_SUCCESS;
}
///
/// Finds a reparse point in file name.
///
///
/// This is a helper for implementing the GetSecurityByName operation in file systems
/// that support reparse points.
///
///
/// The name of the file or directory.
///
///
/// Receives the index of the first reparse point within FileName.
///
/// True if a reparse point was found, false otherwise.
///
public Boolean FindReparsePoint(
String FileName,
out UInt32 ReparsePointIndex)
{
GCHandle Handle = GCHandle.Alloc(this, GCHandleType.Normal);
try
{
return Api.FspFileSystemFindReparsePoint(
IntPtr.Zero,
GetReparsePointByName,
(IntPtr)Handle,
FileName,
out ReparsePointIndex);
}
finally
{
Handle.Free();
}
}
///
/// Makes a byte array that contains a reparse point.
///
/// The reparse point byte array.
public static Byte[] MakeReparsePoint(
IntPtr Buffer,
UInt32 Size)
{
return Api.MakeReparsePoint(Buffer, (UIntPtr)Size);
}
///
/// Gets the reparse tag from reparse data.
///
///
/// The reparse data to extract the reparse tag from.
///
/// The reparse tag.
public static UInt32 GetReparseTag(
Byte[] ReparseData)
{
return BitConverter.ToUInt32(ReparseData, 0);
}
///
/// Tests whether reparse data can be replaced.
///
///
/// This is a helper for implementing the SetReparsePoint/DeleteReparsePoint operation
/// in file systems that support reparse points.
///
///
/// The current reparse data.
///
///
/// The replacement reparse data.
///
/// STATUS_SUCCESS or error code.
///
///
public static Int32 CanReplaceReparsePoint(
Byte[] CurrentReparseData,
Byte[] ReplaceReparseData)
{
return Api.FspFileSystemCanReplaceReparsePoint(CurrentReparseData, ReplaceReparseData);
}
private static Int32 GetReparsePointByName(
IntPtr FileSystem,
IntPtr Context,
String FileName,
Boolean IsDirectory,
IntPtr Buffer,
IntPtr PSize)
{
FileSystemBase self = (FileSystemBase)GCHandle.FromIntPtr(Context).Target;
try
{
Byte[] ReparseData;
Int32 Result;
ReparseData = null;
Result = self.GetReparsePointByName(
FileName,
IsDirectory,
ref ReparseData);
if (0 <= Result)
Result = Api.CopyReparsePoint(ReparseData, Buffer, PSize);
return Result;
}
catch (Exception ex)
{
return self.ExceptionHandler(ex);
}
}
public Int32 SetEaEntries(
Object FileNode,
Object FileDesc,
IntPtr Ea,
UInt32 EaLength)
{
return Api.FspFileSystemEnumerateEa(
FileNode,
FileDesc,
this.SetEaEntry,
Ea,
EaLength);
}
public static UInt32 GetEaEntrySize(
String EaName,
Byte[] EaValue,
Boolean NeedEa)
{
return FullEaInformation.PackedSize(EaName, EaValue, NeedEa);
}
}
}