in simpleProviderManaged/FileSystemApi.cs [108:208]
private static extern bool DeviceIoControl(
SafeFileHandle deviceHandle,
uint ioControlCode,
IntPtr inputBuffer,
int inputBufferSize,
IntPtr outputBuffer,
int outputBufferSize,
out int bytesReturned,
IntPtr overlapped);
[DllImport("kernel32.dll", SetLastError = true, CharSet = CharSet.Unicode, ExactSpelling = true)]
private static extern SafeFileHandle CreateFileW(
string lpFileName,
FileDesiredAccess dwDesiredAccess,
FileShare dwShareMode,
IntPtr lpSecurityAttributes,
FileMode dwCreationDisposition,
FileFlagsAndAttributes dwFlagsAndAttributes,
IntPtr hTemplateFile);
[DllImport("kernel32.dll", SetLastError = true, CharSet = CharSet.Unicode, ExactSpelling = true)]
private static extern int CreateSymbolicLinkW(string lpSymlinkFileName, string lpTargetFileName, SymbolicLinkOptions dwFlags);
[DllImport("shlwapi.dll", SetLastError = true, CharSet = CharSet.Unicode, ExactSpelling = true)]
private static extern bool PathRelativePathToW(
System.Text.StringBuilder pszPath,
string pszFrom,
FileFlagsAndAttributes dwAttrFrom,
string pszTo,
FileFlagsAndAttributes dwAttrTo);
private static unsafe string GetReparsePointTarget(SafeFileHandle handle)
{
string targetPath = string.Empty;
int bufferSize = INITIAL_REPARSE_DATA_BUFFER_SIZE;
int errorCode = ERROR_INSUFFICIENT_BUFFER;
byte[] buffer = null;
while (errorCode == ERROR_MORE_DATA || errorCode == ERROR_INSUFFICIENT_BUFFER)
{
buffer = new byte[bufferSize];
bool success = false;
fixed (byte* pBuffer = buffer)
{
int bufferReturnedSize;
success = DeviceIoControl(
handle,
FSCTL_GET_REPARSE_POINT,
IntPtr.Zero,
0,
(IntPtr)pBuffer,
bufferSize,
out bufferReturnedSize,
IntPtr.Zero);
}
bufferSize *= 2;
errorCode = success ? 0 : Marshal.GetLastWin32Error();
}
if (errorCode != 0)
{
throw new Win32Exception(errorCode, "DeviceIoControl(FSCTL_GET_REPARSE_POINT)");
}
// Now get the offsets in the REPARSE_DATA_BUFFER buffer string based on
// the offsets for the different type of reparse points.
const uint PrintNameOffsetIndex = 12;
const uint PrintNameLengthIndex = 14;
const uint SubsNameOffsetIndex = 8;
const uint SubsNameLengthIndex = 10;
fixed (byte* pBuffer = buffer)
{
uint reparsePointTag = *(uint*)(pBuffer);
if (reparsePointTag != (uint)DwReserved0Flag.IO_REPARSE_TAG_SYMLINK
&& reparsePointTag != (uint)DwReserved0Flag.IO_REPARSE_TAG_MOUNT_POINT)
{
throw new NotSupportedException($"Reparse point tag {reparsePointTag:X} not supported");
}
uint pathBufferOffsetIndex = (uint)((reparsePointTag == (uint)DwReserved0Flag.IO_REPARSE_TAG_SYMLINK) ? 20 : 16);
char* nameStartPtr = (char*)(pBuffer + pathBufferOffsetIndex);
int nameOffset = *(short*)(pBuffer + PrintNameOffsetIndex) / 2;
int nameLength = *(short*)(pBuffer + PrintNameLengthIndex) / 2;
targetPath = new string(nameStartPtr, nameOffset, nameLength);
if (string.IsNullOrWhiteSpace(targetPath))
{
nameOffset = *(short*)(pBuffer + SubsNameOffsetIndex) / 2;
nameLength = *(short*)(pBuffer + SubsNameLengthIndex) / 2;
targetPath = new string(nameStartPtr, nameOffset, nameLength);
}
}
return targetPath;
}