mirror of
https://github.com/PowerShell/PowerShell.git
synced 2025-01-08 17:33:23 +08:00
Removing Hardlink from Mode property in default file system format (#8789)
This commit is contained in:
parent
1e49d09d29
commit
9983297254
@ -42,28 +42,33 @@ namespace System.Management.Automation.Runspaces
|
|||||||
|
|
||||||
private static IEnumerable<FormatViewDefinition> ViewsOf_FileSystemTypes(CustomControl[] sharedControls)
|
private static IEnumerable<FormatViewDefinition> ViewsOf_FileSystemTypes(CustomControl[] sharedControls)
|
||||||
{
|
{
|
||||||
const string LengthScriptBlock =
|
|
||||||
@"if ($_ -is [System.IO.DirectoryInfo]) { return '' }
|
|
||||||
if ($_.Attributes -band [System.IO.FileAttributes]::Offline)
|
|
||||||
{
|
|
||||||
return '({0})' -f $_.Length
|
|
||||||
}
|
|
||||||
return $_.Length";
|
|
||||||
|
|
||||||
yield return new FormatViewDefinition("children",
|
yield return new FormatViewDefinition("children",
|
||||||
TableControl.Create()
|
TableControl.Create()
|
||||||
.GroupByProperty("PSParentPath", customControl: sharedControls[0])
|
.GroupByProperty("PSParentPath", customControl: sharedControls[0])
|
||||||
.AddHeader(Alignment.Left, label: "Mode", width: 7)
|
.AddHeader(Alignment.Left, label: "Mode", width: 7)
|
||||||
.AddHeader(Alignment.Right, label: "LastWriteTime", width: 25)
|
.AddHeader(Alignment.Right, label: "LastWriteTime", width: 25)
|
||||||
.AddHeader(Alignment.Right, label: "Length", width: 14)
|
.AddHeader(Alignment.Right, label: "Length", width: 14)
|
||||||
.AddHeader()
|
.AddHeader(Alignment.Left, label: "Name")
|
||||||
|
.StartRowDefinition(wrap: true)
|
||||||
|
.AddPropertyColumn("ModeWithoutHardLink")
|
||||||
|
.AddPropertyColumn("LastWriteTimeString")
|
||||||
|
.AddPropertyColumn("LengthString")
|
||||||
|
.AddPropertyColumn("NameString")
|
||||||
|
.EndRowDefinition()
|
||||||
|
.EndTable());
|
||||||
|
|
||||||
|
yield return new FormatViewDefinition("childrenWithHardlink",
|
||||||
|
TableControl.Create()
|
||||||
|
.GroupByProperty("PSParentPath", customControl: sharedControls[0])
|
||||||
|
.AddHeader(Alignment.Left, label: "Mode", width: 7)
|
||||||
|
.AddHeader(Alignment.Right, label: "LastWriteTime", width: 25)
|
||||||
|
.AddHeader(Alignment.Right, label: "Length", width: 14)
|
||||||
|
.AddHeader(Alignment.Left, label: "Name")
|
||||||
.StartRowDefinition(wrap: true)
|
.StartRowDefinition(wrap: true)
|
||||||
.AddPropertyColumn("Mode")
|
.AddPropertyColumn("Mode")
|
||||||
.AddScriptBlockColumn(@"
|
.AddPropertyColumn("LastWriteTimeString")
|
||||||
[String]::Format(""{0,10} {1,8}"", $_.LastWriteTime.ToString(""d""), $_.LastWriteTime.ToString(""t""))
|
.AddPropertyColumn("LengthString")
|
||||||
")
|
.AddPropertyColumn("NameString")
|
||||||
.AddScriptBlockColumn(LengthScriptBlock)
|
|
||||||
.AddPropertyColumn("Name")
|
|
||||||
.EndRowDefinition()
|
.EndRowDefinition()
|
||||||
.EndTable());
|
.EndTable());
|
||||||
|
|
||||||
@ -72,7 +77,7 @@ return $_.Length";
|
|||||||
.GroupByProperty("PSParentPath", customControl: sharedControls[0])
|
.GroupByProperty("PSParentPath", customControl: sharedControls[0])
|
||||||
.StartEntry(entrySelectedByType: new[] { "System.IO.FileInfo" })
|
.StartEntry(entrySelectedByType: new[] { "System.IO.FileInfo" })
|
||||||
.AddItemProperty(@"Name")
|
.AddItemProperty(@"Name")
|
||||||
.AddItemScriptBlock(LengthScriptBlock, label: "Length")
|
.AddItemProperty("LengthString", label: "Length")
|
||||||
.AddItemProperty(@"CreationTime")
|
.AddItemProperty(@"CreationTime")
|
||||||
.AddItemProperty(@"LastWriteTime")
|
.AddItemProperty(@"LastWriteTime")
|
||||||
.AddItemProperty(@"LastAccessTime")
|
.AddItemProperty(@"LastAccessTime")
|
||||||
|
@ -183,18 +183,28 @@ namespace System.Management.Automation.Runspaces
|
|||||||
var td19 = new TypeData(@"System.IO.DirectoryInfo", true);
|
var td19 = new TypeData(@"System.IO.DirectoryInfo", true);
|
||||||
td19.Members.Add("Mode",
|
td19.Members.Add("Mode",
|
||||||
new CodePropertyData("Mode", GetMethodInfo(typeof(Microsoft.PowerShell.Commands.FileSystemProvider), "Mode"), null));
|
new CodePropertyData("Mode", GetMethodInfo(typeof(Microsoft.PowerShell.Commands.FileSystemProvider), "Mode"), null));
|
||||||
|
td19.Members.Add("ModeWithoutHardLink",
|
||||||
|
new CodePropertyData("ModeWithoutHardLink", GetMethodInfo(typeof(Microsoft.PowerShell.Commands.FileSystemProvider), "ModeWithoutHardLink"), null));
|
||||||
td19.Members.Add("BaseName",
|
td19.Members.Add("BaseName",
|
||||||
new ScriptPropertyData(@"BaseName", GetScriptBlock(@"$this.Name"), null));
|
new ScriptPropertyData(@"BaseName", GetScriptBlock(@"$this.Name"), null));
|
||||||
td19.Members.Add("Target",
|
td19.Members.Add("Target",
|
||||||
new CodePropertyData("Target", GetMethodInfo(typeof(Microsoft.PowerShell.Commands.InternalSymbolicLinkLinkCodeMethods), "GetTarget"), null));
|
new CodePropertyData("Target", GetMethodInfo(typeof(Microsoft.PowerShell.Commands.InternalSymbolicLinkLinkCodeMethods), "GetTarget"), null));
|
||||||
td19.Members.Add("LinkType",
|
td19.Members.Add("LinkType",
|
||||||
new CodePropertyData("LinkType", GetMethodInfo(typeof(Microsoft.PowerShell.Commands.InternalSymbolicLinkLinkCodeMethods), "GetLinkType"), null));
|
new CodePropertyData("LinkType", GetMethodInfo(typeof(Microsoft.PowerShell.Commands.InternalSymbolicLinkLinkCodeMethods), "GetLinkType"), null));
|
||||||
|
td19.Members.Add("NameString",
|
||||||
|
new CodePropertyData("NameString", GetMethodInfo(typeof(Microsoft.PowerShell.Commands.FileSystemProvider), "NameString"), null) { IsHidden = true });
|
||||||
|
td19.Members.Add("LengthString",
|
||||||
|
new CodePropertyData("LengthString", GetMethodInfo(typeof(Microsoft.PowerShell.Commands.FileSystemProvider), "LengthString"), null) { IsHidden = true });
|
||||||
|
td19.Members.Add("LastWriteTimeString",
|
||||||
|
new CodePropertyData("LastWriteTimeString", GetMethodInfo(typeof(Microsoft.PowerShell.Commands.FileSystemProvider), "LastWriteTimeString"), null) { IsHidden = true });
|
||||||
td19.DefaultDisplayProperty = @"Name";
|
td19.DefaultDisplayProperty = @"Name";
|
||||||
yield return td19;
|
yield return td19;
|
||||||
|
|
||||||
var td20 = new TypeData(@"System.IO.FileInfo", true);
|
var td20 = new TypeData(@"System.IO.FileInfo", true);
|
||||||
td20.Members.Add("Mode",
|
td20.Members.Add("Mode",
|
||||||
new CodePropertyData("Mode", GetMethodInfo(typeof(Microsoft.PowerShell.Commands.FileSystemProvider), "Mode"), null));
|
new CodePropertyData("Mode", GetMethodInfo(typeof(Microsoft.PowerShell.Commands.FileSystemProvider), "Mode"), null));
|
||||||
|
td20.Members.Add("ModeWithoutHardLink",
|
||||||
|
new CodePropertyData("ModeWithoutHardLink", GetMethodInfo(typeof(Microsoft.PowerShell.Commands.FileSystemProvider), "ModeWithoutHardLink"), null));
|
||||||
td20.Members.Add("VersionInfo",
|
td20.Members.Add("VersionInfo",
|
||||||
new ScriptPropertyData(@"VersionInfo", GetScriptBlock(@"[System.Diagnostics.FileVersionInfo]::GetVersionInfo($this.FullName)"), null));
|
new ScriptPropertyData(@"VersionInfo", GetScriptBlock(@"[System.Diagnostics.FileVersionInfo]::GetVersionInfo($this.FullName)"), null));
|
||||||
td20.Members.Add("BaseName",
|
td20.Members.Add("BaseName",
|
||||||
@ -203,6 +213,12 @@ namespace System.Management.Automation.Runspaces
|
|||||||
new CodePropertyData("Target", GetMethodInfo(typeof(Microsoft.PowerShell.Commands.InternalSymbolicLinkLinkCodeMethods), "GetTarget"), null));
|
new CodePropertyData("Target", GetMethodInfo(typeof(Microsoft.PowerShell.Commands.InternalSymbolicLinkLinkCodeMethods), "GetTarget"), null));
|
||||||
td20.Members.Add("LinkType",
|
td20.Members.Add("LinkType",
|
||||||
new CodePropertyData("LinkType", GetMethodInfo(typeof(Microsoft.PowerShell.Commands.InternalSymbolicLinkLinkCodeMethods), "GetLinkType"), null));
|
new CodePropertyData("LinkType", GetMethodInfo(typeof(Microsoft.PowerShell.Commands.InternalSymbolicLinkLinkCodeMethods), "GetLinkType"), null));
|
||||||
|
td20.Members.Add("NameString",
|
||||||
|
new CodePropertyData("NameString", GetMethodInfo(typeof(Microsoft.PowerShell.Commands.FileSystemProvider), "NameString"), null) { IsHidden = true });
|
||||||
|
td20.Members.Add("LengthString",
|
||||||
|
new CodePropertyData("LengthString", GetMethodInfo(typeof(Microsoft.PowerShell.Commands.FileSystemProvider), "LengthString"), null) { IsHidden = true });
|
||||||
|
td20.Members.Add("LastWriteTimeString",
|
||||||
|
new CodePropertyData("LastWriteTimeString", GetMethodInfo(typeof(Microsoft.PowerShell.Commands.FileSystemProvider), "LastWriteTimeString"), null) { IsHidden = true });
|
||||||
td20.DefaultDisplayPropertySet =
|
td20.DefaultDisplayPropertySet =
|
||||||
new PropertySetData(new[] { "LastWriteTime", "Length", "Name" }) { Name = "DefaultDisplayPropertySet" };
|
new PropertySetData(new[] { "LastWriteTime", "Length", "Name" }) { Name = "DefaultDisplayPropertySet" };
|
||||||
yield return td20;
|
yield return td20;
|
||||||
|
@ -1867,33 +1867,99 @@ namespace Microsoft.PowerShell.Commands
|
|||||||
/// Provides a mode property for FileSystemInfo.
|
/// Provides a mode property for FileSystemInfo.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="instance">Instance of PSObject wrapping a FileSystemInfo.</param>
|
/// <param name="instance">Instance of PSObject wrapping a FileSystemInfo.</param>
|
||||||
|
/// <returns>A string representation of the FileAttributes, with one letter per attribute.</returns>
|
||||||
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Reliability", "CA2001:AvoidCallingProblematicMethods")]
|
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Reliability", "CA2001:AvoidCallingProblematicMethods")]
|
||||||
public static string Mode(PSObject instance)
|
public static string Mode(PSObject instance) => Mode(instance, excludeHardLink: false);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Provides a ModeWithoutHardLink property for FileSystemInfo, without HardLinks for performance reasons.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="instance">Instance of PSObject wrapping a FileSystemInfo.</param>
|
||||||
|
/// <returns>A string representation of the FileAttributes, with one letter per attribute.</returns>
|
||||||
|
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Reliability", "CA2001:AvoidCallingProblematicMethods")]
|
||||||
|
public static string ModeWithoutHardLink(PSObject instance) => Mode(instance, excludeHardLink: true);
|
||||||
|
|
||||||
|
private static string Mode(PSObject instance, bool excludeHardLink)
|
||||||
{
|
{
|
||||||
if (instance == null)
|
string ToModeString(FileSystemInfo fileSystemInfo)
|
||||||
{
|
{
|
||||||
return string.Empty;
|
FileAttributes fileAttributes = fileSystemInfo.Attributes;
|
||||||
|
|
||||||
|
bool isReparsePoint = InternalSymbolicLinkLinkCodeMethods.IsReparsePoint(fileSystemInfo);
|
||||||
|
bool isLink = isReparsePoint || (excludeHardLink ? false : InternalSymbolicLinkLinkCodeMethods.IsHardLink(fileSystemInfo));
|
||||||
|
if (!isLink)
|
||||||
|
{
|
||||||
|
// special casing for the common cases - no allocations
|
||||||
|
switch (fileAttributes)
|
||||||
|
{
|
||||||
|
case FileAttributes.Archive:
|
||||||
|
return "-a---";
|
||||||
|
case FileAttributes.Directory:
|
||||||
|
return "d----";
|
||||||
|
case FileAttributes.Normal:
|
||||||
|
return "-----";
|
||||||
|
case FileAttributes.Directory | FileAttributes.ReadOnly:
|
||||||
|
return "d-r--";
|
||||||
|
case FileAttributes.Archive | FileAttributes.ReadOnly:
|
||||||
|
return "-ar--";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool isDirectory = fileAttributes.HasFlag(FileAttributes.Directory);
|
||||||
|
ReadOnlySpan<char> mode = stackalloc char[]
|
||||||
|
{
|
||||||
|
isLink ? 'l' : isDirectory ? 'd' : '-',
|
||||||
|
fileAttributes.HasFlag(FileAttributes.Archive) ? 'a' : '-',
|
||||||
|
fileAttributes.HasFlag(FileAttributes.ReadOnly) ? 'r' : '-',
|
||||||
|
fileAttributes.HasFlag(FileAttributes.Hidden) ? 'h' : '-',
|
||||||
|
fileAttributes.HasFlag(FileAttributes.System) ? 's' : '-',
|
||||||
|
};
|
||||||
|
return new string(mode);
|
||||||
}
|
}
|
||||||
|
|
||||||
FileSystemInfo fileInfo = (FileSystemInfo)instance.BaseObject;
|
return instance?.BaseObject is FileSystemInfo fileInfo
|
||||||
if (fileInfo == null)
|
? ToModeString(fileInfo)
|
||||||
{
|
: string.Empty;
|
||||||
return string.Empty;
|
}
|
||||||
}
|
|
||||||
|
|
||||||
char[] mode = new char[6];
|
/// <summary>
|
||||||
mode[0] = (fileInfo.Attributes & FileAttributes.Directory) == FileAttributes.Directory ? 'd' : '-';
|
/// Provides a NameString property for FileSystemInfo.
|
||||||
mode[1] = (fileInfo.Attributes & FileAttributes.Archive) == FileAttributes.Archive ? 'a' : '-';
|
/// </summary>
|
||||||
mode[2] = (fileInfo.Attributes & FileAttributes.ReadOnly) == FileAttributes.ReadOnly ? 'r' : '-';
|
/// <param name="instance">Instance of PSObject wrapping a FileSystemInfo.</param>
|
||||||
mode[3] = (fileInfo.Attributes & FileAttributes.Hidden) == FileAttributes.Hidden ? 'h' : '-';
|
/// <returns>Name if a file or directory, Name -> Target if symlink.</returns>
|
||||||
mode[4] = (fileInfo.Attributes & FileAttributes.System) == FileAttributes.System ? 's' : '-';
|
public static string NameString(PSObject instance)
|
||||||
// Mark the last bit as a "l" if it's a reparsepoint (symbolic link or junction)
|
{
|
||||||
// Porting note: these need to be handled specially
|
return instance?.BaseObject is FileSystemInfo fileInfo
|
||||||
bool isReparsePoint = InternalSymbolicLinkLinkCodeMethods.IsReparsePoint(fileInfo);
|
? InternalSymbolicLinkLinkCodeMethods.IsReparsePoint(fileInfo)
|
||||||
bool isHardLink = InternalSymbolicLinkLinkCodeMethods.IsHardLink(fileInfo);
|
? $"{fileInfo.Name} -> {InternalSymbolicLinkLinkCodeMethods.GetTarget(instance)}"
|
||||||
mode[5] = isReparsePoint || isHardLink ? 'l' : '-';
|
: fileInfo.Name
|
||||||
|
: string.Empty;
|
||||||
|
}
|
||||||
|
|
||||||
return new string(mode);
|
/// <summary>
|
||||||
|
/// Provides a LengthString property for FileSystemInfo.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="instance">Instance of PSObject wrapping a FileSystemInfo.</param>
|
||||||
|
/// <returns>Length as a string.</returns>
|
||||||
|
public static string LengthString(PSObject instance)
|
||||||
|
{
|
||||||
|
return instance?.BaseObject is FileInfo fileInfo
|
||||||
|
? fileInfo.Attributes.HasFlag(FileAttributes.Offline)
|
||||||
|
? $"({fileInfo.Length})"
|
||||||
|
: fileInfo.Length.ToString()
|
||||||
|
: string.Empty;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Provides a LastWriteTimeString property for FileSystemInfo.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="instance">Instance of PSObject wrapping a FileSystemInfo.</param>
|
||||||
|
/// <returns>LastWriteTime formatted as short date + short time.</returns>
|
||||||
|
public static string LastWriteTimeString(PSObject instance)
|
||||||
|
{
|
||||||
|
return instance?.BaseObject is FileSystemInfo fileInfo
|
||||||
|
? string.Format(CultureInfo.CurrentCulture, "{0,10:d} {0,8:t}", fileInfo.LastWriteTime)
|
||||||
|
: string.Empty;
|
||||||
}
|
}
|
||||||
|
|
||||||
#region RenameItem
|
#region RenameItem
|
||||||
@ -2481,8 +2547,8 @@ namespace Microsoft.PowerShell.Commands
|
|||||||
flags |= NativeMethods.SymbolicLinkFlags.AllowUnprivilegedCreate;
|
flags |= NativeMethods.SymbolicLinkFlags.AllowUnprivilegedCreate;
|
||||||
}
|
}
|
||||||
|
|
||||||
int created = NativeMethods.CreateSymbolicLink(path, strTargetPath, flags);
|
var created = NativeMethods.CreateSymbolicLink(path, strTargetPath, flags);
|
||||||
return (created == 1) ? true : false;
|
return created;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static bool WinCreateHardLink(string path, string strTargetPath)
|
private static bool WinCreateHardLink(string path, string strTargetPath)
|
||||||
@ -7013,7 +7079,8 @@ namespace Microsoft.PowerShell.Commands
|
|||||||
/// <param name="symbolicLinkFlags">Flag values from SymbolicLinkFlags enum.</param>
|
/// <param name="symbolicLinkFlags">Flag values from SymbolicLinkFlags enum.</param>
|
||||||
/// <returns>1 on successful creation.</returns>
|
/// <returns>1 on successful creation.</returns>
|
||||||
[DllImport(PinvokeDllNames.CreateSymbolicLinkDllName, CharSet = CharSet.Unicode, SetLastError = true)]
|
[DllImport(PinvokeDllNames.CreateSymbolicLinkDllName, CharSet = CharSet.Unicode, SetLastError = true)]
|
||||||
internal static extern int CreateSymbolicLink(string name, string destination, SymbolicLinkFlags symbolicLinkFlags);
|
[return: MarshalAs(UnmanagedType.I1)]
|
||||||
|
internal static extern bool CreateSymbolicLink(string name, string destination, SymbolicLinkFlags symbolicLinkFlags);
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Flags used when creating a symbolic link.
|
/// Flags used when creating a symbolic link.
|
||||||
@ -7034,7 +7101,7 @@ namespace Microsoft.PowerShell.Commands
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// Allow creation of symbolic link without elevation. Requires Developer mode.
|
/// Allow creation of symbolic link without elevation. Requires Developer mode.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
AllowUnprivilegedCreate = 2
|
AllowUnprivilegedCreate = 2,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@ -7709,7 +7776,7 @@ namespace Microsoft.PowerShell.Commands
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="instance">The object of FileInfo or DirectoryInfo type.</param>
|
/// <param name="instance">The object of FileInfo or DirectoryInfo type.</param>
|
||||||
/// <returns>The target of the reparse point.</returns>
|
/// <returns>The target of the reparse point.</returns>
|
||||||
public static IEnumerable<string> GetTarget(PSObject instance)
|
public static string GetTarget(PSObject instance)
|
||||||
{
|
{
|
||||||
if (instance.BaseObject is FileSystemInfo fileSysInfo)
|
if (instance.BaseObject is FileSystemInfo fileSysInfo)
|
||||||
{
|
{
|
||||||
@ -7718,13 +7785,11 @@ namespace Microsoft.PowerShell.Commands
|
|||||||
{
|
{
|
||||||
string linkTarget = WinInternalGetTarget(handle);
|
string linkTarget = WinInternalGetTarget(handle);
|
||||||
|
|
||||||
if (linkTarget != null)
|
return linkTarget;
|
||||||
{
|
|
||||||
return (new string[] { linkTarget });
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
#else
|
||||||
|
return UnixInternalGetTarget(fileSysInfo.FullName);
|
||||||
#endif
|
#endif
|
||||||
return InternalGetTarget(fileSysInfo.FullName);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return null;
|
return null;
|
||||||
@ -7743,84 +7808,23 @@ namespace Microsoft.PowerShell.Commands
|
|||||||
{
|
{
|
||||||
return InternalGetLinkType(fileSysInfo);
|
return InternalGetLinkType(fileSysInfo);
|
||||||
}
|
}
|
||||||
else
|
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static List<string> InternalGetTarget(string filePath)
|
|
||||||
{
|
|
||||||
var links = new List<string>();
|
|
||||||
#if UNIX
|
#if UNIX
|
||||||
|
private static string UnixInternalGetTarget(string filePath)
|
||||||
|
{
|
||||||
string link = Platform.NonWindowsInternalGetTarget(filePath);
|
string link = Platform.NonWindowsInternalGetTarget(filePath);
|
||||||
if (!string.IsNullOrEmpty(link))
|
|
||||||
{
|
if (string.IsNullOrEmpty(link))
|
||||||
links.Add(link);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
{
|
||||||
throw new Win32Exception(Marshal.GetLastWin32Error());
|
throw new Win32Exception(Marshal.GetLastWin32Error());
|
||||||
}
|
}
|
||||||
|
|
||||||
#elif !CORECLR // FindFirstFileName, FindNextFileName and FindClose are not available on Core Clr
|
return link;
|
||||||
UInt32 linkStringLength = 0;
|
|
||||||
var linkName = new StringBuilder();
|
|
||||||
|
|
||||||
// First get the length for the linkName buffer.
|
|
||||||
IntPtr fileHandle = InternalSymbolicLinkLinkCodeMethods.FindFirstFileName(filePath, 0, ref linkStringLength, linkName);
|
|
||||||
int lastError = Marshal.GetLastWin32Error();
|
|
||||||
|
|
||||||
// Return handle is INVALID_HANDLE_VALUE and LastError was ERROR_MORE_DATA
|
|
||||||
if ((fileHandle == (IntPtr)(-1)) && (lastError == 234))
|
|
||||||
{
|
|
||||||
linkName = new StringBuilder((int)linkStringLength);
|
|
||||||
fileHandle = InternalSymbolicLinkLinkCodeMethods.FindFirstFileName(filePath, 0, ref linkStringLength, linkName);
|
|
||||||
lastError = Marshal.GetLastWin32Error();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (fileHandle == (IntPtr)(-1))
|
|
||||||
{
|
|
||||||
throw new Win32Exception(lastError);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool continueFind = false;
|
|
||||||
|
|
||||||
try
|
|
||||||
{
|
|
||||||
do
|
|
||||||
{
|
|
||||||
StringBuilder fullName = new StringBuilder();
|
|
||||||
fullName.Append(Path.GetPathRoot(filePath)); // hard link source and target must be on the same drive. So we can use the source for find the path root.
|
|
||||||
fullName.Append(linkName.ToString());
|
|
||||||
FileInfo fInfo = new FileInfo(fullName.ToString());
|
|
||||||
|
|
||||||
// Don't add the target link to the list.
|
|
||||||
if (string.Compare(fInfo.FullName, filePath, StringComparison.OrdinalIgnoreCase) != 0)
|
|
||||||
links.Add(fInfo.FullName);
|
|
||||||
|
|
||||||
continueFind = InternalSymbolicLinkLinkCodeMethods.FindNextFileName(fileHandle, ref linkStringLength, linkName);
|
|
||||||
|
|
||||||
lastError = Marshal.GetLastWin32Error();
|
|
||||||
|
|
||||||
if (!continueFind && lastError == 234) // ERROR_MORE_DATA
|
|
||||||
{
|
|
||||||
linkName = new StringBuilder((int)linkStringLength);
|
|
||||||
continueFind = InternalSymbolicLinkLinkCodeMethods.FindNextFileName(fileHandle, ref linkStringLength, linkName);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!continueFind && lastError != 38) // ERROR_HANDLE_EOF. No more links.
|
|
||||||
{
|
|
||||||
throw new Win32Exception(lastError);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
while (continueFind);
|
|
||||||
}
|
|
||||||
finally
|
|
||||||
{
|
|
||||||
InternalSymbolicLinkLinkCodeMethods.FindClose(fileHandle);
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
return links;
|
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
private static string InternalGetLinkType(FileSystemInfo fileInfo)
|
private static string InternalGetLinkType(FileSystemInfo fileInfo)
|
||||||
{
|
{
|
||||||
@ -7909,16 +7913,9 @@ namespace Microsoft.PowerShell.Commands
|
|||||||
|
|
||||||
internal static bool IsReparsePoint(FileSystemInfo fileInfo)
|
internal static bool IsReparsePoint(FileSystemInfo fileInfo)
|
||||||
{
|
{
|
||||||
if (Platform.IsWindows)
|
return Platform.IsWindows
|
||||||
{
|
? fileInfo.Attributes.HasFlag(System.IO.FileAttributes.ReparsePoint)
|
||||||
// Note that this class also has a enum called FileAttributes, so use fully qualified name
|
: Platform.NonWindowsIsSymLink(fileInfo);
|
||||||
return (fileInfo.Attributes & System.IO.FileAttributes.ReparsePoint)
|
|
||||||
== System.IO.FileAttributes.ReparsePoint;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
return Platform.NonWindowsIsSymLink(fileInfo);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
internal static bool WinIsHardLink(FileSystemInfo fileInfo)
|
internal static bool WinIsHardLink(FileSystemInfo fileInfo)
|
||||||
|
@ -10,5 +10,10 @@
|
|||||||
|
|
||||||
<TreatWarningsAsErrors>true</TreatWarningsAsErrors>
|
<TreatWarningsAsErrors>true</TreatWarningsAsErrors>
|
||||||
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
|
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
|
||||||
|
<IsWindows Condition="'$(OS)' == 'Windows_NT'">true</IsWindows>
|
||||||
|
</PropertyGroup>
|
||||||
|
|
||||||
|
<PropertyGroup Condition=" '$(IsWindows)' != 'true' ">
|
||||||
|
<DefineConstants>$(DefineConstants);UNIX</DefineConstants>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
</Project>
|
</Project>
|
||||||
|
@ -190,3 +190,51 @@ Describe "Get-ChildItem" -Tags "CI" {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Describe 'FileSystem Provider Formatting' -Tag "CI","RequireAdminOnWindows" {
|
||||||
|
|
||||||
|
BeforeAll {
|
||||||
|
$modeTestDir = New-Item -Path "$TestDrive/testmodedirectory" -ItemType Directory -Force
|
||||||
|
$targetFile1 = New-Item -Path "$TestDrive/targetFile1" -ItemType File -Force
|
||||||
|
$targetFile2 = New-Item -Path "$TestDrive/targetFile2" -ItemType File -Force
|
||||||
|
$targetDir1 = New-Item -Path "$TestDrive/targetDir1" -ItemType Directory -Force
|
||||||
|
$targetDir2 = New-Item -Path "$TestDrive/targetDir2" -ItemType Directory -Force
|
||||||
|
|
||||||
|
$testcases = @(
|
||||||
|
@{ expectedMode = "d----"; expectedModeWithoutHardlink = "d----"; itemType = "Directory"; itemName = "Directory"; fileAttributes = [System.IO.FileAttributes] "Directory"; target = $null }
|
||||||
|
@{ expectedMode = "l----"; expectedModeWithoutHardlink = "l----"; itemType = "SymbolicLink"; itemName = "SymbolicLink-Directory"; fileAttributes = [System.IO.FileAttributes]::Directory -bor [System.IO.FileAttributes]::ReparsePoint; target = $targetDir2.FullName }
|
||||||
|
)
|
||||||
|
|
||||||
|
if ($IsWindows)
|
||||||
|
{
|
||||||
|
$testcases += @{ expectedMode = "l----"; expectedModeWithoutHardlink = "l----"; itemType = "Junction"; itemName = "Junction-Directory"; fileAttributes = [System.IO.FileAttributes]::Directory -bor [System.IO.FileAttributes]::ReparsePoint; target = $targetDir1.FullName }
|
||||||
|
$testcases += @{ expectedMode = "-a---"; expectedModeWithoutHardlink = "-a---"; itemType = "File"; itemName = "ArchiveFile"; fileAttributes = [System.IO.FileAttributes] "Archive"; target = $null }
|
||||||
|
$testcases += @{ expectedMode = "la---"; expectedModeWithoutHardlink = "la---"; itemType = "SymbolicLink"; itemName = "SymbolicLink-File"; fileAttributes = [System.IO.FileAttributes]::Archive -bor [System.IO.FileAttributes]::ReparsePoint; target = $targetFile1.FullName }
|
||||||
|
$testcases += @{ expectedMode = "la---"; expectedModeWithoutHardlink = "-a---"; itemType = "HardLink"; itemName = "HardLink"; fileAttributes = [System.IO.FileAttributes] "Archive"; target = $targetFile2.FullName }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
It 'Validate Mode property - <itemName>' -TestCases $testcases {
|
||||||
|
|
||||||
|
param($expectedMode, $expectedModeWithoutHardlink, $itemType, $itemName, $fileAttributes, $target)
|
||||||
|
|
||||||
|
$item = if ($target)
|
||||||
|
{
|
||||||
|
New-Item -Path $modeTestDir -Name $itemName -ItemType $itemType -Target $target
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
New-Item -Path $modeTestDir -Name $itemName -ItemType $itemType
|
||||||
|
}
|
||||||
|
|
||||||
|
$item | Should -BeOfType "System.IO.FileSystemInfo"
|
||||||
|
|
||||||
|
$actualMode = [Microsoft.PowerShell.Commands.FileSystemProvider]::Mode($item)
|
||||||
|
$actualMode | Should -BeExactly $expectedMode
|
||||||
|
|
||||||
|
$actualModeWithoutHardlink = [Microsoft.PowerShell.Commands.FileSystemProvider]::ModeWithoutHardlink($item)
|
||||||
|
$actualModeWithoutHardlink | Should -BeExactly $expectedModeWithoutHardlink
|
||||||
|
|
||||||
|
$item.Attributes | Should -Be $fileAttributes
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -15,7 +15,7 @@ Describe "Get-FormatData" -Tags "CI" {
|
|||||||
$format.TypeNames | Should -HaveCount 2
|
$format.TypeNames | Should -HaveCount 2
|
||||||
$format.TypeNames[0] | Should -BeExactly "System.IO.DirectoryInfo"
|
$format.TypeNames[0] | Should -BeExactly "System.IO.DirectoryInfo"
|
||||||
$format.TypeNames[1] | Should -BeExactly "System.IO.FileInfo"
|
$format.TypeNames[1] | Should -BeExactly "System.IO.FileInfo"
|
||||||
$format.FormatViewDefinition | Should -HaveCount 3
|
$format.FormatViewDefinition | Should -HaveCount 4
|
||||||
}
|
}
|
||||||
|
|
||||||
It "Should return nothing for format data requiring '-PowerShellVersion 5.1' and not provided" {
|
It "Should return nothing for format data requiring '-PowerShellVersion 5.1' and not provided" {
|
||||||
|
@ -418,7 +418,7 @@ Describe "Type inference Tests" -tags "CI" {
|
|||||||
It "Infers typeof Select-Object when Parameter is ExcludeProperty" {
|
It "Infers typeof Select-Object when Parameter is ExcludeProperty" {
|
||||||
$res = [AstTypeInference]::InferTypeOf( { [io.fileinfo]::new("file") | Select-Object -ExcludeProperty *Time*, E* }.Ast)
|
$res = [AstTypeInference]::InferTypeOf( { [io.fileinfo]::new("file") | Select-Object -ExcludeProperty *Time*, E* }.Ast)
|
||||||
$res.Count | Should -Be 1
|
$res.Count | Should -Be 1
|
||||||
$res[0].Name | Should -Be "System.Management.Automation.PSObject#Attributes:BaseName:Directory:DirectoryName:FullName:IsReadOnly:Length:LinkType:Mode:Name:Target:VersionInfo"
|
$res[0].Name | Should -BeExactly "System.Management.Automation.PSObject#Attributes:BaseName:Directory:DirectoryName:FullName:IsReadOnly:Length:LengthString:LinkType:Mode:ModeWithoutHardLink:Name:NameString:Target:VersionInfo"
|
||||||
$names = $res[0].Members.Name
|
$names = $res[0].Members.Name
|
||||||
$names -contains "BaseName" | Should -BeTrue
|
$names -contains "BaseName" | Should -BeTrue
|
||||||
$names -contains "Name" | Should -BeTrue
|
$names -contains "Name" | Should -BeTrue
|
||||||
|
@ -14,6 +14,8 @@ using System.Management.Automation.Internal.Host;
|
|||||||
using System.Management.Automation.Provider;
|
using System.Management.Automation.Provider;
|
||||||
using System.Management.Automation.Runspaces;
|
using System.Management.Automation.Runspaces;
|
||||||
using System.Reflection;
|
using System.Reflection;
|
||||||
|
using System.Reflection.Metadata;
|
||||||
|
using Microsoft.CodeAnalysis.CSharp.Syntax;
|
||||||
using Microsoft.PowerShell;
|
using Microsoft.PowerShell;
|
||||||
using Microsoft.PowerShell.Commands;
|
using Microsoft.PowerShell.Commands;
|
||||||
using Xunit;
|
using Xunit;
|
||||||
@ -107,9 +109,9 @@ namespace PSTests.Parallel
|
|||||||
executableObject = new FileInfo(System.Diagnostics.Process.GetCurrentProcess().MainModule.FileName);
|
executableObject = new FileInfo(System.Diagnostics.Process.GetCurrentProcess().MainModule.FileName);
|
||||||
}
|
}
|
||||||
|
|
||||||
Assert.Equal("d-----", FileSystemProvider.Mode(PSObject.AsPSObject(directoryObject)).Replace("r", "-"));
|
Assert.Equal("d----", FileSystemProvider.Mode(PSObject.AsPSObject(directoryObject)).Replace("r", "-"));
|
||||||
Assert.Equal("------", FileSystemProvider.Mode(PSObject.AsPSObject(fileObject)).Replace("r", "-").Replace("a", "-"));
|
Assert.Equal("-----", FileSystemProvider.Mode(PSObject.AsPSObject(fileObject)).Replace("r", "-").Replace("a", "-"));
|
||||||
Assert.Equal("------", FileSystemProvider.Mode(PSObject.AsPSObject(executableObject)).Replace("r", "-").Replace("a", "-"));
|
Assert.Equal("-----", FileSystemProvider.Mode(PSObject.AsPSObject(executableObject)).Replace("r", "-").Replace("a", "-"));
|
||||||
}
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
@ -125,13 +127,8 @@ namespace PSTests.Parallel
|
|||||||
fileSystemProvider.GetProperty(testPath, new Collection<string>(){ "IsReadOnly" });
|
fileSystemProvider.GetProperty(testPath, new Collection<string>(){ "IsReadOnly" });
|
||||||
FileInfo fileSystemObject1 = new FileInfo(testPath);
|
FileInfo fileSystemObject1 = new FileInfo(testPath);
|
||||||
PSObject psobject1 = PSObject.AsPSObject(fileSystemObject1);
|
PSObject psobject1 = PSObject.AsPSObject(fileSystemObject1);
|
||||||
foreach (PSPropertyInfo property in psobject1.Properties)
|
PSPropertyInfo property = psobject1.Properties["IsReadOnly"];
|
||||||
{
|
Assert.False((bool)property.Value);
|
||||||
if (property.Name == "IsReadOnly")
|
|
||||||
{
|
|
||||||
Assert.False((bool)property.Value);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
@ -144,13 +141,9 @@ namespace PSTests.Parallel
|
|||||||
fileSystemProvider.GetProperty(testPath, new Collection<string>(){ "Name" });
|
fileSystemProvider.GetProperty(testPath, new Collection<string>(){ "Name" });
|
||||||
FileInfo fileSystemObject1 = new FileInfo(testPath);
|
FileInfo fileSystemObject1 = new FileInfo(testPath);
|
||||||
PSObject psobject1 = PSObject.AsPSObject(fileSystemObject1);
|
PSObject psobject1 = PSObject.AsPSObject(fileSystemObject1);
|
||||||
foreach (PSPropertyInfo property in psobject1.Properties)
|
PSPropertyInfo property = psobject1.Properties["FullName"];
|
||||||
{
|
|
||||||
if (property.Name == "FullName")
|
Assert.Equal(testPath, property.Value);
|
||||||
{
|
|
||||||
Assert.Equal(testPath, property.Value);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
|
Loading…
Reference in New Issue
Block a user