/* * dotnet/Interop.cs * * Copyright 2015-2024 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.Diagnostics; using System.IO; using System.Reflection; using System.Runtime.InteropServices; using System.Security; using System.Security.AccessControl; namespace Fsp.Interop { [StructLayout(LayoutKind.Sequential)] internal struct VolumeParams { internal const UInt32 CaseSensitiveSearch = 0x00000001; internal const UInt32 CasePreservedNames = 0x00000002; internal const UInt32 UnicodeOnDisk = 0x00000004; internal const UInt32 PersistentAcls = 0x00000008; internal const UInt32 ReparsePoints = 0x00000010; internal const UInt32 ReparsePointsAccessCheck = 0x00000020; internal const UInt32 NamedStreams = 0x00000040; internal const UInt32 HardLinks = 0x00000080; internal const UInt32 ExtendedAttributes = 0x00000100; internal const UInt32 ReadOnlyVolume = 0x00000200; internal const UInt32 PostCleanupWhenModifiedOnly = 0x00000400; internal const UInt32 PassQueryDirectoryPattern = 0x00000800; internal const UInt32 AlwaysUseDoubleBuffering = 0x00001000; internal const UInt32 PassQueryDirectoryFileName = 0x00002000; internal const UInt32 FlushAndPurgeOnCleanup = 0x00004000; internal const UInt32 DeviceControl = 0x00008000; internal const UInt32 UmFileContextIsUserContext2 = 0x00010000; internal const UInt32 UmFileContextIsFullContext = 0x00020000; internal const UInt32 AllowOpenInKernelMode = 0x01000000; internal const UInt32 CasePreservedExtendedAttributes = 0x02000000; internal const UInt32 WslFeatures = 0x04000000; internal const UInt32 RejectIrpPriorToTransact0 = 0x10000000; internal const UInt32 SupportsPosixUnlinkRename = 0x20000000; internal const UInt32 PostDispositionWhenNecessaryOnly = 0x40000000; internal const int PrefixSize = 192; internal const int FileSystemNameSize = 16; internal const UInt32 VolumeInfoTimeoutValid = 0x00000001; internal const UInt32 DirInfoTimeoutValid = 0x00000002; internal const UInt32 SecurityTimeoutValid = 0x00000004; internal const UInt32 StreamInfoTimeoutValid = 0x00000008; internal const UInt32 EaTimeoutValid = 0x00000010; internal UInt16 Version; internal UInt16 SectorSize; internal UInt16 SectorsPerAllocationUnit; internal UInt16 MaxComponentLength; internal UInt64 VolumeCreationTime; internal UInt32 VolumeSerialNumber; internal UInt32 TransactTimeout; internal UInt32 IrpTimeout; internal UInt32 IrpCapacity; internal UInt32 FileInfoTimeout; internal UInt32 Flags; internal unsafe fixed UInt16 Prefix[PrefixSize]; internal unsafe fixed UInt16 FileSystemName[FileSystemNameSize]; internal UInt32 AdditionalFlags; internal UInt32 VolumeInfoTimeout; internal UInt32 DirInfoTimeout; internal UInt32 SecurityTimeout; internal UInt32 StreamInfoTimeout; internal UInt32 EaTimeout; internal UInt32 FsextControlCode; internal unsafe fixed UInt32 Reserved32[1]; internal unsafe fixed UInt64 Reserved64[2]; internal unsafe String GetPrefix() { fixed (UInt16 *P = Prefix) return Marshal.PtrToStringUni((IntPtr)P); } internal unsafe void SetPrefix(String Value) { fixed (UInt16 *P = Prefix) { int Size = null != Value ? Value.Length : 0; if (Size > PrefixSize - 1) Size = PrefixSize - 1; for (int I = 0; Size > I; I++) P[I] = Value[I]; P[Size] = 0; } } internal unsafe String GetFileSystemName() { fixed (UInt16 *P = FileSystemName) return Marshal.PtrToStringUni((IntPtr)P); } internal unsafe void SetFileSystemName(String Value) { fixed (UInt16 *P = FileSystemName) { int Size = null != Value ? Value.Length : 0; if (Size > FileSystemNameSize - 1) Size = FileSystemNameSize - 1; for (int I = 0; Size > I; I++) P[I] = Value[I]; P[Size] = 0; } } internal unsafe Boolean IsPrefixEmpty() { fixed (UInt16 *P = Prefix) return 0 == *P; } } /// /// Contains volume information about a file system. /// [StructLayout(LayoutKind.Sequential)] public struct VolumeInfo { internal const int VolumeLabelSize = 32; /// /// Total size of volume in bytes. /// public UInt64 TotalSize; /// /// Free size of volume in bytes. /// public UInt64 FreeSize; internal UInt16 VolumeLabelLength; internal unsafe fixed UInt16 VolumeLabel[VolumeLabelSize]; /// /// Sets the volume label. /// public unsafe void SetVolumeLabel(String Value) { fixed (UInt16 *P = VolumeLabel) { int Size = null != Value ? Value.Length : 0; if (Size > VolumeLabelSize) Size = VolumeLabelSize; for (int I = 0; Size > I; I++) P[I] = Value[I]; VolumeLabelLength = (UInt16)(Size * 2); } } } /// /// Contains metadata information about a file or directory. /// [StructLayout(LayoutKind.Sequential)] public struct FileInfo { /// /// The file or directory attributes. /// public UInt32 FileAttributes; /// /// The reparse tag of the file or directory. /// This value is 0 if the file or directory is not a reparse point. /// public UInt32 ReparseTag; /// /// The allocation size of the file. /// public UInt64 AllocationSize; /// /// The file size of the file (end of file). /// public UInt64 FileSize; /// /// The time that the file or directory was created. /// public UInt64 CreationTime; /// /// The time that the file or directory was last accessed. /// public UInt64 LastAccessTime; /// /// The time that the file or direcotry was last modified. /// public UInt64 LastWriteTime; /// /// The time that the file or directory metadata was last modified. /// public UInt64 ChangeTime; /// /// A unique identifier that is associated with the file or directory. /// Not all file systems support this value. /// public UInt64 IndexNumber; /// /// The number of hard links. /// Not currently implemented. Set to 0. /// public UInt32 HardLinks; /// /// The extended attribute size of the file. /// public UInt32 EaSize { get { return GetEaSize(); } set { SetEaSize(value); } } internal static int EaSizeOffset = (int)Marshal.OffsetOf(typeof(FileInfo), "HardLinks") + 4; internal unsafe UInt32 GetEaSize() { fixed (FileInfo *P = &this) return *(UInt32 *)((Int64)(IntPtr)P + EaSizeOffset); } internal unsafe void SetEaSize(UInt32 value) { fixed (FileInfo *P = &this) *(UInt32 *)((Int64)(IntPtr)P + EaSizeOffset) = value; } } [StructLayout(LayoutKind.Sequential)] internal struct OpenFileInfo { internal FileInfo FileInfo; internal IntPtr NormalizedName; internal UInt16 NormalizedNameSize; internal unsafe void SetNormalizedName(String Value) { UInt16 *P = (UInt16 *)NormalizedName; int Size = Value.Length; if (Size > NormalizedNameSize) Size = NormalizedNameSize; for (int I = 0; Size > I; I++) P[I] = Value[I]; NormalizedNameSize = (UInt16)(Size * 2); } } [StructLayout(LayoutKind.Sequential)] internal struct DirInfo { internal const int FileNameBufSize = 255; internal static int FileNameBufOffset = (int)Marshal.OffsetOf(typeof(DirInfo), "FileNameBuf"); internal UInt16 Size; internal FileInfo FileInfo; internal unsafe fixed Byte Padding[24]; //internal unsafe fixed UInt16 FileNameBuf[]; internal unsafe fixed UInt16 FileNameBuf[FileNameBufSize]; internal unsafe void SetFileNameBuf(String Value) { fixed (UInt16 *P = FileNameBuf) { int Size = null != Value ? Value.Length : 0; if (Size > FileNameBufSize) Size = FileNameBufSize; for (int I = 0; Size > I; I++) P[I] = Value[I]; this.Size = (UInt16)(FileNameBufOffset + Size * 2); } } } [StructLayout(LayoutKind.Sequential)] internal struct StreamInfo { internal const int StreamNameBufSize = 255; internal static int StreamNameBufOffset = (int)Marshal.OffsetOf(typeof(StreamInfo), "StreamNameBuf"); internal UInt16 Size; internal UInt64 StreamSize; internal UInt64 StreamAllocationSize; //internal unsafe fixed UInt16 StreamNameBuf[]; internal unsafe fixed UInt16 StreamNameBuf[StreamNameBufSize]; internal unsafe void SetStreamNameBuf(String Value) { fixed (UInt16 *P = StreamNameBuf) { int Size = null != Value ? Value.Length : 0; if (Size > StreamNameBufSize) Size = StreamNameBufSize; for (int I = 0; Size > I; I++) P[I] = Value[I]; this.Size = (UInt16)(StreamNameBufOffset + Size * 2); } } } [StructLayout(LayoutKind.Sequential)] internal struct NotifyInfoInternal { internal const int FileNameBufSize = 1024 * 2/*FSP_FSCTL_TRANSACT_PATH_SIZEMAX*/; internal static int FileNameBufOffset = (int)Marshal.OffsetOf(typeof(NotifyInfoInternal), "FileNameBuf"); internal UInt16 Size; internal UInt32 Filter; internal UInt32 Action; //internal unsafe fixed UInt16 FileNameBuf[]; internal unsafe fixed UInt16 FileNameBuf[FileNameBufSize]; internal unsafe void SetFileNameBuf(String Value) { fixed (UInt16 *P = FileNameBuf) { int Size = null != Value ? Value.Length : 0; if (Size > FileNameBufSize) Size = FileNameBufSize; for (int I = 0; Size > I; I++) P[I] = Value[I]; this.Size = (UInt16)(FileNameBufOffset + Size * 2); } } } /// /// Enumeration of all the possible values for NotifyInfo.Action /// public enum NotifyAction : UInt32 { Added = 1, Removed = 2, Modified = 3, RenamedOldName = 4, RenamedNewName = 5, AddedStream = 6, RemovedStream = 7, ModifiedStream = 8, RemovedByDelete = 9, IdNotTunnelled = 10, TunnelledIdCollision = 11, } /// /// Enumeration of all the possible values for NotifyInfo.Filter /// [Flags] public enum NotifyFilter : UInt32 { None = 0x00000, ChangeFileName = 0x00001, ChangeDirName = 0x00002, ChangeName = ChangeFileName | ChangeDirName, ChangeAttributes = 0x00004, ChangeSize = 0x00008, ChangeLastWrite = 0x00010, ChangeLastAccess = 0x00020, ChangeCreation = 0x00040, ChangeEa = 0x00080, ChangeSecurity = 0x00100, ChangeStreamName = 0x00200, ChangeStreamSize = 0x00400, ChangeStreamWrite = 0x00800, } /// /// Contains file change notification information. /// [StructLayout(LayoutKind.Sequential)] public struct NotifyInfo { public String FileName; public NotifyAction Action; public NotifyFilter Filter; } [StructLayout(LayoutKind.Sequential)] internal struct FullEaInformation { internal const int EaNameSize = 15 * 1024; /* Set this to a value smaller than 16384 with sufficient space for additional data. * This should really be: * FSP_FSCTL_TRANSACT_RSP_BUFFER_SIZEMAX - FIELD_OFFSET(FILE_FULL_EA_INFORMATION, EaName) */ internal UInt32 NextEntryOffset; internal Byte Flags; internal Byte EaNameLength; internal UInt16 EaValueLength; internal unsafe fixed Byte EaName[EaNameSize]; internal unsafe void Set(String Name, Byte[] Value, Boolean NeedEa) { int NameLength = 254 < Name.Length ? 254 : Name.Length; int ValueLength = EaNameSize - Name.Length - 1 < Value.Length ? EaNameSize - Name.Length - 1 : Value.Length; NextEntryOffset = 0; Flags = NeedEa ? (Byte)0x80/*FILE_NEED_EA*/ : (Byte)0; EaNameLength = (Byte)NameLength; EaValueLength = (UInt16)ValueLength; fixed (Byte *P = EaName) { int I = 0, J = 0; for (; NameLength > I; I++) P[I] = (Byte)Name[I]; P[I++] = 0; for (; ValueLength > J; J++) P[I + J] = Value[J]; } } internal static UInt32 PackedSize(String Name, Byte[] Value, Boolean NeedEa) { int NameLength = 254 < Name.Length ? 254 : Name.Length; int ValueLength = EaNameSize - Name.Length - 1 < Value.Length ? EaNameSize - Name.Length - 1 : Value.Length; /* magic computations are courtesy of NTFS */ return (UInt32)(5 + NameLength + ValueLength); } } [StructLayout(LayoutKind.Sequential)] internal struct FullContext { internal UInt64 UserContext; internal UInt64 UserContext2; } [StructLayout(LayoutKind.Sequential)] public struct IoStatusBlock { public IntPtr Status; public IntPtr Information; } [StructLayout(LayoutKind.Sequential)] internal struct IoStatus { internal UInt32 Information; internal UInt32 Status; } internal enum FspFsctlTransact { ReadKind = 5, WriteKind = 6, QueryDirectoryKind = 14 } [StructLayout(LayoutKind.Explicit)] internal struct FspFsctlTransactReq { [FieldOffset(0)] internal UInt16 Version; [FieldOffset(2)] internal UInt16 Size; [FieldOffset(4)] internal UInt32 Kind; [FieldOffset(8)] internal UInt64 Hint; [FieldOffset(0)] internal unsafe fixed Byte Padding[88]; } [StructLayout(LayoutKind.Explicit)] internal struct FspFsctlTransactRsp { [FieldOffset(0)] internal UInt16 Version; [FieldOffset(2)] internal UInt16 Size; [FieldOffset(4)] internal UInt32 Kind; [FieldOffset(8)] internal UInt64 Hint; [FieldOffset(16)] internal IoStatus IoStatus; [FieldOffset(24)] internal FileInfo WriteFileInfo; [FieldOffset(0)] internal unsafe fixed Byte Padding[128]; } [StructLayout(LayoutKind.Sequential)] internal unsafe struct FspFileSystemOperationContext { internal FspFsctlTransactReq *Request; internal FspFsctlTransactRsp *Response; } [StructLayout(LayoutKind.Sequential)] internal struct FileSystemInterface { internal struct Proto { [UnmanagedFunctionPointer(CallingConvention.Cdecl)] internal delegate Int32 GetVolumeInfo( IntPtr FileSystem, out VolumeInfo VolumeInfo); [UnmanagedFunctionPointer(CallingConvention.Cdecl)] internal delegate Int32 SetVolumeLabel( IntPtr FileSystem, [MarshalAs(UnmanagedType.LPWStr)] String VolumeLabel, out VolumeInfo VolumeInfo); [UnmanagedFunctionPointer(CallingConvention.Cdecl)] internal delegate Int32 GetSecurityByName( IntPtr FileSystem, [MarshalAs(UnmanagedType.LPWStr)] String FileName, IntPtr PFileAttributes/* or ReparsePointIndex */, IntPtr SecurityDescriptor, IntPtr PSecurityDescriptorSize); [UnmanagedFunctionPointer(CallingConvention.Cdecl)] internal delegate Int32 Create( IntPtr FileSystem, [MarshalAs(UnmanagedType.LPWStr)] String FileName, UInt32 CreateOptions, UInt32 GrantedAccess, UInt32 FileAttributes, IntPtr SecurityDescriptor, UInt64 AllocationSize, ref FullContext FullContext, ref OpenFileInfo OpenFileInfo); [UnmanagedFunctionPointer(CallingConvention.Cdecl)] internal delegate Int32 Open( IntPtr FileSystem, [MarshalAs(UnmanagedType.LPWStr)] String FileName, UInt32 CreateOptions, UInt32 GrantedAccess, ref FullContext FullContext, ref OpenFileInfo OpenFileInfo); [UnmanagedFunctionPointer(CallingConvention.Cdecl)] internal delegate Int32 Overwrite( IntPtr FileSystem, ref FullContext FullContext, UInt32 FileAttributes, [MarshalAs(UnmanagedType.U1)] Boolean ReplaceFileAttributes, UInt64 AllocationSize, out FileInfo FileInfo); [UnmanagedFunctionPointer(CallingConvention.Cdecl)] internal delegate void Cleanup( IntPtr FileSystem, ref FullContext FullContext, [MarshalAs(UnmanagedType.LPWStr)] String FileName, UInt32 Flags); [UnmanagedFunctionPointer(CallingConvention.Cdecl)] internal delegate void Close( IntPtr FileSystem, ref FullContext FullContext); [UnmanagedFunctionPointer(CallingConvention.Cdecl)] internal delegate Int32 Read( IntPtr FileSystem, ref FullContext FullContext, IntPtr Buffer, UInt64 Offset, UInt32 Length, out UInt32 PBytesTransferred); [UnmanagedFunctionPointer(CallingConvention.Cdecl)] internal delegate Int32 Write( IntPtr FileSystem, ref FullContext FullContext, IntPtr Buffer, UInt64 Offset, UInt32 Length, [MarshalAs(UnmanagedType.U1)] Boolean WriteToEndOfFile, [MarshalAs(UnmanagedType.U1)] Boolean ConstrainedIo, out UInt32 PBytesTransferred, out FileInfo FileInfo); [UnmanagedFunctionPointer(CallingConvention.Cdecl)] internal delegate Int32 Flush( IntPtr FileSystem, ref FullContext FullContext, out FileInfo FileInfo); [UnmanagedFunctionPointer(CallingConvention.Cdecl)] internal delegate Int32 GetFileInfo( IntPtr FileSystem, ref FullContext FullContext, out FileInfo FileInfo); [UnmanagedFunctionPointer(CallingConvention.Cdecl)] internal delegate Int32 SetBasicInfo( IntPtr FileSystem, ref FullContext FullContext, UInt32 FileAttributes, UInt64 CreationTime, UInt64 LastAccessTime, UInt64 LastWriteTime, UInt64 ChangeTime, out FileInfo FileInfo); [UnmanagedFunctionPointer(CallingConvention.Cdecl)] internal delegate Int32 SetFileSize( IntPtr FileSystem, ref FullContext FullContext, UInt64 NewSize, [MarshalAs(UnmanagedType.U1)] Boolean SetAllocationSize, out FileInfo FileInfo); [UnmanagedFunctionPointer(CallingConvention.Cdecl)] internal delegate Int32 CanDelete( IntPtr FileSystem, ref FullContext FullContext, [MarshalAs(UnmanagedType.LPWStr)] String FileName); [UnmanagedFunctionPointer(CallingConvention.Cdecl)] internal delegate Int32 Rename( IntPtr FileSystem, ref FullContext FullContext, [MarshalAs(UnmanagedType.LPWStr)] String FileName, [MarshalAs(UnmanagedType.LPWStr)] String NewFileName, [MarshalAs(UnmanagedType.U1)] Boolean ReplaceIfExists); [UnmanagedFunctionPointer(CallingConvention.Cdecl)] internal delegate Int32 GetSecurity( IntPtr FileSystem, ref FullContext FullContext, IntPtr SecurityDescriptor, IntPtr PSecurityDescriptorSize); [UnmanagedFunctionPointer(CallingConvention.Cdecl)] internal delegate Int32 SetSecurity( IntPtr FileSystem, ref FullContext FullContext, UInt32 SecurityInformation, IntPtr ModificationDescriptor); [UnmanagedFunctionPointer(CallingConvention.Cdecl)] internal delegate Int32 ReadDirectory( IntPtr FileSystem, ref FullContext FullContext, [MarshalAs(UnmanagedType.LPWStr)] String Pattern, [MarshalAs(UnmanagedType.LPWStr)] String Marker, IntPtr Buffer, UInt32 Length, out UInt32 PBytesTransferred); [UnmanagedFunctionPointer(CallingConvention.Cdecl)] internal delegate Int32 ResolveReparsePoints( IntPtr FileSystem, [MarshalAs(UnmanagedType.LPWStr)] String FileName, UInt32 ReparsePointIndex, [MarshalAs(UnmanagedType.U1)] Boolean ResolveLastPathComponent, out IoStatusBlock PIoStatus, IntPtr Buffer, IntPtr PSize); [UnmanagedFunctionPointer(CallingConvention.Cdecl)] internal delegate Int32 GetReparsePoint( IntPtr FileSystem, ref FullContext FullContext, [MarshalAs(UnmanagedType.LPWStr)] String FileName, IntPtr Buffer, IntPtr PSize); [UnmanagedFunctionPointer(CallingConvention.Cdecl)] internal delegate Int32 SetReparsePoint( IntPtr FileSystem, ref FullContext FullContext, [MarshalAs(UnmanagedType.LPWStr)] String FileName, IntPtr Buffer, UIntPtr Size); [UnmanagedFunctionPointer(CallingConvention.Cdecl)] internal delegate Int32 DeleteReparsePoint( IntPtr FileSystem, ref FullContext FullContext, [MarshalAs(UnmanagedType.LPWStr)] String FileName, IntPtr Buffer, UIntPtr Size); [UnmanagedFunctionPointer(CallingConvention.Cdecl)] internal delegate Int32 GetStreamInfo( IntPtr FileSystem, ref FullContext FullContext, IntPtr Buffer, UInt32 Length, out UInt32 PBytesTransferred); [UnmanagedFunctionPointer(CallingConvention.Cdecl)] internal delegate Int32 GetDirInfoByName( IntPtr FileSystem, ref FullContext FullContext, [MarshalAs(UnmanagedType.LPWStr)] String FileName, out DirInfo DirInfo); [UnmanagedFunctionPointer(CallingConvention.Cdecl)] internal delegate Int32 Control( IntPtr FileSystem, ref FullContext FullContext, UInt32 ControlCode, IntPtr InputBuffer, UInt32 InputBufferLength, IntPtr OutputBuffer, UInt32 OutputBufferLength, out UInt32 PBytesTransferred); [UnmanagedFunctionPointer(CallingConvention.Cdecl)] internal delegate Int32 SetDelete( IntPtr FileSystem, ref FullContext FullContext, [MarshalAs(UnmanagedType.LPWStr)] String FileName, [MarshalAs(UnmanagedType.U1)] Boolean DeleteFile); [UnmanagedFunctionPointer(CallingConvention.Cdecl)] internal delegate Int32 CreateEx( IntPtr FileSystem, [MarshalAs(UnmanagedType.LPWStr)] String FileName, UInt32 CreateOptions, UInt32 GrantedAccess, UInt32 FileAttributes, IntPtr SecurityDescriptor, UInt64 AllocationSize, IntPtr ExtraBuffer, UInt32 ExtraLength, [MarshalAs(UnmanagedType.U1)] Boolean ExtraBufferIsReparsePoint, ref FullContext FullContext, ref OpenFileInfo OpenFileInfo); [UnmanagedFunctionPointer(CallingConvention.Cdecl)] internal delegate Int32 OverwriteEx( IntPtr FileSystem, ref FullContext FullContext, UInt32 FileAttributes, [MarshalAs(UnmanagedType.U1)] Boolean ReplaceFileAttributes, UInt64 AllocationSize, IntPtr Ea, UInt32 EaLength, out FileInfo FileInfo); [UnmanagedFunctionPointer(CallingConvention.Cdecl)] internal delegate Int32 GetEa( IntPtr FileSystem, ref FullContext FullContext, IntPtr Ea, UInt32 EaLength, out UInt32 PBytesTransferred); [UnmanagedFunctionPointer(CallingConvention.Cdecl)] internal delegate Int32 SetEa( IntPtr FileSystem, ref FullContext FullContext, IntPtr Ea, UInt32 EaLength, out FileInfo FileInfo); [UnmanagedFunctionPointer(CallingConvention.Cdecl)] internal delegate Int32 Obsolete0(); [UnmanagedFunctionPointer(CallingConvention.Cdecl)] internal delegate void DispatcherStopped( IntPtr FileSystem, [MarshalAs(UnmanagedType.U1)] Boolean Normally); } internal static int Size = IntPtr.Size * 64; internal Proto.GetVolumeInfo GetVolumeInfo; internal Proto.SetVolumeLabel SetVolumeLabel; internal Proto.GetSecurityByName GetSecurityByName; internal Proto.Create Create; internal Proto.Open Open; internal Proto.Overwrite Overwrite; internal Proto.Cleanup Cleanup; internal Proto.Close Close; internal Proto.Read Read; internal Proto.Write Write; internal Proto.Flush Flush; internal Proto.GetFileInfo GetFileInfo; internal Proto.SetBasicInfo SetBasicInfo; internal Proto.SetFileSize SetFileSize; internal Proto.CanDelete CanDelete; internal Proto.Rename Rename; internal Proto.GetSecurity GetSecurity; internal Proto.SetSecurity SetSecurity; internal Proto.ReadDirectory ReadDirectory; internal Proto.ResolveReparsePoints ResolveReparsePoints; internal Proto.GetReparsePoint GetReparsePoint; internal Proto.SetReparsePoint SetReparsePoint; internal Proto.DeleteReparsePoint DeleteReparsePoint; internal Proto.GetStreamInfo GetStreamInfo; internal Proto.GetDirInfoByName GetDirInfoByName; internal Proto.Control Control; internal Proto.SetDelete SetDelete; internal Proto.CreateEx CreateEx; internal Proto.OverwriteEx OverwriteEx; internal Proto.GetEa GetEa; internal Proto.SetEa SetEa; internal Proto.Obsolete0 Obsolete0; internal Proto.DispatcherStopped DispatcherStopped; /* NTSTATUS (*Reserved[33])(); */ } [SuppressUnmanagedCodeSecurity] internal static class Api { internal struct Proto { /* FileSystem */ [UnmanagedFunctionPointer(CallingConvention.Cdecl)] internal delegate Int32 FspFileSystemPreflight( [MarshalAs(UnmanagedType.LPWStr)] String DevicePath, [MarshalAs(UnmanagedType.LPWStr)] String MountPoint); [UnmanagedFunctionPointer(CallingConvention.Cdecl)] internal delegate Int32 FspFileSystemCreate( [MarshalAs(UnmanagedType.LPWStr)] String DevicePath, ref VolumeParams VolumeParams, IntPtr Interface, out IntPtr PFileSystem); [UnmanagedFunctionPointer(CallingConvention.Cdecl)] internal delegate void FspFileSystemDelete( IntPtr FileSystem); [UnmanagedFunctionPointer(CallingConvention.Cdecl)] internal delegate Int32 FspFileSystemSetMountPoint( IntPtr FileSystem, [MarshalAs(UnmanagedType.LPWStr)] String MountPoint); [UnmanagedFunctionPointer(CallingConvention.Cdecl)] internal delegate Int32 FspFileSystemSetMountPointEx( IntPtr FileSystem, [MarshalAs(UnmanagedType.LPWStr)] String MountPoint, IntPtr SecurityDescriptor); [UnmanagedFunctionPointer(CallingConvention.Cdecl)] internal delegate Int32 FspFileSystemRemoveMountPoint( IntPtr FileSystem); [UnmanagedFunctionPointer(CallingConvention.Cdecl)] internal delegate Int32 FspFileSystemStartDispatcher( IntPtr FileSystem, UInt32 ThreadCount); [UnmanagedFunctionPointer(CallingConvention.Cdecl)] internal delegate Int32 FspFileSystemStopDispatcher( IntPtr FileSystem); [UnmanagedFunctionPointer(CallingConvention.Cdecl)] internal delegate void FspFileSystemSendResponse( IntPtr FileSystem, ref FspFsctlTransactRsp Response); [UnmanagedFunctionPointer(CallingConvention.Cdecl)] internal delegate Int32 FspFileSystemNotifyBegin( IntPtr FileSystem, UInt32 Timeout); [UnmanagedFunctionPointer(CallingConvention.Cdecl)] internal delegate Int32 FspFileSystemNotifyEnd( IntPtr FileSystem); [UnmanagedFunctionPointer(CallingConvention.Cdecl)] internal delegate Int32 FspFileSystemNotify( IntPtr FileSystem, IntPtr NotifyInfo, UIntPtr Size); [UnmanagedFunctionPointer(CallingConvention.Cdecl)] internal unsafe delegate FspFileSystemOperationContext *FspFileSystemGetOperationContext(); [UnmanagedFunctionPointer(CallingConvention.Cdecl)] internal delegate IntPtr FspFileSystemMountPointF( IntPtr FileSystem); [UnmanagedFunctionPointer(CallingConvention.Cdecl)] internal delegate void FspFileSystemSetOperationGuardStrategyF( IntPtr FileSystem, Int32 GuardStrategy); [UnmanagedFunctionPointer(CallingConvention.Cdecl)] internal delegate void FspFileSystemSetDebugLogF( IntPtr FileSystem, UInt32 DebugLog); [UnmanagedFunctionPointer(CallingConvention.Cdecl)] internal delegate UInt32 FspFileSystemOperationProcessIdF(); [UnmanagedFunctionPointer(CallingConvention.Cdecl)] [return: MarshalAs(UnmanagedType.U1)] internal delegate Boolean FspFileSystemAddDirInfo( IntPtr DirInfo, IntPtr Buffer, UInt32 Length, out UInt32 PBytesTransferred); [UnmanagedFunctionPointer(CallingConvention.Cdecl)] [return: MarshalAs(UnmanagedType.U1)] internal delegate Boolean FspFileSystemFindReparsePoint( IntPtr FileSystem, GetReparsePointByName GetReparsePointByName, IntPtr Context, [MarshalAs(UnmanagedType.LPWStr)] String FileName, out UInt32 PReparsePointIndex); [UnmanagedFunctionPointer(CallingConvention.Cdecl)] internal delegate Int32 FspFileSystemResolveReparsePoints( IntPtr FileSystem, GetReparsePointByName GetReparsePointByName, IntPtr Context, [MarshalAs(UnmanagedType.LPWStr)] String FileName, UInt32 ReparsePointIndex, [MarshalAs(UnmanagedType.U1)] Boolean ResolveLastPathComponent, out IoStatusBlock PIoStatus, IntPtr Buffer, IntPtr PSize); [UnmanagedFunctionPointer(CallingConvention.Cdecl)] internal delegate Int32 FspFileSystemCanReplaceReparsePoint( IntPtr CurrentReparseData, UIntPtr CurrentReparseDataSize, IntPtr ReplaceReparseData, UIntPtr ReplaceReparseDataSize); [UnmanagedFunctionPointer(CallingConvention.Cdecl)] [return: MarshalAs(UnmanagedType.U1)] internal delegate Boolean FspFileSystemAddStreamInfo( IntPtr StreamInfo, IntPtr Buffer, UInt32 Length, out UInt32 PBytesTransferred); [UnmanagedFunctionPointer(CallingConvention.Cdecl)] [return: MarshalAs(UnmanagedType.U1)] internal delegate Boolean FspFileSystemAddEa( IntPtr SingleEa, IntPtr Ea, UInt32 EaLength, out UInt32 PBytesTransferred); [UnmanagedFunctionPointer(CallingConvention.Cdecl)] [return: MarshalAs(UnmanagedType.U1)] internal delegate Boolean FspFileSystemAddNotifyInfo( IntPtr NotifyInfo, IntPtr Buffer, UInt32 Length, out UInt32 PBytesTransferred); [UnmanagedFunctionPointer(CallingConvention.Cdecl)] internal delegate void FspFileSystemStopServiceIfNecessary( IntPtr FileSystem, [MarshalAs(UnmanagedType.U1)] Boolean Normally); [UnmanagedFunctionPointer(CallingConvention.Cdecl)] [return: MarshalAs(UnmanagedType.U1)] internal delegate Boolean FspFileSystemAcquireDirectoryBuffer( ref IntPtr PDirBuffer, [MarshalAs(UnmanagedType.U1)] Boolean Reset, out Int32 PResult); [UnmanagedFunctionPointer(CallingConvention.Cdecl)] [return: MarshalAs(UnmanagedType.U1)] internal delegate Boolean FspFileSystemFillDirectoryBuffer( ref IntPtr PDirBuffer, ref DirInfo DirInfo, out Int32 PResult); [UnmanagedFunctionPointer(CallingConvention.Cdecl)] internal delegate void FspFileSystemReleaseDirectoryBuffer( ref IntPtr PDirBuffer); [UnmanagedFunctionPointer(CallingConvention.Cdecl)] internal delegate void FspFileSystemReadDirectoryBuffer( ref IntPtr PDirBuffer, [MarshalAs(UnmanagedType.LPWStr)] String Marker, IntPtr Buffer, UInt32 Length, out UInt32 PBytesTransferred); [UnmanagedFunctionPointer(CallingConvention.Cdecl)] internal delegate void FspFileSystemDeleteDirectoryBuffer( ref IntPtr PDirBuffer); [UnmanagedFunctionPointer(CallingConvention.Cdecl)] internal delegate Int32 FspSetSecurityDescriptor( IntPtr InputDescriptor, UInt32 SecurityInformation, IntPtr ModificationDescriptor, out IntPtr PSecurityDescriptor); [UnmanagedFunctionPointer(CallingConvention.Cdecl)] internal delegate void FspDeleteSecurityDescriptor( IntPtr SecurityDescriptor, IntPtr CreateFunc); /* Service */ [UnmanagedFunctionPointer(CallingConvention.Cdecl)] internal delegate Int32 FspServiceCreate( [MarshalAs(UnmanagedType.LPWStr)] String ServiceName, ServiceStart OnStart, ServiceStop OnStop, ServiceControl OnControl, out IntPtr PService); [UnmanagedFunctionPointer(CallingConvention.Cdecl)] internal delegate void FspServiceDelete( IntPtr Service); [UnmanagedFunctionPointer(CallingConvention.Cdecl)] internal delegate void FspServiceAllowConsoleMode( IntPtr Service); [UnmanagedFunctionPointer(CallingConvention.Cdecl)] internal delegate void FspServiceRequestTime( IntPtr Service, UInt32 Time); [UnmanagedFunctionPointer(CallingConvention.Cdecl)] internal delegate void FspServiceSetExitCode( IntPtr Service, UInt32 ExitCode); [UnmanagedFunctionPointer(CallingConvention.Cdecl)] internal delegate UInt32 FspServiceGetExitCode( IntPtr Service); [UnmanagedFunctionPointer(CallingConvention.Cdecl)] internal delegate Int32 FspServiceLoop( IntPtr Service); [UnmanagedFunctionPointer(CallingConvention.Cdecl)] internal delegate void FspServiceStop( IntPtr Service); [UnmanagedFunctionPointer(CallingConvention.Cdecl)] internal delegate void FspServiceLog( UInt32 Type, [MarshalAs(UnmanagedType.LPWStr)] String Format, [MarshalAs(UnmanagedType.LPWStr)] String Message); /* utility */ [UnmanagedFunctionPointer(CallingConvention.Cdecl)] internal delegate Int32 FspVersion( out UInt32 PVersion); [UnmanagedFunctionPointer(CallingConvention.Cdecl)] internal delegate Int32 FspNtStatusFromWin32( UInt32 Error); [UnmanagedFunctionPointer(CallingConvention.Cdecl)] internal delegate UInt32 FspWin32FromNtStatus( Int32 Status); [UnmanagedFunctionPointer(CallingConvention.Cdecl)] internal delegate void FspDebugLog( [MarshalAs(UnmanagedType.LPStr)] String Format, [MarshalAs(UnmanagedType.LPStr)] String Message); [UnmanagedFunctionPointer(CallingConvention.Cdecl)] internal delegate void FspDebugLogSetHandle( IntPtr Handle); /* callbacks */ [UnmanagedFunctionPointer(CallingConvention.Cdecl)] internal delegate Int32 GetReparsePointByName( IntPtr FileSystem, IntPtr Context, [MarshalAs(UnmanagedType.LPWStr)] String FileName, [MarshalAs(UnmanagedType.U1)] Boolean IsDirectory, IntPtr Buffer, IntPtr PSize); [UnmanagedFunctionPointer(CallingConvention.Cdecl)] internal delegate Int32 ServiceStart( IntPtr Service, UInt32 Argc, [MarshalAs(UnmanagedType.LPArray, ArraySubType = UnmanagedType.LPWStr, SizeParamIndex = 1)] String[] Argv); [UnmanagedFunctionPointer(CallingConvention.Cdecl)] internal delegate Int32 ServiceStop( IntPtr Service); [UnmanagedFunctionPointer(CallingConvention.Cdecl)] internal delegate Int32 ServiceControl( IntPtr Service, UInt32 Control, UInt32 EventType, IntPtr EventData); } internal static Proto.FspFileSystemPreflight FspFileSystemPreflight; internal static Proto.FspFileSystemCreate FspFileSystemCreate; internal static Proto.FspFileSystemDelete FspFileSystemDelete; internal static Proto.FspFileSystemSetMountPoint FspFileSystemSetMountPoint; internal static Proto.FspFileSystemSetMountPointEx _FspFileSystemSetMountPointEx; internal static Proto.FspFileSystemRemoveMountPoint FspFileSystemRemoveMountPoint; internal static Proto.FspFileSystemStartDispatcher FspFileSystemStartDispatcher; internal static Proto.FspFileSystemStopDispatcher FspFileSystemStopDispatcher; internal static Proto.FspFileSystemSendResponse FspFileSystemSendResponse; internal static Proto.FspFileSystemNotifyBegin FspFileSystemNotifyBegin; internal static Proto.FspFileSystemNotifyEnd FspFileSystemNotifyEnd; internal static Proto.FspFileSystemNotify _FspFileSystemNotify; internal static Proto.FspFileSystemGetOperationContext FspFileSystemGetOperationContext; internal static Proto.FspFileSystemMountPointF FspFileSystemMountPoint; internal static Proto.FspFileSystemSetOperationGuardStrategyF FspFileSystemSetOperationGuardStrategy; internal static Proto.FspFileSystemSetDebugLogF FspFileSystemSetDebugLog; internal static Proto.FspFileSystemOperationProcessIdF FspFileSystemOperationProcessId; internal static Proto.FspFileSystemAddDirInfo _FspFileSystemAddDirInfo; internal static Proto.FspFileSystemFindReparsePoint FspFileSystemFindReparsePoint; internal static Proto.FspFileSystemResolveReparsePoints FspFileSystemResolveReparsePoints; internal static Proto.FspFileSystemCanReplaceReparsePoint _FspFileSystemCanReplaceReparsePoint; internal static Proto.FspFileSystemAddStreamInfo _FspFileSystemAddStreamInfo; internal static Proto.FspFileSystemAddEa _FspFileSystemAddEa; internal static Proto.FspFileSystemAddNotifyInfo _FspFileSystemAddNotifyInfo; internal static Proto.FspFileSystemStopServiceIfNecessary FspFileSystemStopServiceIfNecessary; internal static Proto.FspFileSystemAcquireDirectoryBuffer FspFileSystemAcquireDirectoryBuffer; internal static Proto.FspFileSystemFillDirectoryBuffer FspFileSystemFillDirectoryBuffer; internal static Proto.FspFileSystemReleaseDirectoryBuffer FspFileSystemReleaseDirectoryBuffer; internal static Proto.FspFileSystemReadDirectoryBuffer FspFileSystemReadDirectoryBuffer; internal static Proto.FspFileSystemDeleteDirectoryBuffer FspFileSystemDeleteDirectoryBuffer; internal static Proto.FspSetSecurityDescriptor FspSetSecurityDescriptor; internal static IntPtr _FspSetSecurityDescriptorPtr; internal static Proto.FspDeleteSecurityDescriptor FspDeleteSecurityDescriptor; internal static Proto.FspServiceCreate FspServiceCreate; internal static Proto.FspServiceDelete FspServiceDelete; internal static Proto.FspServiceAllowConsoleMode FspServiceAllowConsoleMode; internal static Proto.FspServiceRequestTime FspServiceRequestTime; internal static Proto.FspServiceSetExitCode FspServiceSetExitCode; internal static Proto.FspServiceGetExitCode FspServiceGetExitCode; internal static Proto.FspServiceLoop FspServiceLoop; internal static Proto.FspServiceStop FspServiceStop; internal static Proto.FspServiceLog FspServiceLog; internal static Proto.FspVersion FspVersion; internal static Proto.FspNtStatusFromWin32 FspNtStatusFromWin32; internal static Proto.FspWin32FromNtStatus FspWin32FromNtStatus; internal static Proto.FspDebugLog FspDebugLog; internal static Proto.FspDebugLogSetHandle FspDebugLogSetHandle; internal static unsafe Int32 FspFileSystemSetMountPointEx( IntPtr FileSystem, String MountPoint, Byte[] SecurityDescriptor) { if (null != SecurityDescriptor) { fixed (Byte *P = SecurityDescriptor) return _FspFileSystemSetMountPointEx(FileSystem, MountPoint, (IntPtr)P); } else return _FspFileSystemSetMountPointEx(FileSystem, MountPoint, IntPtr.Zero); } internal static unsafe UInt64 FspFileSystemGetOperationRequestHint() { return FspFileSystemGetOperationContext()->Request->Hint; } internal static unsafe Boolean FspFileSystemAddDirInfo( ref DirInfo DirInfo, IntPtr Buffer, UInt32 Length, out UInt32 PBytesTransferred) { fixed (DirInfo *P = &DirInfo) return _FspFileSystemAddDirInfo((IntPtr)P, Buffer, Length, out PBytesTransferred); } internal static unsafe Boolean FspFileSystemEndDirInfo( IntPtr Buffer, UInt32 Length, out UInt32 PBytesTransferred) { return _FspFileSystemAddDirInfo(IntPtr.Zero, Buffer, Length, out PBytesTransferred); } internal static unsafe Boolean FspFileSystemAddStreamInfo( ref StreamInfo StreamInfo, IntPtr Buffer, UInt32 Length, out UInt32 PBytesTransferred) { fixed (StreamInfo *P = &StreamInfo) return _FspFileSystemAddStreamInfo((IntPtr)P, Buffer, Length, out PBytesTransferred); } internal static unsafe Boolean FspFileSystemEndStreamInfo( IntPtr Buffer, UInt32 Length, out UInt32 PBytesTransferred) { return _FspFileSystemAddStreamInfo(IntPtr.Zero, Buffer, Length, out PBytesTransferred); } internal static unsafe Boolean FspFileSystemAddNotifyInfo( ref NotifyInfoInternal NotifyInfo, IntPtr Buffer, UInt32 Length, out UInt32 PBytesTransferred) { fixed (NotifyInfoInternal *P = &NotifyInfo) return _FspFileSystemAddNotifyInfo((IntPtr)P, Buffer, Length, out PBytesTransferred); } internal delegate Int32 EnumerateEa( Object FileNode, Object FileDesc, ref Object Context, String EaName, Byte[] EaValue, Boolean NeedEa); internal static unsafe Int32 FspFileSystemEnumerateEa( Object FileNode, Object FileDesc, EnumerateEa EnumerateEa, IntPtr Ea, UInt32 EaLength) { Object Context = null; FullEaInformation *P = (FullEaInformation *)Ea; FullEaInformation *EndP = (FullEaInformation *)(Ea.ToInt64() + EaLength); Int32 Result; Result = 0/*STATUS_SUCCESS*/; for (; EndP > P; P = 0 != P->NextEntryOffset ? (FullEaInformation *)(((IntPtr)P).ToInt64() + P->NextEntryOffset) : EndP) { String EaName = Marshal.PtrToStringAnsi((IntPtr)P->EaName, P->EaNameLength); Byte[] EaValue = null; if (0 != P->EaValueLength) { EaValue = new Byte[P->EaValueLength]; Marshal.Copy((IntPtr)(((IntPtr)P->EaName).ToInt64() + P->EaNameLength + 1), EaValue, 0, P->EaValueLength); } Boolean NeedEa = 0 != (0x80/*FILE_NEED_EA*/ & P->Flags); Result = EnumerateEa(FileNode, FileDesc, ref Context, EaName, EaValue, NeedEa); if (0 > Result) break; } return Result; } internal static unsafe Boolean FspFileSystemAddEa( ref FullEaInformation EaInfo, IntPtr Buffer, UInt32 Length, out UInt32 PBytesTransferred) { fixed (FullEaInformation *P = &EaInfo) return _FspFileSystemAddEa((IntPtr)P, Buffer, Length, out PBytesTransferred); } internal static unsafe Boolean FspFileSystemEndEa( IntPtr Buffer, UInt32 Length, out UInt32 PBytesTransferred) { return _FspFileSystemAddEa(IntPtr.Zero, Buffer, Length, out PBytesTransferred); } internal static unsafe Int32 FspFileSystemNotify( IntPtr FileSystem, NotifyInfo[] NotifyInfoArray) { int Length = 0; for (int I = 0; NotifyInfoArray.Length > I; I++) { Length += NotifyInfoInternal.FileNameBufOffset + NotifyInfoArray[I].FileName.Length * 2; Length = (Length + 7) & ~7; // align to next qword boundary } Byte[] Buffer = new Byte[Length]; UInt32 BytesTransferred = default(UInt32); fixed (Byte *P = Buffer) { for (int I = 0; NotifyInfoArray.Length > I; I++) { NotifyInfoInternal Internal = default(NotifyInfoInternal); Internal.Action = (UInt32)NotifyInfoArray[I].Action; Internal.Filter = (UInt32)NotifyInfoArray[I].Filter; Internal.SetFileNameBuf(NotifyInfoArray[I].FileName); FspFileSystemAddNotifyInfo( ref Internal, (IntPtr)P, (UInt32)Length, out BytesTransferred); } return _FspFileSystemNotify(FileSystem, (IntPtr)P, (UIntPtr)BytesTransferred); } } internal unsafe static Object GetUserContext( IntPtr NativePtr) { IntPtr UserContext = *(IntPtr *)((Byte *)NativePtr + sizeof(IntPtr)); return IntPtr.Zero != UserContext ? GCHandle.FromIntPtr(UserContext).Target : null; } internal unsafe static void SetUserContext( IntPtr NativePtr, Object Obj) { Debug.Assert(IntPtr.Zero == *(IntPtr *)((Byte *)NativePtr + sizeof(IntPtr))); GCHandle Handle = GCHandle.Alloc(Obj, GCHandleType.Weak); *(IntPtr *)((Byte *)NativePtr + sizeof(IntPtr)) = (IntPtr)Handle; } internal unsafe static void DisposeUserContext( IntPtr NativePtr) { IntPtr UserContext = *(IntPtr *)((Byte *)NativePtr + sizeof(IntPtr)); Debug.Assert(IntPtr.Zero != UserContext); if (IntPtr.Zero != UserContext) { GCHandle.FromIntPtr(UserContext).Free(); *(IntPtr *)((Byte *)NativePtr + sizeof(IntPtr)) = IntPtr.Zero; } } private class FullContextHolder { public Object FileNode; public Object FileDesc; } internal static void GetFullContext(ref FullContext FullContext, out Object FileNode, out Object FileDesc) { FullContextHolder Holder = 0 != FullContext.UserContext2 ? (FullContextHolder)GCHandle.FromIntPtr((IntPtr)FullContext.UserContext2).Target : null; if (null != Holder) { FileNode = Holder.FileNode; FileDesc = Holder.FileDesc; } else { FileNode = null; FileDesc = null; } } internal static void SetFullContext(ref FullContext FullContext, Object FileNode, Object FileDesc) { Debug.Assert(0 == FullContext.UserContext && 0 == FullContext.UserContext2); FullContextHolder Holder = new FullContextHolder(); Holder.FileNode = FileNode; Holder.FileDesc = FileDesc; GCHandle Handle = GCHandle.Alloc(Holder, GCHandleType.Normal); FullContext.UserContext2 = (UInt64)(IntPtr)Handle; } internal static void DisposeFullContext(ref FullContext FullContext) { Debug.Assert(0 == FullContext.UserContext && 0 != FullContext.UserContext2); if (0 != FullContext.UserContext2) { GCHandle.FromIntPtr((IntPtr)FullContext.UserContext2).Free(); FullContext.UserContext2 = 0; } } internal unsafe static Int32 CopySecurityDescriptor( Byte[] SecurityDescriptorBytes, IntPtr SecurityDescriptor, IntPtr PSecurityDescriptorSize) { if (IntPtr.Zero != PSecurityDescriptorSize) { if (null != SecurityDescriptorBytes) { if (SecurityDescriptorBytes.Length > (int)*(IntPtr *)PSecurityDescriptorSize) { *(IntPtr *)PSecurityDescriptorSize = (IntPtr)SecurityDescriptorBytes.Length; return unchecked((Int32)0x80000005)/*STATUS_BUFFER_OVERFLOW*/; } *(IntPtr *)PSecurityDescriptorSize = (IntPtr)SecurityDescriptorBytes.Length; if (IntPtr.Zero != SecurityDescriptor) Marshal.Copy(SecurityDescriptorBytes, 0, SecurityDescriptor, SecurityDescriptorBytes.Length); } else *(IntPtr *)PSecurityDescriptorSize = IntPtr.Zero; } return 0/*STATUS_SUCCESS*/; } internal static Byte[] MakeSecurityDescriptor( IntPtr SecurityDescriptor) { if (IntPtr.Zero != SecurityDescriptor) { Byte[] SecurityDescriptorBytes = new Byte[GetSecurityDescriptorLength(SecurityDescriptor)]; Marshal.Copy(SecurityDescriptor, SecurityDescriptorBytes, 0, SecurityDescriptorBytes.Length); return SecurityDescriptorBytes; } else return null; } internal unsafe static byte[] ModifySecurityDescriptor( Byte[] SecurityDescriptorBytes, UInt32 SecurityInformation, Byte[] ModificationDescriptorBytes) { fixed (Byte *S = SecurityDescriptorBytes) fixed (Byte *M = ModificationDescriptorBytes) { IntPtr SecurityDescriptor; Int32 Result = FspSetSecurityDescriptor( (IntPtr)S, SecurityInformation, (IntPtr)M, out SecurityDescriptor); if (0 > Result) return null; SecurityDescriptorBytes = MakeSecurityDescriptor(SecurityDescriptor); FspDeleteSecurityDescriptor(SecurityDescriptor, _FspSetSecurityDescriptorPtr); return SecurityDescriptorBytes; } } internal unsafe static Int32 ModifySecurityDescriptorEx( Byte[] SecurityDescriptorBytes, UInt32 SecurityInformation, Byte[] ModificationDescriptorBytes, ref Byte[] ModifiedDescriptorBytes) { fixed (Byte *S = SecurityDescriptorBytes) fixed (Byte *M = ModificationDescriptorBytes) { IntPtr SecurityDescriptor; Int32 Result = FspSetSecurityDescriptor( (IntPtr)S, SecurityInformation, (IntPtr)M, out SecurityDescriptor); if (0 > Result) return Result; SecurityDescriptorBytes = MakeSecurityDescriptor(SecurityDescriptor); FspDeleteSecurityDescriptor(SecurityDescriptor, _FspSetSecurityDescriptorPtr); ModifiedDescriptorBytes = SecurityDescriptorBytes; return 0/*STATUS_SUCCESS*/; } } internal unsafe static Int32 CopyReparsePoint( Byte[] ReparseData, IntPtr Buffer, IntPtr PSize) { if (IntPtr.Zero != Buffer) { if (null != ReparseData) { if (ReparseData.Length > (int)*(UIntPtr *)PSize) return unchecked((Int32)0xc0000023)/*STATUS_BUFFER_TOO_SMALL*/; *(UIntPtr *)PSize = (UIntPtr)ReparseData.Length; Marshal.Copy(ReparseData, 0, Buffer, ReparseData.Length); } else *(UIntPtr *)PSize = UIntPtr.Zero; } return 0/*STATUS_SUCCESS*/; } internal static Byte[] MakeReparsePoint( IntPtr Buffer, UIntPtr Size) { if (IntPtr.Zero != Buffer) { Byte[] ReparseData = new Byte[(int)Size]; Marshal.Copy(Buffer, ReparseData, 0, ReparseData.Length); return ReparseData; } else return null; } internal unsafe static Int32 FspFileSystemCanReplaceReparsePoint( Byte[] CurrentReparseData, Byte[] ReplaceReparseData) { fixed (Byte *C = CurrentReparseData) fixed (Byte *R = ReplaceReparseData) return _FspFileSystemCanReplaceReparsePoint( (IntPtr)C, (UIntPtr)CurrentReparseData.Length, (IntPtr)R, (UIntPtr)ReplaceReparseData.Length); } internal static Int32 SetDebugLogFile(String FileName) { IntPtr Handle; if ("-" == FileName) Handle = GetStdHandle(unchecked((UInt32)(-12))/*STD_ERROR_HANDLE*/); else Handle = CreateFileW( FileName, (UInt32)FileSystemRights.AppendData, (UInt32)(FileShare.Read | FileShare.Write), IntPtr.Zero, (UInt32)FileMode.OpenOrCreate, (UInt32)FileAttributes.Normal, IntPtr.Zero); if ((IntPtr)(-1) == Handle) return FspNtStatusFromWin32((UInt32)Marshal.GetLastWin32Error()); Api.FspDebugLogSetHandle(Handle); return 0/*STATUS_SUCCESS*/; } internal static Version GetVersion() { UInt32 Version = 0; FspVersion(out Version); return new System.Version((Int32)Version >> 16, (Int32)Version & 0xFFFF); } /* initialization */ internal static String ProductName = "WinFsp"; internal static String ProductFileName = "winfsp"; private static IntPtr LoadDll() { String RegPath, DllName, DllPath; SYSTEM_INFO SystemInfo; GetSystemInfo(out SystemInfo); switch ((UInt32)SystemInfo.wProcessorArchitecture) { case SYSTEM_INFO.PROCESSOR_ARCHITECTURE_ARM64: RegPath = "HKEY_LOCAL_MACHINE\\SOFTWARE\\WOW6432Node\\" + ProductName; DllName = ProductFileName + "-a64.dll"; break; case SYSTEM_INFO.PROCESSOR_ARCHITECTURE_AMD64: RegPath = "HKEY_LOCAL_MACHINE\\SOFTWARE\\WOW6432Node\\" + ProductName; DllName = ProductFileName + "-x64.dll"; break; case SYSTEM_INFO.PROCESSOR_ARCHITECTURE_INTEL: default: RegPath = "HKEY_LOCAL_MACHINE\\SOFTWARE\\" + ProductName; DllName = ProductFileName + "-x86.dll"; break; } IntPtr Module; Module = LoadLibraryW(DllName); if (IntPtr.Zero == Module) { DllPath = Microsoft.Win32.Registry.GetValue(RegPath, "InstallDir", null) as String; if (null != DllPath) { DllPath = Path.Combine(DllPath, Path.Combine("bin", DllName)); Module = LoadLibraryW(DllPath); } if (IntPtr.Zero == Module) throw new DllNotFoundException("cannot load " + DllName); } return Module; } private static IntPtr GetEntryPointPtr(IntPtr Module, String Name) { IntPtr Proc = GetProcAddress(Module, Name); if (IntPtr.Zero == Proc) throw new EntryPointNotFoundException("cannot get entry point " + Name); return Proc; } private static T GetEntryPoint(IntPtr Module) { return (T)(object)Marshal.GetDelegateForFunctionPointer( GetEntryPointPtr(Module, typeof(T).Name), typeof(T)); } private static void LoadProto(IntPtr Module) { FspFileSystemPreflight = GetEntryPoint(Module); FspFileSystemCreate = GetEntryPoint(Module); FspFileSystemDelete = GetEntryPoint(Module); FspFileSystemSetMountPoint = GetEntryPoint(Module); _FspFileSystemSetMountPointEx = GetEntryPoint(Module); FspFileSystemRemoveMountPoint = GetEntryPoint(Module); FspFileSystemStartDispatcher = GetEntryPoint(Module); FspFileSystemStopDispatcher = GetEntryPoint(Module); FspFileSystemSendResponse = GetEntryPoint(Module); FspFileSystemNotifyBegin = GetEntryPoint(Module); FspFileSystemNotifyEnd = GetEntryPoint(Module); _FspFileSystemNotify = GetEntryPoint(Module); FspFileSystemGetOperationContext = GetEntryPoint(Module); FspFileSystemMountPoint = GetEntryPoint(Module); FspFileSystemSetOperationGuardStrategy = GetEntryPoint(Module); FspFileSystemSetDebugLog = GetEntryPoint(Module); FspFileSystemOperationProcessId = GetEntryPoint(Module); _FspFileSystemAddDirInfo = GetEntryPoint(Module); FspFileSystemFindReparsePoint = GetEntryPoint(Module); FspFileSystemResolveReparsePoints = GetEntryPoint(Module); _FspFileSystemCanReplaceReparsePoint = GetEntryPoint(Module); _FspFileSystemAddStreamInfo = GetEntryPoint(Module); _FspFileSystemAddEa = GetEntryPoint(Module); _FspFileSystemAddNotifyInfo = GetEntryPoint(Module); FspFileSystemStopServiceIfNecessary = GetEntryPoint(Module); FspFileSystemAcquireDirectoryBuffer = GetEntryPoint(Module); FspFileSystemFillDirectoryBuffer = GetEntryPoint(Module); FspFileSystemReleaseDirectoryBuffer = GetEntryPoint(Module); FspFileSystemReadDirectoryBuffer = GetEntryPoint(Module); FspFileSystemDeleteDirectoryBuffer = GetEntryPoint(Module); FspSetSecurityDescriptor = GetEntryPoint(Module); _FspSetSecurityDescriptorPtr = GetEntryPointPtr(Module, "FspSetSecurityDescriptor"); FspDeleteSecurityDescriptor = GetEntryPoint(Module); FspServiceCreate = GetEntryPoint(Module); FspServiceDelete = GetEntryPoint(Module); FspServiceAllowConsoleMode = GetEntryPoint(Module); FspServiceRequestTime = GetEntryPoint(Module); FspServiceSetExitCode = GetEntryPoint(Module); FspServiceGetExitCode = GetEntryPoint(Module); FspServiceLoop = GetEntryPoint(Module); FspServiceStop = GetEntryPoint(Module); FspServiceLog = GetEntryPoint(Module); FspVersion = GetEntryPoint(Module); FspNtStatusFromWin32 = GetEntryPoint(Module); FspWin32FromNtStatus = GetEntryPoint(Module); FspDebugLog = GetEntryPoint(Module); FspDebugLogSetHandle = GetEntryPoint(Module); } private static void CheckVersion() { FileVersionInfo Info; UInt32 Version = 0, VersionMajor, VersionMinor; Info = FileVersionInfo.GetVersionInfo(Assembly.GetExecutingAssembly().Location); FspVersion(out Version); VersionMajor = Version >> 16; VersionMinor = Version & 0xFFFF; if (Info.FileMajorPart != VersionMajor || Info.FileMinorPart > VersionMinor) throw new TypeLoadException(String.Format( "incorrect dll version (need {0}.{1}, have {2}.{3})", Info.FileMajorPart, Info.FileMinorPart, VersionMajor, VersionMinor)); } static Api() { #if false //DEBUG if (Debugger.IsAttached) Debugger.Break(); #endif object[] attributes = Assembly.GetExecutingAssembly().GetCustomAttributes( typeof(AssemblyProductAttribute), false); if (null != attributes && 0 < attributes.Length && null != attributes[0] as AssemblyProductAttribute) { ProductName = (attributes[0] as AssemblyProductAttribute).Product; ProductFileName = ProductName.ToLowerInvariant(); } LoadProto(LoadDll()); CheckVersion(); } [StructLayout(LayoutKind.Sequential)] private struct SYSTEM_INFO { internal const UInt32 PROCESSOR_ARCHITECTURE_INTEL = 0; internal const UInt32 PROCESSOR_ARCHITECTURE_MIPS = 1; internal const UInt32 PROCESSOR_ARCHITECTURE_ALPHA = 2; internal const UInt32 PROCESSOR_ARCHITECTURE_PPC = 3; internal const UInt32 PROCESSOR_ARCHITECTURE_SHX = 4; internal const UInt32 PROCESSOR_ARCHITECTURE_ARM = 5; internal const UInt32 PROCESSOR_ARCHITECTURE_IA64 = 6; internal const UInt32 PROCESSOR_ARCHITECTURE_ALPHA64 = 7; internal const UInt32 PROCESSOR_ARCHITECTURE_MSIL = 8; internal const UInt32 PROCESSOR_ARCHITECTURE_AMD64 = 9; internal const UInt32 PROCESSOR_ARCHITECTURE_IA32_ON_WIN64 = 10; internal const UInt32 PROCESSOR_ARCHITECTURE_NEUTRAL = 11; internal const UInt32 PROCESSOR_ARCHITECTURE_ARM64 = 12; internal const UInt32 PROCESSOR_ARCHITECTURE_ARM32_ON_WIN64 = 13; internal const UInt32 PROCESSOR_ARCHITECTURE_IA32_ON_ARM64 = 14; internal const UInt32 PROCESSOR_ARCHITECTURE_UNKNOWN = 0xFFFF; internal UInt16 wProcessorArchitecture; internal UInt16 wReserved; internal UInt32 dwPageSize; internal IntPtr lpMinimumApplicationAddress; internal IntPtr lpMaximumApplicationAddress; internal IntPtr dwActiveProcessorMask; internal UInt32 dwNumberOfProcessors; internal UInt32 dwProcessorType; internal UInt32 dwAllocationGranularity; internal UInt16 wProcessorLevel; internal UInt16 wProcessorRevision; } [DllImport("kernel32.dll", CallingConvention = CallingConvention.StdCall, SetLastError = true)] private static extern IntPtr LoadLibraryW( [MarshalAs(UnmanagedType.LPWStr)] String DllName); [DllImport("kernel32.dll", CallingConvention = CallingConvention.StdCall, SetLastError = true)] private static extern IntPtr GetProcAddress( IntPtr hModule, [MarshalAs(UnmanagedType.LPStr)] String lpProcName); [DllImport("kernel32.dll", CallingConvention = CallingConvention.StdCall, SetLastError = false)] private static extern void GetSystemInfo( out SYSTEM_INFO SystemInfo); [DllImport("advapi32.dll", CallingConvention = CallingConvention.StdCall)] private static extern UInt32 GetSecurityDescriptorLength(IntPtr SecurityDescriptor); [DllImport("kernel32.dll", CallingConvention = CallingConvention.StdCall, SetLastError = true)] private static extern IntPtr GetStdHandle(UInt32 nStdHandle); [DllImport("kernel32.dll", CallingConvention = CallingConvention.StdCall, SetLastError = true)] private static extern IntPtr CreateFileW( [MarshalAs(UnmanagedType.LPWStr)] String lpFileName, UInt32 dwDesiredAccess, UInt32 dwShareMode, IntPtr lpSecurityAttributes, UInt32 dwCreationDisposition, UInt32 dwFlagsAndAttributes, IntPtr hTemplateFile); } }