Files
Explorer-Workbench/src/Explorer.Windows/CloudFilesNative.cs
netquick e9aba73552 Add Explorer Workbench with hierarchical, off-UI Storage analysis.
Storage queries run in the background with cancellation and covering indexes so switching views no longer freezes the UI.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-08-22 12:43:05 +02:00

161 lines
4.4 KiB
C#

using System.Runtime.InteropServices;
using Explorer.Domain;
namespace Explorer.Windows;
public static partial class CloudFilesNative
{
public const uint PlaceholderNone = 0;
public const uint Placeholder = 0x1;
public const uint PlaceholderSyncRoot = 0x2;
public const uint PlaceholderInSync = 0x8;
public const uint PlaceholderPartial = 0x10;
public const uint PlaceholderPartiallyOnDisk = 0x20;
public const uint PlaceholderInvalid = 0xFFFFFFFF;
public const int PinUnspecified = 0;
public const int PinPinned = 1;
public const int PinUnpinned = 2;
public const int PinExcluded = 3;
public const int PinInherit = 4;
public static nint OpenNoRecall(string path)
=> NativeMethods.CreateFile(
PathRules.ToExtended(path),
NativeMethods.FileReadAttributes,
NativeMethods.FileShareRead | NativeMethods.FileShareWrite | NativeMethods.FileShareDelete,
0,
NativeMethods.OpenExisting,
NativeMethods.SafeOpenFlags,
0);
public static bool IsInvalid(nint handle)
=> handle == nint.Zero || handle == new nint(-1);
public static long? TryGetAllocatedSize(string path)
{
var handle = OpenNoRecall(path);
if (IsInvalid(handle))
{
return null;
}
try
{
return TryGetAllocatedSize(handle);
}
finally
{
NativeMethods.CloseHandle(handle);
}
}
public static long? TryGetAllocatedSize(nint handle)
{
var size = Marshal.SizeOf<FileStandardInfo>();
var buffer = Marshal.AllocHGlobal(size);
try
{
if (!NativeMethods.GetFileInformationByHandleEx(handle, NativeMethods.FileStandardInfo, buffer, (uint)size))
{
return null;
}
var info = Marshal.PtrToStructure<FileStandardInfo>(buffer);
return info.AllocationSize;
}
catch
{
return null;
}
finally
{
Marshal.FreeHGlobal(buffer);
}
}
public static uint? TryGetPlaceholderState(int attributes, int reparseTag)
{
try
{
return CfGetPlaceholderStateFromAttributeTag((uint)attributes, (uint)reparseTag);
}
catch (DllNotFoundException)
{
return null;
}
catch (EntryPointNotFoundException)
{
return null;
}
}
public static bool TrySetPinState(string path, int pinState)
{
var handle = OpenNoRecall(path);
if (IsInvalid(handle))
{
return false;
}
try
{
return CfSetPinState(handle, pinState, 0, nint.Zero) == 0;
}
catch (DllNotFoundException)
{
return false;
}
catch (EntryPointNotFoundException)
{
return false;
}
finally
{
NativeMethods.CloseHandle(handle);
}
}
public static bool IsCloudSyncRoot(string path)
{
try
{
uint returned = 0;
var hr = CfGetSyncRootInfoByPath(path, 0, nint.Zero, 0, ref returned);
const int insufficientBuffer = unchecked((int)0x8007007A);
return hr == 0 || (hr == insufficientBuffer && returned > 0);
}
catch (DllNotFoundException)
{
return false;
}
catch (EntryPointNotFoundException)
{
return false;
}
catch
{
return false;
}
}
[LibraryImport("cldapi.dll")]
private static partial uint CfGetPlaceholderStateFromAttributeTag(uint fileAttributes, uint reparseTag);
[DllImport("cldapi.dll", ExactSpelling = true)]
private static extern int CfSetPinState(nint fileHandle, int pinState, uint pinFlags, nint overlapped);
[DllImport("cldapi.dll", CharSet = CharSet.Unicode, ExactSpelling = true)]
private static extern int CfGetSyncRootInfoByPath(string filePath, int infoClass, nint infoBuffer, uint infoBufferLength, ref uint returnedLength);
[StructLayout(LayoutKind.Sequential)]
private struct FileStandardInfo
{
public long AllocationSize;
public long EndOfFile;
public uint NumberOfLinks;
public byte DeletePending;
public byte Directory;
}
}