Ran*_*etz 4 c# winapi reparsepoint deviceiocontrol windows-10
我使用下面的代码在我的应用程序中检索重新分析点信息。这对于符号链接和连接非常有效,但对于 OneDrive 文件夹及其所有子项目来说会失败,并显示“不是重新分析点”。
using (SafeFileHandle srcHandle = NativeMethods.CreateFile(@"C:\Users\UserName\OneDrive",
0,
System.IO.FileShare.Read,
IntPtr.Zero,
System.IO.FileMode.Open,
NativeMethods.FileFlags.BackupSemantics | NativeMethods.FileFlags.OpenReparsePoint,
IntPtr.Zero))
{
if (!srcHandle.IsInvalid)
{
NativeMethods.REPARSE_DATA_BUFFER rdb = new NativeMethods.REPARSE_DATA_BUFFER();
IntPtr pMem = Marshal.AllocHGlobal(Marshal.SizeOf(rdb) + sizeof(uint) + sizeof(ushort) + sizeof(ushort) + 0xFFFF);
var outBufferSize = Marshal.SizeOf(typeof(NativeMethods.REPARSE_DATA_BUFFER));
var outBuffer = Marshal.AllocHGlobal(outBufferSize);
// Determine if it's a symbolic link or a junction point
try
{
int bytesRet = 0;
if (NativeMethods.DeviceIoControl(srcHandle, NativeMethods.FSCTL_GET_REPARSE_POINT, IntPtr.Zero, 0, outBuffer, outBufferSize, ref bytesRet, IntPtr.Zero) != 0)
{
rdb = (NativeMethods.REPARSE_DATA_BUFFER)Marshal.PtrToStructure(pMem, rdb.GetType());
...
}
else // Fails with ERROR_NOT_A_REPARSE_POINT** (0x1126) on OneDrive folder and all it's child items
{
log.LogError("FSCTL_GET_REPARSE_POINT error=" + Marshal.GetHRForLastWin32Error());
}
}
catch (Exception e1)
{
log.LogError("FSCTL_GET_REPARSE_POINT exception error=" + e1.Message + " -> GetLastWin32Error=" + Marshal.GetLastWin32Error().ToString());
}
finally
{
Marshal.FreeHGlobal(pMem);
}
}
}
Run Code Online (Sandbox Code Playgroud)
本机声明:
[DllImport("kernel32.dll", EntryPoint = "CreateFile", SetLastError = true, CharSet = CharSet.Unicode)]
public static extern SafeFileHandle CreateFile(string fileName, FileAccessAPI desiredAccess, FileShare shareMode, IntPtr secAttrib, FileMode createDisp, FileFlags flags, IntPtr template);
public const int FSCTL_GET_REPARSE_POINT = 0x000900A8;
[DllImport("kernel32.dll", SetLastError = true, CharSet = CharSet.Unicode)]
public static extern unsafe int DeviceIoControl(SafeFileHandle hFile,
int control,
IntPtr inbuffer,
int bufferSize,
IntPtr outBuffer,
int outBufferSize,
ref int bytesRet,
IntPtr overlapped);
public const uint RP_SYMBOLICLINK = 0xA000000C;
public const uint RP_JUNCTION = 0xA0000003;
public const uint RP_REPARSETAG_WCI = 0x80000018;
public const uint RP_REPARSETAG_APP = 0x8000001b;
public const uint RP_CLOUD = 0x9000001A;
public const uint RP_CLOUD_1 = 0x9000101A;
...
[StructLayout(LayoutKind.Sequential)]
public struct REPARSE_DATA_BUFFER
{
public uint ReparseTag;
public ushort ReparseDataLength;
public ushort Reserved;
public ushort SubstituteNameOffset;
public ushort SubstituteNameLength;
public ushort PrintNameOffset;
public ushort PrintNameLength;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 0xFFF0)]
public byte[] PathBuffer;
}
[Flags()]
public enum FileFlags : uint
{
...
OpenReparsePoint = 0x00200000,
BackupSemantics = 0x02000000,
}
Run Code Online (Sandbox Code Playgroud)
以下命令可以成功检索 OneDrive 文件夹的重分析点信息。
fsutil 重新分析点查询 C:\Users\UserName\OneDrive
确定如何让这段代码工作会很棒。非常令人沮丧的是,被确认具有重新分析点的文件夹收到一条错误消息,表明它们没有。
我也在 C++ 中尝试过这个,但得到了同样的错误。
使用一些相关的API对其进行了测试。如有问题,欢迎指出。
\n\n通过使用获得的文件属性GetFileAttributes:
FILE_ATTRIBUTE_ARCHIVE | FILE_ATTRIBUTE_DIRECTORY | FILE_ATTRIBUTE_READONLY\nRun Code Online (Sandbox Code Playgroud)\n\n但没有属性:FILE_ATTRIBUTE_REPARSE_POINT. 而OneDrive中的普通文件只有属性:
FILE_ATTRIBUTE_ARCHIVE \nRun Code Online (Sandbox Code Playgroud)\n\n因此,OneDrive 文件夹及其所有子项目没有重新分析点属性。
\n\n这是测试样本\xef\xbc\x9a
\n\n#include <windows.h>\n#include <iostream>\ntypedef struct _REPARSE_DATA_BUFFER {\n ULONG ReparseTag;\n USHORT ReparseDataLength;\n USHORT Reserved;\n union {\n struct {\n USHORT SubstituteNameOffset;\n USHORT SubstituteNameLength;\n USHORT PrintNameOffset;\n USHORT PrintNameLength;\n ULONG Flags;\n WCHAR PathBuffer[1];\n } SymbolicLinkReparseBuffer;\n struct {\n USHORT SubstituteNameOffset;\n USHORT SubstituteNameLength;\n USHORT PrintNameOffset;\n USHORT PrintNameLength;\n WCHAR PathBuffer[1];\n } MountPointReparseBuffer;\n struct {\n UCHAR DataBuffer[1];\n } GenericReparseBuffer;\n } DUMMYUNIONNAME;\n} REPARSE_DATA_BUFFER, * PREPARSE_DATA_BUFFER;\n\nint main()\n{\n DWORD attr = GetFileAttributes(TEXT("C:\\\\Users\\\\UserName\\\\OneDrive"));\n if (attr & FILE_ATTRIBUTE_REPARSE_POINT)\n printf("with Attributes: FILE_ATTRIBUTE_REPARSE_POINT\\n");\n else\n printf("without FILE_ATTRIBUTE_REPARSE_POINT, Attributes = %x\\n",attr);\n HANDLE hFile = CreateFile(\n TEXT("C:\\\\Users\\\\UserName\\\\OneDrive"),\n 0,\n FILE_SHARE_READ,\n NULL,\n OPEN_EXISTING,\n FILE_FLAG_BACKUP_SEMANTICS| FILE_FLAG_OPEN_REPARSE_POINT,\n NULL\n );\n if (hFile != INVALID_HANDLE_VALUE)\n {\n REPARSE_DATA_BUFFER *rdb = (REPARSE_DATA_BUFFER*)malloc(sizeof(REPARSE_DATA_BUFFER)+ sizeof(ULONG)+sizeof(USHORT)+0xffff);\n if (rdb)\n {\n DWORD outBufferSize = sizeof(REPARSE_DATA_BUFFER) + sizeof(ULONG) + sizeof(USHORT) + 0xffff;\n DWORD bytesRet = 0;\n if (DeviceIoControl(hFile, FSCTL_GET_REPARSE_POINT, NULL, 0, rdb, outBufferSize, &bytesRet, NULL))\n wprintf(L"DeviceIoControl succeed! printfname = %s\\n", rdb->MountPointReparseBuffer.PathBuffer[rdb->MountPointReparseBuffer.PrintNameLength / sizeof(WCHAR)]);\n else\n wprintf(L"error code = %d\\n", GetLastError());\n free(rdb);\n rdb = NULL;\n }\n else\n printf("malloc failed\\n");\n }\n}\nRun Code Online (Sandbox Code Playgroud)\n\n使用fsutil reparsepoint query "C:\\\\Users\\\\UserName\\\\OneDrive",输出始终如下:
基本上没有可用的信息。此外,关闭“Files On Demand”将删除重分析点。
\n\n编辑:
\n\n与 不同的是GetFileAttributes,FindFirstFile可以获得该FILE_ATTRIBUTE_REPARSE_POINT属性。根据文档重新分析点标签:
\n\n\n要检索重分析点标记,请使用该
\nFindFirstFile函数。\n 如果dwFileAttributes成员包含\nFILE_ATTRIBUTE_REPARSE_POINT属性,则dwReserved0\n 成员指定重分析点。
更新:
\n\n与相关工程师确认后,由于云文件导致的此问题将隐藏重新解析信息,下面是相同的文档\n要解决此问题,有两种方法。
\n\ntypedef NTSYSAPI CHAR(*PGNSI)(CHAR Mode);\n#define PHCM_EXPOSE_PLACEHOLDERS ((CHAR)2)\nHMODULE hmod = LoadLibrary(L"ntdll.dll");\nif (hmod == NULL)\n{\n wprintf(L"LoadLibrary failed with %u\\n", GetLastError());\n return 0;\n}\n\nPGNSI pGNSI;\npGNSI = (PGNSI)GetProcAddress(hmod,"RtlSetProcessPlaceholderCompatibilityMode");\nif (pGNSI == NULL)\n{\n wprintf(L"GetProcAddress failed with %u\\n", GetLastError());\n return 0;\n}\nCHAR c = pGNSI(PHCM_EXPOSE_PLACEHOLDERS);\nRun Code Online (Sandbox Code Playgroud)\n\n文档:
\n\n\n\n\n\n与使用重分析点的应用程序的兼容性
\n\n云文件 API 使用重解析点实现占位符系统。关于重分析点的一个常见误解是它们与符号链接相同。这种误解偶尔会反映在应用程序实现中,因此,许多现有应用程序在遇到任何重新分析点时都会遇到错误。
\n\n为了缓解此兼容性问题,云文件 API 始终对除同步引擎和主映像驻留在 %systemroot% 下的进程之外的所有应用程序隐藏其重分析点。正确理解重分析点的应用程序可以强制平台使用 RtlSetProcessPlaceholderCompatibilityMode 或RtlSetThreadProcessPlaceholderCompatibilityMode 公开云文件 API 重分析点。
\n