Skip to content

Instantly share code, notes, and snippets.

@secdev02
Forked from udaken/ProjectedFSLib.cs
Created June 24, 2024 13:57
Show Gist options
  • Select an option

  • Save secdev02/ecd91a44d8dac4f124f169569b140466 to your computer and use it in GitHub Desktop.

Select an option

Save secdev02/ecd91a44d8dac4f124f169569b140466 to your computer and use it in GitHub Desktop.
using System;
using System.Runtime.InteropServices;
using Microsoft.Win32.SafeHandles;
namespace ProjectedFSLib
{
static class Native
{
public static T? PtrToStructure<T>(IntPtr ptr) where T : struct
=> ptr == IntPtr.Zero ? default : Marshal.PtrToStructure<T>(ptr);
}
public enum HResult : int
{
Ok = 0,
Pending = -2147023899,
OutOfMemory = -2147024882,
InsufficientBuffer = -2147024774,
FileNotFound = -2147024894,
VirtualizationUnavaliable = -2147024527,
InternalError = -2147023537,
AlreadyInitialized = -2147023649,
AccessDenied = -2147024891,
CannotDelete = -805306079,
Directory = -2147024629,
DirNotEmpty = -2147024751,
Handle = -2147024890,
InvalidArg = -2147024809,
PathNotFound = -2147024893,
ReparsePointEncountered = -2147020501,
VirtualizationInvalidOp = -2147024511
}
#region Common structures
/// <summary>
/// PRJ_NOTIFY_TYPES
/// </summary>
[Flags]
public enum PRJ_NOTIFY_TYPES : uint
{
NONE = 0x00000000,
SUPPRESS_NOTIFICATIONS = 0x00000001,
FILE_OPENED = 0x00000002,
NEW_FILE_CREATED = 0x00000004,
FILE_OVERWRITTEN = 0x00000008,
PRE_DELETE = 0x00000010,
PRE_RENAME = 0x00000020,
PRE_SET_HARDLINK = 0x00000040,
FILE_RENAMED = 0x00000080,
HARDLINK_CREATED = 0x00000100,
FILE_HANDLE_CLOSED_NO_MODIFICATION = 0x00000200,
FILE_HANDLE_CLOSED_FILE_MODIFIED = 0x00000400,
FILE_HANDLE_CLOSED_FILE_DELETED = 0x00000800,
FILE_PRE_CONVERT_TO_FULL = 0x00001000,
USE_EXISTING_MASK = 0xFFFFFFFF,
}
/// <summary>
/// PRJ_NOTIFICATION
/// </summary>
[Flags]
public enum PRJ_NOTIFICATION
{
FILE_OPENED = 0x00000002,
NEW_FILE_CREATED = 0x00000004,
FILE_OVERWRITTEN = 0x00000008,
PRE_DELETE = 0x00000010,
PRE_RENAME = 0x00000020,
PRE_SET_HARDLINK = 0x00000040,
FILE_RENAMED = 0x00000080,
HARDLINK_CREATED = 0x00000100,
FILE_HANDLE_CLOSED_NO_MODIFICATION = 0x00000200,
FILE_HANDLE_CLOSED_FILE_MODIFIED = 0x00000400,
FILE_HANDLE_CLOSED_FILE_DELETED = 0x00000800,
FILE_PRE_CONVERT_TO_FULL = 0x00001000,
}
[StructLayout(LayoutKind.Sequential)]
public struct PRJ_NAMESPACE_VIRTUALIZATION_CONTEXT
{
public IntPtr Pointer;
}
public struct PRJ_DIR_ENTRY_BUFFER_HANDLE
{
public IntPtr Pointer;
}
#endregion
#region Virtualization instance APIs
[StructLayout(LayoutKind.Sequential)]
public struct PRJ_NOTIFICATION_MAPPING
{
public PRJ_NOTIFY_TYPES NotificationBitMask;
//[MarshalAs(UnmanagedType.LPWStr)]
public IntPtr NotificationRoot;
}
public enum StartvirtualizingFlags
{
NONE = 0x00000000,
USE_NEGATIVE_PATH_CACHE = 0x00000001,
}
[StructLayout(LayoutKind.Sequential)]
public struct PRJ_STARTVIRTUALIZING_OPTIONS
{
public StartvirtualizingFlags Flags;
public uint PoolThreadCount;
public uint ConcurrentThreadCount;
//PRJ_NOTIFICATION_MAPPING
public IntPtr NotificationMappings;
[MarshalAs(UnmanagedType.U4)]
public int NotificationMappingsCount;
}
[StructLayout(LayoutKind.Sequential)]
public struct PRJ_VIRTUALIZATION_INSTANCE_INFO
{
public Guid InstanceID;
public uint WriteAlignment;
}
internal static partial class ProjectedFSLib
{
private const string dllName = "projectedfslib.dll";
/*
STDAPI
PrjStartVirtualizing(
_In_ PCWSTR virtualizationRootPath,
_In_ const PRJ_CALLBACKS* callbacks,
_In_opt_ const void* instanceContext,
_In_opt_ const PRJ_STARTVIRTUALIZING_OPTIONS* options,
_Outptr_ PRJ_NAMESPACE_VIRTUALIZATION_CONTEXT* namespaceVirtualizationContext
);
*/
[DllImport(dllName, CharSet = CharSet.Unicode, PreserveSig = false)]
public static extern void PrjStartVirtualizing(
string virtualizationRootPath,
in PRJ_CALLBACKS callbacks,
[Optional] IntPtr instanceContext,
[Optional] in PRJ_STARTVIRTUALIZING_OPTIONS options,
out PRJ_NAMESPACE_VIRTUALIZATION_CONTEXT namespaceVirtualizationContext
);
[DllImport(dllName, PreserveSig = true)]
public static extern void PrjStopVirtualizing(
PRJ_NAMESPACE_VIRTUALIZATION_CONTEXT namespaceVirtualizationContext
);
[DllImport(dllName, CharSet = CharSet.Unicode, PreserveSig = false)]
public static extern void PrjClearNegativePathCache(
PRJ_NAMESPACE_VIRTUALIZATION_CONTEXT namespaceVirtualizationContext,
out uint totalEntryNumber
);
/*
STDAPI
PrjGetVirtualizationInstanceInfo(
_In_ PRJ_NAMESPACE_VIRTUALIZATION_CONTEXT namespaceVirtualizationContext,
_Out_ PRJ_VIRTUALIZATION_INSTANCE_INFO* virtualizationInstanceInfo
);
*/
[DllImport(dllName, CharSet = CharSet.Unicode, PreserveSig = false)]
public static extern void PrjGetVirtualizationInstanceInfo(
PRJ_NAMESPACE_VIRTUALIZATION_CONTEXT namespaceVirtualizationContext,
out PRJ_VIRTUALIZATION_INSTANCE_INFO virtualizationInstanceInfo
);
}
#endregion
#region region Placeholder and File APIs
public enum PRJ_PLACEHOLDER_ID
{
PRJ_PLACEHOLDER_ID_LENGTH = 128
}
[StructLayout(LayoutKind.Sequential)]
public struct PRJ_PLACEHOLDER_VERSION_INFO
{
[MarshalAs(UnmanagedType.ByValArray, SizeConst = (int)PRJ_PLACEHOLDER_ID.PRJ_PLACEHOLDER_ID_LENGTH)]
public byte[] ProviderID;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = (int)PRJ_PLACEHOLDER_ID.PRJ_PLACEHOLDER_ID_LENGTH)]
public byte[] ContentID;
}
static partial class ProjectedFSLib
{
[DllImport(dllName, CharSet = CharSet.Unicode, PreserveSig = false)]
public static extern void PrjMarkDirectoryAsPlaceholder(
string rootPathName,
[Optional] string targetPathName,
[Optional] IntPtr versionInfo,
in Guid virtualizationInstanceID
);
[DllImport(dllName, CharSet = CharSet.Unicode, PreserveSig = false)]
public static extern void PrjMarkDirectoryAsPlaceholder(
string rootPathName,
[Optional] string targetPathName,
[Optional] in PRJ_PLACEHOLDER_VERSION_INFO versionInfo,
in Guid virtualizationInstanceID
);
}
[StructLayout(LayoutKind.Sequential)]
public struct PRJ_FILE_BASIC_INFO
{
[MarshalAs(UnmanagedType.U1)]
public bool IsDirectory;
public long FileSize;
public long CreationTime;
public long LastAccessTime;
public long LastWriteTime;
public long ChangeTime;
public uint FileAttributes;
}
[StructLayout(LayoutKind.Sequential)]
public struct PRJ_PLACEHOLDER_INFO
{
public PRJ_FILE_BASIC_INFO FileBasicInfo;
public struct EaInformation_
{
public uint EaBufferSize;
public uint OffsetToFirstEa;
}
public EaInformation_ EaInformation;
public struct SecurityInformation_
{
public uint SecurityBufferSize;
public uint OffsetToSecurityDescriptor;
}
public SecurityInformation_ SecurityInformation;
public struct StreamsInformation_
{
public uint StreamsInfoBufferSize;
public uint OffsetToFirstStreamInfo;
}
public StreamsInformation_ StreamsInformation;
public PRJ_PLACEHOLDER_VERSION_INFO VersionInfo;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 1)]
public byte[] VariableData;
}
static partial class ProjectedFSLib
{
[DllImport(dllName, CharSet = CharSet.Unicode, PreserveSig = false)]
public static extern void PrjWritePlaceholderInfo(
PRJ_NAMESPACE_VIRTUALIZATION_CONTEXT namespaceVirtualizationContext,
string destinationFileName,
// PRJ_PLACEHOLDER_INFO
IntPtr placeholderInfo,
uint placeholderInfoSize
);
}
[Flags]
public enum PRJ_UPDATE_TYPES
{
NONE = 0x00000000,
ALLOW_DIRTY_METADATA = 0x00000001,
ALLOW_DIRTY_DATA = 0x00000002,
ALLOW_TOMBSTONE = 0x00000004,
RESERVED1 = 0x00000008,
RESERVED2 = 0x00000010,
ALLOW_READ_ONLY = 0x00000020,
MAX_VAL = (ALLOW_READ_ONLY << 1),
}
[Flags]
public enum PRJ_UPDATE_FAILURE_CAUSES
{
NONE = 0x00000000,
DIRTY_METADATA = 0x00000001,
DIRTY_DATA = 0x00000002,
TOMBSTONE = 0x00000004,
READ_ONLY = 0x00000008,
}
static partial class ProjectedFSLib
{
[DllImport(dllName, CharSet = CharSet.Unicode, PreserveSig = false)]
public static extern void PrjUpdateFileIfNeeded(
PRJ_NAMESPACE_VIRTUALIZATION_CONTEXT namespaceVirtualizationContext,
string destinationFileName,
// PRJ_PLACEHOLDER_INFO
IntPtr placeholderInfo,
uint placeholderInfoSize,
[Optional] PRJ_UPDATE_TYPES updateFlags,
[Optional] out PRJ_UPDATE_FAILURE_CAUSES failureReason
);
[DllImport(dllName, CharSet = CharSet.Unicode, PreserveSig = false)]
public static extern void PrjDeleteFile(
PRJ_NAMESPACE_VIRTUALIZATION_CONTEXT namespaceVirtualizationContext,
string destinationFileName,
[Optional] PRJ_UPDATE_TYPES updateFlags,
[Optional] out PRJ_UPDATE_FAILURE_CAUSES failureReason
);
[DllImport(dllName, CharSet = CharSet.Unicode, PreserveSig = false)]
public static extern void PrjWriteFileData(
PRJ_NAMESPACE_VIRTUALIZATION_CONTEXT namespaceVirtualizationContext,
in Guid dataStreamId,
IntPtr buffer,
ulong byteOffset,
uint length
);
}
[Flags]
public enum PRJ_FILE_STATE
{
PLACEHOLDER = 0x00000001,
HYDRATED_PLACEHOLDER = 0x00000002,
DIRTY_PLACEHOLDER = 0x00000004,
FULL = 0x00000008,
TOMBSTONE = 0x00000010,
}
static partial class ProjectedFSLib
{
[DllImport(dllName, CharSet = CharSet.Unicode, PreserveSig = false)]
public static extern void PrjGetOnDiskFileState(
string destinationFileName,
out PRJ_FILE_STATE fileState
);
[DllImport(dllName, CharSet = CharSet.Unicode, PreserveSig = true)]
public static extern SafeAlignedBuffer PrjAllocateAlignedBuffer(
PRJ_NAMESPACE_VIRTUALIZATION_CONTEXT namespaceVirtualizationContext,
[MarshalAs(UnmanagedType.SysUInt)]ulong size
);
[DllImport(dllName, CharSet = CharSet.Unicode, PreserveSig = true)]
public static extern void PrjFreeAlignedBuffer(
IntPtr buffer
);
}
#endregion
#region Callback support
[Flags]
public enum PRJ_CALLBACK_DATA_FLAGS
{
ENUM_RESTART_SCAN = 0x00000001,
ENUM_RETURN_SINGLE_ENTRY = 0x00000002
}
[StructLayout(LayoutKind.Sequential)]
public struct PRJ_CALLBACK_DATA
{
public uint Size;
public PRJ_CALLBACK_DATA_FLAGS Flags;
public PRJ_NAMESPACE_VIRTUALIZATION_CONTEXT NamespaceVirtualizationContext;
public int CommandId;
public Guid FileId;
public Guid DataStreamId;
[MarshalAs(UnmanagedType.LPWStr)]
public string FilePathName;
readonly IntPtr _VersionInfo;
public PRJ_PLACEHOLDER_VERSION_INFO? VersionInfo
=> Native.PtrToStructure<PRJ_PLACEHOLDER_VERSION_INFO>(_VersionInfo);
public uint TriggeringProcessId;
[MarshalAs(UnmanagedType.LPWStr)]
public string TriggeringProcessImageFileName;
public IntPtr InstanceContext;
}
public delegate HResult PRJ_START_DIRECTORY_ENUMERATION_CB(
in PRJ_CALLBACK_DATA callbackData,
in Guid enumerationId
);
public delegate HResult PRJ_GET_DIRECTORY_ENUMERATION_CB(
in PRJ_CALLBACK_DATA callbackData,
in Guid enumerationId,
[Optional] string searchExpression,
PRJ_DIR_ENTRY_BUFFER_HANDLE dirEntryBufferHandle
);
public delegate HResult PRJ_END_DIRECTORY_ENUMERATION_CB(
in PRJ_CALLBACK_DATA callbackData,
in Guid enumerationId
);
public delegate HResult PRJ_GET_PLACEHOLDER_INFO_CB(
in PRJ_CALLBACK_DATA callbackData
);
public delegate HResult PRJ_GET_FILE_DATA_CB(
in PRJ_CALLBACK_DATA callbackData,
ulong byteOffset,
uint length
);
public delegate HResult PRJ_QUERY_FILE_NAME_CB(
in PRJ_CALLBACK_DATA callbackData
);
[StructLayout(LayoutKind.Explicit)]
public struct PRJ_NOTIFICATION_PARAMETERS
{
public struct PostCreate_
{
public PRJ_NOTIFY_TYPES NotificationMask;
}
[FieldOffset(0)]
public PostCreate_ PostCreate;
public struct FileRenamed_
{
public PRJ_NOTIFY_TYPES NotificationMask;
}
[FieldOffset(0)]
public FileRenamed_ FileRenamed;
public struct FileDeletedOnHandleClose_
{
[MarshalAs(UnmanagedType.U1)]
public bool IsFileModified;
}
[FieldOffset(0)]
public FileDeletedOnHandleClose_ FileDeletedOnHandleClose;
}
public delegate HResult PRJ_NOTIFICATION_CB(
in PRJ_CALLBACK_DATA callbackData,
[MarshalAs(UnmanagedType.U1)] bool isDirectory,
PRJ_NOTIFICATION notification,
[Optional] string destinationFileName,
[Optional] in PRJ_NOTIFICATION_PARAMETERS operationParameters
);
public delegate void PRJ_CANCEL_COMMAND_CB(
in PRJ_CALLBACK_DATA callbackData
);
public struct PRJ_CALLBACKS
{
[MarshalAs(UnmanagedType.FunctionPtr)]
public PRJ_START_DIRECTORY_ENUMERATION_CB StartDirectoryEnumerationCallback;
[MarshalAs(UnmanagedType.FunctionPtr)]
public PRJ_END_DIRECTORY_ENUMERATION_CB EndDirectoryEnumerationCallback;
[MarshalAs(UnmanagedType.FunctionPtr)]
public PRJ_GET_DIRECTORY_ENUMERATION_CB GetDirectoryEnumerationCallback;
[MarshalAs(UnmanagedType.FunctionPtr)]
public PRJ_GET_PLACEHOLDER_INFO_CB GetPlaceholderInfoCallback;
[MarshalAs(UnmanagedType.FunctionPtr)]
public PRJ_GET_FILE_DATA_CB GetFileDataCallback;
[MarshalAs(UnmanagedType.FunctionPtr)]
public PRJ_QUERY_FILE_NAME_CB QueryFileNameCallback;
[MarshalAs(UnmanagedType.FunctionPtr)]
public PRJ_NOTIFICATION_CB NotificationCallback;
[MarshalAs(UnmanagedType.FunctionPtr)]
public PRJ_CANCEL_COMMAND_CB CancelCommandCallback;
}
public enum PRJ_COMPLETE_COMMAND_TYPE
{
NOTIFICATION = 1,
ENUMERATION = 2
}
[StructLayout(LayoutKind.Explicit)]
public struct PRJ_COMPLETE_COMMAND_EXTENDED_PARAMETERS
{
[FieldOffset(0)]
public PRJ_COMPLETE_COMMAND_TYPE CommandType;
public struct Notification_
{
public PRJ_NOTIFY_TYPES NotificationMask;
}
[FieldOffset(4)]
public Notification_ Notification;
public struct Enumeration_
{
public PRJ_DIR_ENTRY_BUFFER_HANDLE DirEntryBufferHandle;
}
[FieldOffset(4)]
public Enumeration_ Enumeration;
}
static partial class ProjectedFSLib
{
[DllImport(dllName, CharSet = CharSet.Unicode, PreserveSig = false)]
public static extern void PrjCompleteCommand(
PRJ_NAMESPACE_VIRTUALIZATION_CONTEXT namespaceVirtualizationContext,
int commandId,
HResult completionResult,
[Optional] in PRJ_COMPLETE_COMMAND_EXTENDED_PARAMETERS extendedParameters
);
#endregion
#region Enumeration APIs
[DllImport(dllName, CharSet = CharSet.Unicode, PreserveSig = false)]
public static extern void PrjFillDirEntryBuffer(
string fileName,
[Optional] in PRJ_FILE_BASIC_INFO fileBasicInfo,
PRJ_DIR_ENTRY_BUFFER_HANDLE dirEntryBufferHandle
);
[DllImport(dllName, CharSet = CharSet.Unicode, PreserveSig = true)]
[return: MarshalAs(UnmanagedType.U1)]
public static extern bool PrjFileNameMatch(
string fileNameToCheck,
string pattern
);
[DllImport(dllName, CharSet = CharSet.Unicode, PreserveSig = true)]
public static extern int PrjFileNameCompare(
string fileName1,
string fileName2
);
[DllImport(dllName, CharSet = CharSet.Unicode, PreserveSig = true)]
[return: MarshalAs(UnmanagedType.U1)]
public static extern bool PrjDoesNameContainWildCards(
string fileName
);
}
#endregion
public class SafeAlignedBuffer : SafeBuffer
{
protected SafeAlignedBuffer(bool ownsHandle) : base(ownsHandle)
{
}
protected override bool ReleaseHandle()
{
if(handle != IntPtr.Zero)
ProjectedFSLib.PrjFreeAlignedBuffer(handle);
return true;
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment