Process reparse points for Microsoft Store applications (#13481)

This commit is contained in:
Ilya 2020-08-27 23:51:19 +05:00 committed by GitHub
parent 78d0d0e306
commit 4e2b6e9540
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 57 additions and 17 deletions

View File

@ -10,7 +10,6 @@ using System.Text;
using System.Collections;
using System.Threading;
using System.Management.Automation.Internal;
using System.Management.Automation.Runspaces;
using System.Xml;
using System.Runtime.InteropServices;
using Dbg = System.Management.Automation.Diagnostics;
@ -222,6 +221,29 @@ namespace System.Management.Automation
}
}
/// <summary>
/// Gets true if Path is Console Application.
/// </summary>
private bool IsConsoleApplication => !IsWindowsApplication;
/// <summary>
/// Gets true if Path is Windows Application.
/// </summary>
private bool IsWindowsApplication
{
get
{
if (!_isWindowsApplication.HasValue)
{
_isWindowsApplication = CheckIfWindowsApplication(Path);
}
return _isWindowsApplication.Value;
}
}
private bool? _isWindowsApplication;
#endregion ctor/native command properties
#region parameter binder
@ -476,7 +498,7 @@ namespace System.Management.Automation
bool notDone = true;
if (!string.IsNullOrEmpty(executable))
{
if (IsConsoleApplication(executable))
if (CheckIfConsoleApplication(executable))
{
// Allocate a console if there isn't one attached already...
ConsoleVisibility.AllocateHiddenConsole();
@ -532,7 +554,7 @@ namespace System.Management.Automation
_isRunningInBackground = true;
if (startInfo.UseShellExecute == false)
{
_isRunningInBackground = IsWindowsApplication(_nativeProcess.StartInfo.FileName);
_isRunningInBackground = IsWindowsApplication;
}
}
@ -935,9 +957,9 @@ namespace System.Management.Automation
/// </summary>
/// <param name="fileName"></param>
/// <returns></returns>
private static bool IsConsoleApplication(string fileName)
private static bool CheckIfConsoleApplication(string fileName)
{
return !IsWindowsApplication(fileName);
return !CheckIfWindowsApplication(fileName);
}
/// <summary>
@ -946,10 +968,22 @@ namespace System.Management.Automation
/// <param name="fileName"></param>
/// <returns></returns>
[ArchitectureSensitive]
private static bool IsWindowsApplication(string fileName)
private static bool CheckIfWindowsApplication(string fileName)
{
#if UNIX
return false;
#else
if (!Platform.IsWindowsDesktop) { return false; }
// SHGetFileInfo() does not understand reparse points and returns 0 ("non exe or error")
// so we are trying to get a real path before.
// It is a workaround for Microsoft Store applications.
string realPath = Microsoft.PowerShell.Commands.InternalSymbolicLinkLinkCodeMethods.WinInternalGetTarget(fileName);
if (realPath is not null)
{
fileName = realPath;
}
SHFILEINFO shinfo = new SHFILEINFO();
IntPtr type = SHGetFileInfo(fileName, 0, ref shinfo, (uint)Marshal.SizeOf(shinfo), SHGFI_EXETYPE);
@ -968,6 +1002,7 @@ namespace System.Management.Automation
// anything else - is a windows program...
return true;
}
#endif
}
#endregion checkForConsoleApplication
@ -1266,7 +1301,7 @@ namespace System.Management.Automation
redirectOutput = true;
redirectError = true;
}
else if (Platform.IsWindowsDesktop && IsConsoleApplication(this.Path))
else if (Platform.IsWindowsDesktop && IsConsoleApplication)
{
// On Windows desktops, if the command to run is a console application,
// then allocate a console if there isn't one attached already...

View File

@ -8073,16 +8073,7 @@ namespace Microsoft.PowerShell.Commands
if (instance.BaseObject is FileSystemInfo fileSysInfo)
{
#if !UNIX
// 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(fileSysInfo.FullName, FileDesiredAccess.GenericZero))
{
string linkTarget = WinInternalGetTarget(handle);
return linkTarget;
}
return WinInternalGetTarget(fileSysInfo.FullName);
#else
return UnixInternalGetTarget(fileSysInfo.FullName);
#endif
@ -8382,6 +8373,19 @@ namespace Microsoft.PowerShell.Commands
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)
{
@ -8456,6 +8460,7 @@ namespace Microsoft.PowerShell.Commands
Marshal.FreeHGlobal(outBuffer);
}
}
#endif
internal static bool CreateJunction(string path, string target)
{