我正在使用下面的代码在我的应用程序中检索重解析点信息。这对于符号链接和结点非常有用,但对于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);
}
}
}
本地声明
[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,
}
以下命令可以成功检索OneDrive文件夹的重解析点信息。
fsutil重新解析点查询C:\ Users \ UserName \ OneDrive
确定如何使此代码正常工作将非常有用。令人沮丧的是,确认为具有重定位点的文件夹会收到错误消息,提示它们不是。
我也曾在C ++中尝试过此方法,但遇到相同的错误。
答案 0 :(得分:0)
使用一些相关的API对其进行了测试。如有任何问题,请随时指出。
使用GetFileAttributes
获得的文件属性:
FILE_ATTRIBUTE_ARCHIVE | FILE_ATTRIBUTE_DIRECTORY | FILE_ATTRIBUTE_READONLY
,但没有属性:FILE_ATTRIBUTE_REPARSE_POINT
。而且OneDrive中的通用文件仅具有以下属性:
FILE_ATTRIBUTE_ARCHIVE
因此,OneDrive文件夹及其所有子项没有重新解析点属性。
这里是测试样品:
#include <windows.h>
#include <iostream>
typedef struct _REPARSE_DATA_BUFFER {
ULONG ReparseTag;
USHORT ReparseDataLength;
USHORT Reserved;
union {
struct {
USHORT SubstituteNameOffset;
USHORT SubstituteNameLength;
USHORT PrintNameOffset;
USHORT PrintNameLength;
ULONG Flags;
WCHAR PathBuffer[1];
} SymbolicLinkReparseBuffer;
struct {
USHORT SubstituteNameOffset;
USHORT SubstituteNameLength;
USHORT PrintNameOffset;
USHORT PrintNameLength;
WCHAR PathBuffer[1];
} MountPointReparseBuffer;
struct {
UCHAR DataBuffer[1];
} GenericReparseBuffer;
} DUMMYUNIONNAME;
} REPARSE_DATA_BUFFER, * PREPARSE_DATA_BUFFER;
int main()
{
DWORD attr = GetFileAttributes(TEXT("C:\\Users\\UserName\\OneDrive"));
if (attr & FILE_ATTRIBUTE_REPARSE_POINT)
printf("with Attributes: FILE_ATTRIBUTE_REPARSE_POINT\n");
else
printf("without FILE_ATTRIBUTE_REPARSE_POINT, Attributes = %x\n",attr);
HANDLE hFile = CreateFile(
TEXT("C:\\Users\\UserName\\OneDrive"),
0,
FILE_SHARE_READ,
NULL,
OPEN_EXISTING,
FILE_FLAG_BACKUP_SEMANTICS| FILE_FLAG_OPEN_REPARSE_POINT,
NULL
);
if (hFile != INVALID_HANDLE_VALUE)
{
REPARSE_DATA_BUFFER *rdb = (REPARSE_DATA_BUFFER*)malloc(sizeof(REPARSE_DATA_BUFFER)+ sizeof(ULONG)+sizeof(USHORT)+0xffff);
if (rdb)
{
DWORD outBufferSize = sizeof(REPARSE_DATA_BUFFER) + sizeof(ULONG) + sizeof(USHORT) + 0xffff;
DWORD bytesRet = 0;
if (DeviceIoControl(hFile, FSCTL_GET_REPARSE_POINT, NULL, 0, rdb, outBufferSize, &bytesRet, NULL))
wprintf(L"DeviceIoControl succeed! printfname = %s\n", rdb->MountPointReparseBuffer.PathBuffer[rdb->MountPointReparseBuffer.PrintNameLength / sizeof(WCHAR)]);
else
wprintf(L"error code = %d\n", GetLastError());
free(rdb);
rdb = NULL;
}
else
printf("malloc failed\n");
}
}
使用fsutil reparsepoint query "C:\\Users\\UserName\\OneDrive"
,输出始终如下:
基本上没有可用信息。此外,关闭“按需文件”将删除重新解析点。
编辑:
与GetFileAttributes
,FindFirstFile
不同的是,可以获取此FILE_ATTRIBUTE_REPARSE_POINT
属性。根据文档Reparse Point Tags:
要检索重新解析点标记,请使用
FindFirstFile
函数。 如果dwFileAttributes
成员包括FILE_ATTRIBUTE_REPARSE_POINT
属性,然后是dwReserved0
成员指定重新解析点。
答案 1 :(得分:0)
此答案是一种解决方法,可让OneDrive从备份映像正常工作。
备份过程需要正常复制OneDrive文件,而无需重新解析信息。 OneDrive仍会为仅在线且不在本地存储的任何数据创建存根文件。然后,需要一个命令让OneDrive从备份映像中重置自身。然后,重置过程将为每个文件夹和文件重新创建重新分析信息。为此,备份过程会在备份映像中为reset命令创建一个注册表RunOnce注册表项。
RunOnce命令类似于以下内容:
HKEY_CURRENT_USER\SOFTWARE\Microsoft\Windows\CurrentVersion\RunOnce
"Reset" REG_SZ "C:\Users\UserName\AppData\Local\Microsoft\OneDrive\OneDrive.exe" /reset
我更愿意为其他人功劳,因为该答案可以演示对OneDrive的读写信息。这样可以在启动备用映像时删除重置。