-
Notifications
You must be signed in to change notification settings - Fork 8.1k
WIP: Use newly added LinkTarget property #15960
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,5 +1,5 @@ | ||
| { | ||
| "sdk": { | ||
| "version": "6.0.100-preview.6.21355.2" | ||
| "version": "6.0.100-preview.7.21379.14" | ||
| } | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -211,7 +211,7 @@ private static string GetCorrectCasedPath(string path) | |
| /// <exception cref="System.UnauthorizedAccessException"> | ||
| /// An I/O error or a specific type of security error. | ||
| /// </exception> | ||
| private static FileSystemInfo GetFileSystemInfo(string path, out bool isContainer) | ||
| internal static FileSystemInfo GetFileSystemInfo(string path, out bool isContainer) | ||
| { | ||
| // We use 'FileInfo.Attributes' (not 'FileInfo.Exist') | ||
| // because we want to get exceptions | ||
|
|
@@ -2069,7 +2069,7 @@ public static string NameString(PSObject instance) | |
| { | ||
| if (InternalSymbolicLinkLinkCodeMethods.IsReparsePointLikeSymlink(fileInfo)) | ||
| { | ||
| return $"{PSStyle.Instance.FileInfo.SymbolicLink}{fileInfo.Name}{PSStyle.Instance.Reset} -> {InternalSymbolicLinkLinkCodeMethods.GetTarget(instance)}"; | ||
| return $"{PSStyle.Instance.FileInfo.SymbolicLink}{fileInfo.Name}{PSStyle.Instance.Reset} -> {fileInfo.LinkTarget}"; | ||
| } | ||
| else if (fileInfo.Attributes.HasFlag(FileAttributes.Directory)) | ||
| { | ||
|
|
@@ -2096,7 +2096,7 @@ public static string NameString(PSObject instance) | |
| { | ||
| return instance?.BaseObject is FileSystemInfo fileInfo | ||
| ? InternalSymbolicLinkLinkCodeMethods.IsReparsePointLikeSymlink(fileInfo) | ||
| ? $"{fileInfo.Name} -> {InternalSymbolicLinkLinkCodeMethods.GetTarget(instance)}" | ||
| ? $"{fileInfo.Name} -> {fileInfo.LinkTarget}" | ||
| : fileInfo.Name | ||
| : string.Empty; | ||
| } | ||
|
|
@@ -8112,11 +8112,7 @@ public static string GetTarget(PSObject instance) | |
| { | ||
| if (instance.BaseObject is FileSystemInfo fileSysInfo) | ||
| { | ||
| #if !UNIX | ||
| return WinInternalGetTarget(fileSysInfo.FullName); | ||
| #else | ||
| return UnixInternalGetTarget(fileSysInfo.FullName); | ||
| #endif | ||
| return fileSysInfo.LinkTarget; | ||
| } | ||
|
|
||
| return null; | ||
|
|
@@ -8139,20 +8135,6 @@ public static string GetLinkType(PSObject instance) | |
| return null; | ||
| } | ||
|
|
||
| #if UNIX | ||
| private static string UnixInternalGetTarget(string filePath) | ||
| { | ||
| string link = Platform.NonWindowsInternalGetTarget(filePath); | ||
|
|
||
| if (string.IsNullOrEmpty(link)) | ||
| { | ||
| throw new Win32Exception(Marshal.GetLastWin32Error()); | ||
| } | ||
|
|
||
| return link; | ||
| } | ||
| #endif | ||
|
|
||
| private static string InternalGetLinkType(FileSystemInfo fileInfo) | ||
| { | ||
| if (Platform.IsWindows) | ||
|
|
@@ -8446,99 +8428,6 @@ internal static bool WinIsHardLink(ref IntPtr handle) | |
| return succeeded && (handleInfo.NumberOfLinks > 1); | ||
| } | ||
|
|
||
| #if !UNIX | ||
| internal static string WinInternalGetTarget(string path) | ||
| { | ||
| // We set accessMode parameter to zero because documentation says: | ||
| // If this parameter is zero, the application can query certain metadata | ||
| // such as file, directory, or device attributes without accessing | ||
| // that file or device, even if GENERIC_READ access would have been denied. | ||
| using (SafeFileHandle handle = OpenReparsePoint(path, FileDesiredAccess.GenericZero)) | ||
| { | ||
| return WinInternalGetTarget(handle); | ||
| } | ||
| } | ||
|
|
||
| [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Reliability", "CA2001:AvoidCallingProblematicMethods")] | ||
| private static string WinInternalGetTarget(SafeFileHandle handle) | ||
| { | ||
| int outBufferSize = Marshal.SizeOf<REPARSE_DATA_BUFFER_SYMBOLICLINK>(); | ||
|
|
||
| IntPtr outBuffer = Marshal.AllocHGlobal(outBufferSize); | ||
| bool success = false; | ||
|
|
||
| try | ||
| { | ||
| int bytesReturned; | ||
|
|
||
| // OACR warning 62001 about using DeviceIOControl has been disabled. | ||
| // According to MSDN guidance DangerousAddRef() and DangerousRelease() have been used. | ||
| handle.DangerousAddRef(ref success); | ||
|
|
||
| bool result = DeviceIoControl( | ||
| handle.DangerousGetHandle(), | ||
| FSCTL_GET_REPARSE_POINT, | ||
| InBuffer: IntPtr.Zero, | ||
| nInBufferSize: 0, | ||
| outBuffer, | ||
| outBufferSize, | ||
| out bytesReturned, | ||
| lpOverlapped: IntPtr.Zero); | ||
|
|
||
| if (!result) | ||
| { | ||
| // It's not a reparse point or the file system doesn't support reparse points. | ||
| return null; | ||
| } | ||
|
|
||
| string targetDir = null; | ||
|
|
||
| REPARSE_DATA_BUFFER_SYMBOLICLINK reparseDataBuffer = Marshal.PtrToStructure<REPARSE_DATA_BUFFER_SYMBOLICLINK>(outBuffer); | ||
|
|
||
| switch (reparseDataBuffer.ReparseTag) | ||
| { | ||
| case IO_REPARSE_TAG_SYMLINK: | ||
| targetDir = Encoding.Unicode.GetString(reparseDataBuffer.PathBuffer, reparseDataBuffer.SubstituteNameOffset, reparseDataBuffer.SubstituteNameLength); | ||
| break; | ||
|
|
||
| case IO_REPARSE_TAG_MOUNT_POINT: | ||
| REPARSE_DATA_BUFFER_MOUNTPOINT reparseMountPointDataBuffer = Marshal.PtrToStructure<REPARSE_DATA_BUFFER_MOUNTPOINT>(outBuffer); | ||
| targetDir = Encoding.Unicode.GetString(reparseMountPointDataBuffer.PathBuffer, reparseMountPointDataBuffer.SubstituteNameOffset, reparseMountPointDataBuffer.SubstituteNameLength); | ||
| break; | ||
|
|
||
| case IO_REPARSE_TAG_APPEXECLINK: | ||
| REPARSE_DATA_BUFFER_APPEXECLINK reparseAppExeDataBuffer = Marshal.PtrToStructure<REPARSE_DATA_BUFFER_APPEXECLINK>(outBuffer); | ||
| // The target file is at index 2 | ||
| if (reparseAppExeDataBuffer.StringCount >= 3) | ||
| { | ||
| string temp = Encoding.Unicode.GetString(reparseAppExeDataBuffer.StringList); | ||
| targetDir = temp.Split('\0')[2]; | ||
| } | ||
| break; | ||
|
Comment on lines
-8504
to
-8517
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. We are currently only supporting symlinks, not mount points or apexeclinks. I don't think this should be deleted yet.
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. We can defer merging after .NET 6 RC1 is released (and consumed by pwsh), which will include that.
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Is it already in a PR?
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. |
||
|
|
||
| default: | ||
| return null; | ||
| } | ||
|
|
||
| if (targetDir != null && targetDir.StartsWith(NonInterpretedPathPrefix, StringComparison.OrdinalIgnoreCase)) | ||
| { | ||
| targetDir = targetDir.Substring(NonInterpretedPathPrefix.Length); | ||
| } | ||
|
|
||
| return targetDir; | ||
| } | ||
| finally | ||
| { | ||
| if (success) | ||
| { | ||
| handle.DangerousRelease(); | ||
| } | ||
|
|
||
| Marshal.FreeHGlobal(outBuffer); | ||
| } | ||
| } | ||
| #endif | ||
|
|
||
| internal static bool CreateJunction(string path, string target) | ||
| { | ||
| // this is a purely Windows specific feature, no feature flag | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It would be great to get rid of IsReparsePointLikeSymlink() call and check
fileInfo.LinkTarget is not nullbut .Net API has slightly different behavior - can we enhance the .Net API?PowerShell/src/System.Management.Automation/namespaces/FileSystemProvider.cs
Lines 8301 to 8308 in 176303d
(Also you can see as IsReparsePointLikeSymlink() is used in other places. It seems it work the same for directory removal scenario but directory enumeration requires enhaсing of .Net API)