I'm using the code below to retrieve reparse point information in my application. This works great for symbolic links and junctions, but fails with 'Not a reparse point' for the OneDrive folder and all it's child items.
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);
}
}
}
Native declarations:
[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,
}
The following command can successfully retrieve reparse point info for the OneDrive folder.
fsutil reparsepoint query C:\Users\UserName\OneDrive
Would be great to determine how to get this code to work. Very frustrating that folders that are confirmed as having reparse points get an error message that they aren't.
I also have tried this in C++, but get the same error.
Tested it with the some relevant APIs. If there is any issue, please feel free to point out.
The file attributes obtained by using GetFileAttributes
:
FILE_ATTRIBUTE_ARCHIVE | FILE_ATTRIBUTE_DIRECTORY | FILE_ATTRIBUTE_READONLY
but without attribute: FILE_ATTRIBUTE_REPARSE_POINT
. And the common file in OneDrive only have attributes:
FILE_ATTRIBUTE_ARCHIVE
Therefore, OneDrive folder and all it's child items do not have the reparse points property.
Here is the sample for testingļ¼
#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");
}
}
And using fsutil reparsepoint query "C:\\Users\\UserName\\OneDrive"
, the output is always as follows:
There is basically no information available. In addition, turn off "Files On Demand" will remove the reparse points.
EDIT:
Different with GetFileAttributes
, FindFirstFile
can get this FILE_ATTRIBUTE_REPARSE_POINT
attribute. According to the document Reparse Point Tags:
To retrieve the reparse point tag, use the
FindFirstFile
function. If thedwFileAttributes
member includes theFILE_ATTRIBUTE_REPARSE_POINT
attribute, then thedwReserved0
member specifies the reparse point.
UPDATE:
After confirm with relevant engineer, This issue due to cloud files will hides the reparse information below is the documentation for the same To overcome this issue they are two ways.
typedef NTSYSAPI CHAR(*PGNSI)(CHAR Mode);
#define PHCM_EXPOSE_PLACEHOLDERS ((CHAR)2)
HMODULE hmod = LoadLibrary(L"ntdll.dll");
if (hmod == NULL)
{
wprintf(L"LoadLibrary failed with %u\n", GetLastError());
return 0;
}
PGNSI pGNSI;
pGNSI = (PGNSI)GetProcAddress(hmod,"RtlSetProcessPlaceholderCompatibilityMode");
if (pGNSI == NULL)
{
wprintf(L"GetProcAddress failed with %u\n", GetLastError());
return 0;
}
CHAR c = pGNSI(PHCM_EXPOSE_PLACEHOLDERS);
Documentation:
Compatibility with applications that use reparse points
The cloud files API implements the placeholder system using reparse points. A common misconception about reparse points is that they are the same as symbolic links. This misconception is occasionally reflected in application implementations, and as a result, many existing applications hit errors when encountering any reparse point.
To mitigate this compatibility issue, the cloud files API always hides its reparse points from all applications except for sync engines and processes whose main image resides under %systemroot%. Applications that understand reparse points correctly can force the platform to expose cloud files API reparse points using RtlSetProcessPlaceholderCompatibilityMode or RtlSetThreadProcessPlaceholderCompatibilityMode.
User contributions licensed under CC BY-SA 3.0