winfsp/src/dotnet/Interop.cs
2024-01-08 12:38:44 +00:00

1632 lines
70 KiB
C#

/*
* 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;
}
}
/// <summary>
/// Contains volume information about a file system.
/// </summary>
[StructLayout(LayoutKind.Sequential)]
public struct VolumeInfo
{
internal const int VolumeLabelSize = 32;
/// <summary>
/// Total size of volume in bytes.
/// </summary>
public UInt64 TotalSize;
/// <summary>
/// Free size of volume in bytes.
/// </summary>
public UInt64 FreeSize;
internal UInt16 VolumeLabelLength;
internal unsafe fixed UInt16 VolumeLabel[VolumeLabelSize];
/// <summary>
/// Sets the volume label.
/// </summary>
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);
}
}
}
/// <summary>
/// Contains metadata information about a file or directory.
/// </summary>
[StructLayout(LayoutKind.Sequential)]
public struct FileInfo
{
/// <summary>
/// The file or directory attributes.
/// </summary>
public UInt32 FileAttributes;
/// <summary>
/// The reparse tag of the file or directory.
/// This value is 0 if the file or directory is not a reparse point.
/// </summary>
public UInt32 ReparseTag;
/// <summary>
/// The allocation size of the file.
/// </summary>
public UInt64 AllocationSize;
/// <summary>
/// The file size of the file (end of file).
/// </summary>
public UInt64 FileSize;
/// <summary>
/// The time that the file or directory was created.
/// </summary>
public UInt64 CreationTime;
/// <summary>
/// The time that the file or directory was last accessed.
/// </summary>
public UInt64 LastAccessTime;
/// <summary>
/// The time that the file or direcotry was last modified.
/// </summary>
public UInt64 LastWriteTime;
/// <summary>
/// The time that the file or directory metadata was last modified.
/// </summary>
public UInt64 ChangeTime;
/// <summary>
/// A unique identifier that is associated with the file or directory.
/// Not all file systems support this value.
/// </summary>
public UInt64 IndexNumber;
/// <summary>
/// The number of hard links.
/// Not currently implemented. Set to 0.
/// </summary>
public UInt32 HardLinks;
/// <summary>
/// The extended attribute size of the file.
/// </summary>
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);
}
}
}
/// <summary>
/// Enumeration of all the possible values for NotifyInfo.Action
/// </summary>
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,
}
/// <summary>
/// Enumeration of all the possible values for NotifyInfo.Filter
/// </summary>
[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,
}
/// <summary>
/// Contains file change notification information.
/// </summary>
[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<T>(IntPtr Module)
{
return (T)(object)Marshal.GetDelegateForFunctionPointer(
GetEntryPointPtr(Module, typeof(T).Name), typeof(T));
}
private static void LoadProto(IntPtr Module)
{
FspFileSystemPreflight = GetEntryPoint<Proto.FspFileSystemPreflight>(Module);
FspFileSystemCreate = GetEntryPoint<Proto.FspFileSystemCreate>(Module);
FspFileSystemDelete = GetEntryPoint<Proto.FspFileSystemDelete>(Module);
FspFileSystemSetMountPoint = GetEntryPoint<Proto.FspFileSystemSetMountPoint>(Module);
_FspFileSystemSetMountPointEx = GetEntryPoint<Proto.FspFileSystemSetMountPointEx>(Module);
FspFileSystemRemoveMountPoint = GetEntryPoint<Proto.FspFileSystemRemoveMountPoint>(Module);
FspFileSystemStartDispatcher = GetEntryPoint<Proto.FspFileSystemStartDispatcher>(Module);
FspFileSystemStopDispatcher = GetEntryPoint<Proto.FspFileSystemStopDispatcher>(Module);
FspFileSystemSendResponse = GetEntryPoint<Proto.FspFileSystemSendResponse>(Module);
FspFileSystemNotifyBegin = GetEntryPoint<Proto.FspFileSystemNotifyBegin>(Module);
FspFileSystemNotifyEnd = GetEntryPoint<Proto.FspFileSystemNotifyEnd>(Module);
_FspFileSystemNotify = GetEntryPoint<Proto.FspFileSystemNotify>(Module);
FspFileSystemGetOperationContext = GetEntryPoint<Proto.FspFileSystemGetOperationContext>(Module);
FspFileSystemMountPoint = GetEntryPoint<Proto.FspFileSystemMountPointF>(Module);
FspFileSystemSetOperationGuardStrategy = GetEntryPoint<Proto.FspFileSystemSetOperationGuardStrategyF>(Module);
FspFileSystemSetDebugLog = GetEntryPoint<Proto.FspFileSystemSetDebugLogF>(Module);
FspFileSystemOperationProcessId = GetEntryPoint<Proto.FspFileSystemOperationProcessIdF>(Module);
_FspFileSystemAddDirInfo = GetEntryPoint<Proto.FspFileSystemAddDirInfo>(Module);
FspFileSystemFindReparsePoint = GetEntryPoint<Proto.FspFileSystemFindReparsePoint>(Module);
FspFileSystemResolveReparsePoints = GetEntryPoint<Proto.FspFileSystemResolveReparsePoints>(Module);
_FspFileSystemCanReplaceReparsePoint = GetEntryPoint<Proto.FspFileSystemCanReplaceReparsePoint>(Module);
_FspFileSystemAddStreamInfo = GetEntryPoint<Proto.FspFileSystemAddStreamInfo>(Module);
_FspFileSystemAddEa = GetEntryPoint<Proto.FspFileSystemAddEa>(Module);
_FspFileSystemAddNotifyInfo = GetEntryPoint<Proto.FspFileSystemAddNotifyInfo>(Module);
FspFileSystemStopServiceIfNecessary = GetEntryPoint<Proto.FspFileSystemStopServiceIfNecessary>(Module);
FspFileSystemAcquireDirectoryBuffer = GetEntryPoint<Proto.FspFileSystemAcquireDirectoryBuffer>(Module);
FspFileSystemFillDirectoryBuffer = GetEntryPoint<Proto.FspFileSystemFillDirectoryBuffer>(Module);
FspFileSystemReleaseDirectoryBuffer = GetEntryPoint<Proto.FspFileSystemReleaseDirectoryBuffer>(Module);
FspFileSystemReadDirectoryBuffer = GetEntryPoint<Proto.FspFileSystemReadDirectoryBuffer>(Module);
FspFileSystemDeleteDirectoryBuffer = GetEntryPoint<Proto.FspFileSystemDeleteDirectoryBuffer>(Module);
FspSetSecurityDescriptor = GetEntryPoint<Proto.FspSetSecurityDescriptor>(Module);
_FspSetSecurityDescriptorPtr = GetEntryPointPtr(Module, "FspSetSecurityDescriptor");
FspDeleteSecurityDescriptor = GetEntryPoint<Proto.FspDeleteSecurityDescriptor>(Module);
FspServiceCreate = GetEntryPoint<Proto.FspServiceCreate>(Module);
FspServiceDelete = GetEntryPoint<Proto.FspServiceDelete>(Module);
FspServiceAllowConsoleMode = GetEntryPoint<Proto.FspServiceAllowConsoleMode>(Module);
FspServiceRequestTime = GetEntryPoint<Proto.FspServiceRequestTime>(Module);
FspServiceSetExitCode = GetEntryPoint<Proto.FspServiceSetExitCode>(Module);
FspServiceGetExitCode = GetEntryPoint<Proto.FspServiceGetExitCode>(Module);
FspServiceLoop = GetEntryPoint<Proto.FspServiceLoop>(Module);
FspServiceStop = GetEntryPoint<Proto.FspServiceStop>(Module);
FspServiceLog = GetEntryPoint<Proto.FspServiceLog>(Module);
FspVersion = GetEntryPoint<Proto.FspVersion>(Module);
FspNtStatusFromWin32 = GetEntryPoint<Proto.FspNtStatusFromWin32>(Module);
FspWin32FromNtStatus = GetEntryPoint<Proto.FspWin32FromNtStatus>(Module);
FspDebugLog = GetEntryPoint<Proto.FspDebugLog>(Module);
FspDebugLogSetHandle = GetEntryPoint<Proto.FspDebugLogSetHandle>(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);
}
}