Skip to content

Commit 2c2912c

Browse files
SteveL-MSFTadityapatwardhan
authored andcommitted
Enable recursion into OneDrive (PowerShell#9509)
1 parent 609fc9f commit 2c2912c

1 file changed

Lines changed: 57 additions & 1 deletion

File tree

src/System.Management.Automation/namespaces/FileSystemProvider.cs

Lines changed: 57 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1848,9 +1848,11 @@ private void Dir(
18481848
// a) the user has asked to with the -FollowSymLinks switch parameter and
18491849
// b) the directory pointed to by the symlink has not already been visited,
18501850
// preventing symlink loops.
1851+
// c) it is not a name surrogate making it not a symlink
18511852
if (tracker == null)
18521853
{
1853-
if (InternalSymbolicLinkLinkCodeMethods.IsReparsePoint(recursiveDirectory))
1854+
if (InternalSymbolicLinkLinkCodeMethods.IsReparsePoint(recursiveDirectory) &&
1855+
InternalSymbolicLinkLinkCodeMethods.IsNameSurrogateReparsePoint(recursiveDirectory.FullName))
18541856
{
18551857
continue;
18561858
}
@@ -7706,6 +7708,8 @@ public static class InternalSymbolicLinkLinkCodeMethods
77067708

77077709
private const string NonInterpretedPathPrefix = @"\??\";
77087710

7711+
private const int MAX_PATH = 260;
7712+
77097713
[Flags]
77107714
// dwDesiredAccess of CreateFile
77117715
internal enum FileDesiredAccess : uint
@@ -7846,6 +7850,39 @@ internal static extern IntPtr CreateFile(
78467850
FileAttributes dwFlagsAndAttributes,
78477851
IntPtr hTemplateFile);
78487852

7853+
[DllImport(PinvokeDllNames.FindFirstFileDllName, EntryPoint = "FindFirstFileExW", SetLastError = true, CharSet = CharSet.Unicode)]
7854+
private static extern SafeFileHandle FindFirstFileEx(string lpFileName, FINDEX_INFO_LEVELS fInfoLevelId, ref WIN32_FIND_DATA lpFindFileData, FINDEX_SEARCH_OPS fSearchOp, IntPtr lpSearchFilter, int dwAdditionalFlags);
7855+
7856+
internal enum FINDEX_INFO_LEVELS : uint
7857+
{
7858+
FindExInfoStandard = 0x0u,
7859+
FindExInfoBasic = 0x1u,
7860+
FindExInfoMaxInfoLevel = 0x2u,
7861+
}
7862+
7863+
internal enum FINDEX_SEARCH_OPS : uint
7864+
{
7865+
FindExSearchNameMatch = 0x0u,
7866+
FindExSearchLimitToDirectories = 0x1u,
7867+
FindExSearchLimitToDevices = 0x2u,
7868+
FindExSearchMaxSearchOp = 0x3u,
7869+
}
7870+
7871+
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
7872+
internal unsafe struct WIN32_FIND_DATA
7873+
{
7874+
internal uint dwFileAttributes;
7875+
internal System.Runtime.InteropServices.ComTypes.FILETIME ftCreationTime;
7876+
internal System.Runtime.InteropServices.ComTypes.FILETIME ftLastAccessTime;
7877+
internal System.Runtime.InteropServices.ComTypes.FILETIME ftLastWriteTime;
7878+
internal uint nFileSizeHigh;
7879+
internal uint nFileSizeLow;
7880+
internal uint dwReserved0;
7881+
internal uint dwReserved1;
7882+
internal fixed char cFileName[MAX_PATH];
7883+
internal fixed char cAlternateFileName[14];
7884+
}
7885+
78497886
/// <summary>
78507887
/// Gets the target of the specified reparse point.
78517888
/// </summary>
@@ -7993,6 +8030,25 @@ internal static bool IsReparsePoint(FileSystemInfo fileInfo)
79938030
: Platform.NonWindowsIsSymLink(fileInfo);
79948031
}
79958032

8033+
internal static bool IsNameSurrogateReparsePoint(string filePath)
8034+
{
8035+
#if !UNIX
8036+
var data = new WIN32_FIND_DATA();
8037+
using (SafeFileHandle handle = FindFirstFileEx(filePath, FINDEX_INFO_LEVELS.FindExInfoBasic, ref data, FINDEX_SEARCH_OPS.FindExSearchNameMatch, IntPtr.Zero, 0))
8038+
{
8039+
// Name surrogates are reparse points that point to other named entities local to the filesystem (like symlinks)
8040+
// In the case of OneDrive, they are not surrogates and would be safe to recurse into.
8041+
// This code is equivalent to the IsReparseTagNameSurrogate macro: https://docs.microsoft.com/en-us/windows-hardware/drivers/ddi/content/ntifs/nf-ntifs-isreparsetagnamesurrogate
8042+
if (!handle.IsInvalid && (data.dwReserved0 & 0x20000000) == 0)
8043+
{
8044+
return false;
8045+
}
8046+
}
8047+
#endif
8048+
// true means the reparse point is a symlink
8049+
return true;
8050+
}
8051+
79968052
internal static bool WinIsHardLink(FileSystemInfo fileInfo)
79978053
{
79988054
bool isHardLink = false;

0 commit comments

Comments
 (0)