From 816dac0a55c98c80321d7dc75d8146bb6127f944 Mon Sep 17 00:00:00 2001 From: Andrew Schwartzmeyer Date: Fri, 5 Aug 2016 13:29:27 -0700 Subject: [PATCH 1/4] Do not throw when getting Unix domain or user name If the attempt to get the name fails, throwing an exception results in PowerShell crashing. Instead, we should simply return empty data. "unknown" is specifically not returned because it would be ambiguous; it is not impossible to have an actual user or domain named "unknown". --- .../CoreCLR/CorePsPlatform.cs | 37 ++++++------------- 1 file changed, 12 insertions(+), 25 deletions(-) diff --git a/src/System.Management.Automation/CoreCLR/CorePsPlatform.cs b/src/System.Management.Automation/CoreCLR/CorePsPlatform.cs index 2d56cea1b..11f85272e 100644 --- a/src/System.Management.Automation/CoreCLR/CorePsPlatform.cs +++ b/src/System.Management.Automation/CoreCLR/CorePsPlatform.cs @@ -312,20 +312,18 @@ namespace System.Management.Automation internal static string NonWindowsGetDomainName() { - string fullyQualifiedName = Unix.NativeMethods.GetFullyQualifiedName(); - if (string.IsNullOrEmpty(fullyQualifiedName)) + string name = Unix.NativeMethods.GetFullyQualifiedName(); + if (!string.IsNullOrEmpty(name)) { - int lastError = Marshal.GetLastWin32Error(); - throw new InvalidOperationException("Unix.NonWindowsGetDomainName error: " + lastError); + // name is hostname.domainname, so extract domainname + int index = name.IndexOf('.'); + if (index >= 0) + { + return name.Substring(index + 1); + } } - - int index = fullyQualifiedName.IndexOf('.'); - if (index >= 0) - { - return fullyQualifiedName.Substring(index + 1); - } - - return ""; + // if the domain name could not be found, do not throw, just return empty + return string.Empty; } internal static string NonWindowsGetUserName() @@ -336,13 +334,7 @@ namespace System.Management.Automation // Hostname in this context seems to be the FQDN internal static string NonWindowsGetHostName() { - string hostName = Unix.NativeMethods.GetFullyQualifiedName(); - if (string.IsNullOrEmpty(hostName)) - { - int lastError = Marshal.GetLastWin32Error(); - throw new InvalidOperationException("Unix.NonWindowsHostName error: " + lastError); - } - return hostName; + return Unix.NativeMethods.GetFullyQualifiedName() ?? string.Empty; } internal static bool NonWindowsIsFile(string path) @@ -377,13 +369,8 @@ namespace System.Management.Automation if (string.IsNullOrEmpty(s_userName)) { s_userName = NativeMethods.GetUserName(); - if (string.IsNullOrEmpty(s_userName)) - { - int lastError = Marshal.GetLastWin32Error(); - throw new InvalidOperationException("Unix.UserName error: " + lastError); - } } - return s_userName; + return s_userName ?? string.Empty; } } From 3f9889d6da240fd49b2101188cf945295928f6ab Mon Sep 17 00:00:00 2001 From: Andrew Schwartzmeyer Date: Fri, 5 Aug 2016 13:50:51 -0700 Subject: [PATCH 2/4] Consolidate InternalGetFolderPath This logic belongs in one place, not split in two. --- .../CoreCLR/CorePsExtensions.cs | 34 ++++++++++++-- .../CoreCLR/CorePsPlatform.cs | 47 ------------------- 2 files changed, 29 insertions(+), 52 deletions(-) diff --git a/src/System.Management.Automation/CoreCLR/CorePsExtensions.cs b/src/System.Management.Automation/CoreCLR/CorePsExtensions.cs index 9b6aad4e0..6b0c77432 100644 --- a/src/System.Management.Automation/CoreCLR/CorePsExtensions.cs +++ b/src/System.Management.Automation/CoreCLR/CorePsExtensions.cs @@ -1146,13 +1146,36 @@ namespace System.Management.Automation /// private static string InternalGetFolderPath(SpecialFolder folder) { - if (!Platform.IsWindows) - { - return Platform.NonWindowsGetFolderPath(folder); - } - // The API 'SHGetFolderPath' is not available on OneCore, so we have to rely on environment variables string folderPath = null; + + #if UNIX + switch (folder) + { + case SpecialFolder.ProgramFiles: + folderPath = "/bin"; + if (!System.IO.Directory.Exists(folderPath)) { folderPath = null; } + break; + case SpecialFolder.ProgramFilesX86: + folderPath = "/usr/bin"; + if (!System.IO.Directory.Exists(folderPath)) { folderPath = null; } + break; + case SpecialFolder.System: + case SpecialFolder.SystemX86: + folderPath = "/sbin"; + if (!System.IO.Directory.Exists(folderPath)) { folderPath = null; } + break; + case SpecialFolder.Personal: + folderPath = System.Environment.GetEnvironmentVariable("HOME"); + break; + case SpecialFolder.LocalApplicationData: + folderPath = System.IO.Path.Combine(System.Environment.GetEnvironmentVariable("HOME"), ".config"); + if (!System.IO.Directory.Exists(folderPath)) { System.IO.Directory.CreateDirectory(folderPath); } + break; + default: + throw new NotSupportedException(); + } + #else string systemRoot = null; string userProfile = null; @@ -1219,6 +1242,7 @@ namespace System.Management.Automation default: throw new NotSupportedException(); } + #endif return folderPath ?? string.Empty; } diff --git a/src/System.Management.Automation/CoreCLR/CorePsPlatform.cs b/src/System.Management.Automation/CoreCLR/CorePsPlatform.cs index 11f85272e..dff618743 100644 --- a/src/System.Management.Automation/CoreCLR/CorePsPlatform.cs +++ b/src/System.Management.Automation/CoreCLR/CorePsPlatform.cs @@ -14,11 +14,6 @@ using Microsoft.Win32; using Microsoft.Win32.SafeHandles; using System.IO; -#if CORECLR -// SMA.Environment is only available on CoreCLR -using SpecialFolder = System.Management.Automation.Environment.SpecialFolder; -#endif - namespace System.Management.Automation { /// @@ -271,13 +266,6 @@ namespace System.Management.Automation return Unix.NativeMethods.GetUserFromPid(path); } -#if CORECLR - internal static string NonWindowsGetFolderPath(SpecialFolder folder) - { - return Unix.GetFolderPath(folder); - } -#endif - internal static string NonWindowsInternalGetLinkType(FileSystemInfo fileInfo) { if (NonWindowsIsSymLink(fileInfo)) @@ -393,41 +381,6 @@ namespace System.Management.Automation } } -#if CORECLR - public static string GetFolderPath(SpecialFolder folder) - { - string s = null; - switch (folder) - { - case SpecialFolder.ProgramFiles: - s = "/bin"; - break; - case SpecialFolder.ProgramFilesX86: - s = "/usr/bin"; - break; - case SpecialFolder.System: - s = "/sbin"; - break; - case SpecialFolder.SystemX86: - s = "/sbin"; - break; - case SpecialFolder.Personal: - s = System.Environment.GetEnvironmentVariable("HOME"); - break; - case SpecialFolder.LocalApplicationData: - s = System.IO.Path.Combine(System.Environment.GetEnvironmentVariable("HOME"), ".config"); - if (!System.IO.Directory.Exists(s)) - { - System.IO.Directory.CreateDirectory(s); - } - break; - default: - throw new NotSupportedException(); - } - return s; - } -#endif - public static bool IsHardLink(ref IntPtr handle) { // TODO:PSL implement using fstat to query inode refcount to see if it is a hard link From a8416d7b3049b7650f726460ed345e93f9ce3089 Mon Sep 17 00:00:00 2001 From: Andrew Schwartzmeyer Date: Fri, 5 Aug 2016 14:55:17 -0700 Subject: [PATCH 3/4] Consolidate GetUserName code Once .NET Core 1.1 becomes available, we can likely remove the entirety of CorePsExtensions.cs. --- .../CoreCLR/CorePsExtensions.cs | 39 ++++++++----------- .../CoreCLR/CorePsPlatform.cs | 5 --- .../engine/InformationRecord.cs | 19 ++++----- .../engine/InitialSessionState.cs | 8 +++- test/csharp/test_CorePsPlatform.cs | 2 +- 5 files changed, 34 insertions(+), 39 deletions(-) diff --git a/src/System.Management.Automation/CoreCLR/CorePsExtensions.cs b/src/System.Management.Automation/CoreCLR/CorePsExtensions.cs index 6b0c77432..657475c06 100644 --- a/src/System.Management.Automation/CoreCLR/CorePsExtensions.cs +++ b/src/System.Management.Automation/CoreCLR/CorePsExtensions.cs @@ -1026,25 +1026,8 @@ namespace System.Management.Automation { return Platform.NonWindowsGetDomainName(); } - } - } - internal static string WinGetUserName() - { - StringBuilder domainName = new StringBuilder(1024); - uint domainNameLen = (uint)domainName.Capacity; - - byte ret = Win32Native.GetUserNameEx(Win32Native.NameSamCompatible, domainName, ref domainNameLen); - if (ret == 1) - { - string samName = domainName.ToString(); - int index = samName.IndexOf('\\'); - if (index != -1) - { - return samName.Substring(index + 1); - } } - return string.Empty; } /// @@ -1054,14 +1037,24 @@ namespace System.Management.Automation { get { - if (Platform.IsWindows) + #if UNIX + return Platform.Unix.UserName; + #else + StringBuilder domainName = new StringBuilder(1024); + uint domainNameLen = (uint)domainName.Capacity; + + byte ret = Win32Native.GetUserNameEx(Win32Native.NameSamCompatible, domainName, ref domainNameLen); + if (ret == 1) { - return WinGetUserName(); - } - else - { - return Platform.NonWindowsGetUserName(); + string samName = domainName.ToString(); + int index = samName.IndexOf('\\'); + if (index != -1) + { + return samName.Substring(index + 1); + } } + return string.Empty; + #endif } } diff --git a/src/System.Management.Automation/CoreCLR/CorePsPlatform.cs b/src/System.Management.Automation/CoreCLR/CorePsPlatform.cs index dff618743..53b72fcbf 100644 --- a/src/System.Management.Automation/CoreCLR/CorePsPlatform.cs +++ b/src/System.Management.Automation/CoreCLR/CorePsPlatform.cs @@ -314,11 +314,6 @@ namespace System.Management.Automation return string.Empty; } - internal static string NonWindowsGetUserName() - { - return Unix.UserName; - } - // Hostname in this context seems to be the FQDN internal static string NonWindowsGetHostName() { diff --git a/src/System.Management.Automation/engine/InformationRecord.cs b/src/System.Management.Automation/engine/InformationRecord.cs index 68df207a9..9bc8f98a5 100644 --- a/src/System.Management.Automation/engine/InformationRecord.cs +++ b/src/System.Management.Automation/engine/InformationRecord.cs @@ -6,6 +6,10 @@ using Dbg = System.Management.Automation.Diagnostics; using System.Runtime.Serialization; using System.Collections.Generic; +#if CORECLR +using Environment = System.Management.Automation.Environment; +#endif + namespace System.Management.Automation { /// @@ -38,15 +42,12 @@ namespace System.Management.Automation this.TimeGenerated = DateTime.Now; this.Tags = new List(); - if (Platform.IsWindows) - { - this.User = System.Security.Principal.WindowsIdentity.GetCurrent().Name; - } - else - { - this.User = Platform.NonWindowsGetUserName(); - } - // Porting note: PsUtils.GetHostName() already handles platform specifics + // domain\user on Windows, just user on Unix + #if UNIX + this.User = Platform.Unix.UserName; + #else + this.User = System.Security.Principal.WindowsIdentity.GetCurrent().Name; + #endif this.Computer = PsUtils.GetHostName(); this.ProcessId = (uint)System.Diagnostics.Process.GetCurrentProcess().Id; this.NativeThreadId = PsUtils.GetNativeThreadId(); diff --git a/src/System.Management.Automation/engine/InitialSessionState.cs b/src/System.Management.Automation/engine/InitialSessionState.cs index d3a7a1a13..16f6a0571 100644 --- a/src/System.Management.Automation/engine/InitialSessionState.cs +++ b/src/System.Management.Automation/engine/InitialSessionState.cs @@ -3148,7 +3148,13 @@ namespace System.Management.Automation.Runspaces // otherwise use the current user name. var userName = (!string.IsNullOrEmpty(this.UserDriveUserName)) ? this.UserDriveUserName : - System.Security.Principal.WindowsIdentity.GetCurrent().Name; + // domain\user on Windows, just user on Unix + #if UNIX + Platform.Unix.UserName + #else + System.Security.Principal.WindowsIdentity.GetCurrent().Name + #endif + ; // Ensure that user name contains no invalid path characters. // MSDN indicates that logon names cannot contain any of these invalid characters, diff --git a/test/csharp/test_CorePsPlatform.cs b/test/csharp/test_CorePsPlatform.cs index 7937d539b..8974a51b4 100644 --- a/test/csharp/test_CorePsPlatform.cs +++ b/test/csharp/test_CorePsPlatform.cs @@ -34,7 +34,7 @@ namespace PSTests // The process should return an exit code of 0 on success Assert.Equal(0, process.ExitCode); // It should be the same as what our platform code returns - Assert.Equal(username, Platform.NonWindowsGetUserName()); + Assert.Equal(username, Platform.Unix.UserName()); } } From 9d164ea972add3818f2fb5cfe7da0284ad5cfeaa Mon Sep 17 00:00:00 2001 From: Andrew Schwartzmeyer Date: Fri, 5 Aug 2016 15:32:48 -0700 Subject: [PATCH 4/4] Move Unix class under Platform E.g. SMA.Platform.Unix, not just SMA.Unix. --- .../CoreCLR/CorePsPlatform.cs | 287 +++++++++--------- 1 file changed, 142 insertions(+), 145 deletions(-) diff --git a/src/System.Management.Automation/CoreCLR/CorePsPlatform.cs b/src/System.Management.Automation/CoreCLR/CorePsPlatform.cs index 53b72fcbf..8c681ae25 100644 --- a/src/System.Management.Automation/CoreCLR/CorePsPlatform.cs +++ b/src/System.Management.Automation/CoreCLR/CorePsPlatform.cs @@ -18,9 +18,6 @@ namespace System.Management.Automation { /// /// These are platform abstractions and platform specific implementations - /// - /// All these properties are calling into platform specific static classes, to make - /// sure the platform implementations are switched at runtime (including pinvokes). /// public static class Platform { @@ -31,11 +28,11 @@ namespace System.Management.Automation { get { -#if CORECLR + #if CORECLR return RuntimeInformation.IsOSPlatform(OSPlatform.Linux); -#else + #else return false; -#endif + #endif } } @@ -46,11 +43,11 @@ namespace System.Management.Automation { get { -#if CORECLR + #if CORECLR return RuntimeInformation.IsOSPlatform(OSPlatform.OSX); -#else + #else return false; -#endif + #endif } } @@ -61,11 +58,11 @@ namespace System.Management.Automation { get { -#if CORECLR + #if CORECLR return RuntimeInformation.IsOSPlatform(OSPlatform.Windows); -#else + #else return true; -#endif + #endif } } @@ -76,11 +73,11 @@ namespace System.Management.Automation { get { -#if CORECLR + #if CORECLR return true; -#else + #else return false; -#endif + #endif } } @@ -340,171 +337,171 @@ namespace System.Management.Automation // TODO:PSL clean this up return 0; } - } - internal static class Unix - { - private static string s_userName; - public static string UserName + internal static class Unix { - get + private static string s_userName; + public static string UserName { - if (string.IsNullOrEmpty(s_userName)) + get { - s_userName = NativeMethods.GetUserName(); - } - return s_userName ?? string.Empty; - } - } - - public static string TemporaryDirectory - { - get - { - // POSIX temporary directory environment variables - string[] environmentVariables = { "TMPDIR", "TMP", "TEMP", "TEMPDIR" }; - string dir = string.Empty; - foreach (string s in environmentVariables) - { - dir = System.Environment.GetEnvironmentVariable(s); - if (!string.IsNullOrEmpty(dir)) + if (string.IsNullOrEmpty(s_userName)) { - return dir; + s_userName = NativeMethods.GetUserName(); } + return s_userName ?? string.Empty; } - return "/tmp"; } - } - public static bool IsHardLink(ref IntPtr handle) - { - // TODO:PSL implement using fstat to query inode refcount to see if it is a hard link - return false; - } - - - public static bool IsHardLink(FileSystemInfo fs) - { - if (!fs.Exists || (fs.Attributes & FileAttributes.Directory) == FileAttributes.Directory) + public static string TemporaryDirectory { + get + { + // POSIX temporary directory environment variables + string[] environmentVariables = { "TMPDIR", "TMP", "TEMP", "TEMPDIR" }; + string dir = string.Empty; + foreach (string s in environmentVariables) + { + dir = System.Environment.GetEnvironmentVariable(s); + if (!string.IsNullOrEmpty(dir)) + { + return dir; + } + } + return "/tmp"; + } + } + + public static bool IsHardLink(ref IntPtr handle) + { + // TODO:PSL implement using fstat to query inode refcount to see if it is a hard link return false; } - int count; - string filePath = fs.FullName; - int ret = NativeMethods.GetLinkCount(filePath, out count); - if (ret == 1) - { - return count > 1; - } - else - { - int lastError = Marshal.GetLastWin32Error(); - throw new InvalidOperationException("Unix.IsHardLink error: " + lastError); - } - } - public static void SetDate(SetDateInfoInternal info) - { - int ret = NativeMethods.SetDate(info); - if (ret == -1) + public static bool IsHardLink(FileSystemInfo fs) { - int lastError = Marshal.GetLastWin32Error(); - throw new InvalidOperationException("Unix.NonWindowsSetDate error: " + lastError); - } - } + if (!fs.Exists || (fs.Attributes & FileAttributes.Directory) == FileAttributes.Directory) + { + return false; + } - public static bool CreateHardLink(string path, string strTargetPath) - { - int ret = NativeMethods.CreateHardLink(path, strTargetPath); - return ret == 1 ? true : false; - } - - [StructLayout(LayoutKind.Sequential)] - internal class SetDateInfoInternal - { - public int Year; - public int Month; - public int Day; - public int Hour; - public int Minute; - public int Second; - public int Millisecond; - public int DST; - - public SetDateInfoInternal(DateTime d) - { - Year = d.Year; - Month = d.Month; - Day = d.Day; - Hour = d.Hour; - Minute = d.Minute; - Second = d.Second; - Millisecond = d.Millisecond; - DST = d.IsDaylightSavingTime() ? 1 : 0; + int count; + string filePath = fs.FullName; + int ret = NativeMethods.GetLinkCount(filePath, out count); + if (ret == 1) + { + return count > 1; + } + else + { + int lastError = Marshal.GetLastWin32Error(); + throw new InvalidOperationException("Unix.IsHardLink error: " + lastError); + } } - public override string ToString() + public static void SetDate(SetDateInfoInternal info) { - string ret = String.Format("Year = {0}; Month = {1}; Day = {2}; Hour = {3}; Minute = {4}; Second = {5}; Millisec = {6}; DST = {7}", Year, Month, Day, Hour, Minute, Second, Millisecond, DST); - return ret; + int ret = NativeMethods.SetDate(info); + if (ret == -1) + { + int lastError = Marshal.GetLastWin32Error(); + throw new InvalidOperationException("Unix.NonWindowsSetDate error: " + lastError); + } } - } - internal static class NativeMethods - { - private const string psLib = "libpsl-native"; + public static bool CreateHardLink(string path, string strTargetPath) + { + int ret = NativeMethods.CreateHardLink(path, strTargetPath); + return ret == 1 ? true : false; + } - // Ansi is a misnomer, it is hardcoded to UTF-8 on Linux and OS X + [StructLayout(LayoutKind.Sequential)] + internal class SetDateInfoInternal + { + public int Year; + public int Month; + public int Day; + public int Hour; + public int Minute; + public int Second; + public int Millisecond; + public int DST; - // C bools are 1 byte and so must be marshaled as I1 + public SetDateInfoInternal(DateTime d) + { + Year = d.Year; + Month = d.Month; + Day = d.Day; + Hour = d.Hour; + Minute = d.Minute; + Second = d.Second; + Millisecond = d.Millisecond; + DST = d.IsDaylightSavingTime() ? 1 : 0; + } - [DllImport(psLib, CharSet = CharSet.Ansi, SetLastError = true)] - [return: MarshalAs(UnmanagedType.LPStr)] - internal static extern string GetUserName(); + public override string ToString() + { + string ret = String.Format("Year = {0}; Month = {1}; Day = {2}; Hour = {3}; Minute = {4}; Second = {5}; Millisec = {6}; DST = {7}", Year, Month, Day, Hour, Minute, Second, Millisecond, DST); + return ret; + } + } - [DllImport(psLib, CharSet = CharSet.Ansi, SetLastError = true)] - internal static extern int GetLinkCount([MarshalAs(UnmanagedType.LPStr)]string filePath, out int linkCount); + internal static class NativeMethods + { + private const string psLib = "libpsl-native"; - [DllImport(psLib, CharSet = CharSet.Ansi, SetLastError = true)] - [return: MarshalAs(UnmanagedType.I1)] - internal static extern bool IsSymLink([MarshalAs(UnmanagedType.LPStr)]string filePath); + // Ansi is a misnomer, it is hardcoded to UTF-8 on Linux and OS X - [DllImport(psLib, CharSet = CharSet.Ansi, SetLastError = true)] - [return: MarshalAs(UnmanagedType.I1)] - internal static extern bool IsExecutable([MarshalAs(UnmanagedType.LPStr)]string filePath); + // C bools are 1 byte and so must be marshaled as I1 - [DllImport(psLib, CharSet = CharSet.Ansi, SetLastError = true)] - [return: MarshalAs(UnmanagedType.LPStr)] - internal static extern string GetFullyQualifiedName(); + [DllImport(psLib, CharSet = CharSet.Ansi, SetLastError = true)] + [return: MarshalAs(UnmanagedType.LPStr)] + internal static extern string GetUserName(); - [DllImport(psLib, CharSet = CharSet.Ansi, SetLastError = true)] - internal static extern int SetDate(SetDateInfoInternal info); + [DllImport(psLib, CharSet = CharSet.Ansi, SetLastError = true)] + internal static extern int GetLinkCount([MarshalAs(UnmanagedType.LPStr)]string filePath, out int linkCount); - [DllImport(psLib, CharSet = CharSet.Ansi, SetLastError = true)] - [return: MarshalAs(UnmanagedType.I1)] - internal static extern bool CreateSymLink([MarshalAs(UnmanagedType.LPStr)]string filePath, - [MarshalAs(UnmanagedType.LPStr)]string target); + [DllImport(psLib, CharSet = CharSet.Ansi, SetLastError = true)] + [return: MarshalAs(UnmanagedType.I1)] + internal static extern bool IsSymLink([MarshalAs(UnmanagedType.LPStr)]string filePath); - [DllImport(psLib, CharSet = CharSet.Ansi, SetLastError = true)] - internal static extern int CreateHardLink([MarshalAs(UnmanagedType.LPStr)]string filePath, - [MarshalAs(UnmanagedType.LPStr)]string target); + [DllImport(psLib, CharSet = CharSet.Ansi, SetLastError = true)] + [return: MarshalAs(UnmanagedType.I1)] + internal static extern bool IsExecutable([MarshalAs(UnmanagedType.LPStr)]string filePath); - [DllImport(psLib, CharSet = CharSet.Ansi, SetLastError = true)] - [return: MarshalAs(UnmanagedType.LPStr)] - internal static extern string FollowSymLink([MarshalAs(UnmanagedType.LPStr)]string filePath); + [DllImport(psLib, CharSet = CharSet.Ansi, SetLastError = true)] + [return: MarshalAs(UnmanagedType.LPStr)] + internal static extern string GetFullyQualifiedName(); - [DllImport(psLib, CharSet = CharSet.Ansi, SetLastError = true)] - [return: MarshalAs(UnmanagedType.LPStr)] - internal static extern string GetUserFromPid(int pid); + [DllImport(psLib, CharSet = CharSet.Ansi, SetLastError = true)] + internal static extern int SetDate(SetDateInfoInternal info); - [DllImport(psLib, CharSet = CharSet.Ansi, SetLastError = true)] - [return: MarshalAs(UnmanagedType.I1)] - internal static extern bool IsFile([MarshalAs(UnmanagedType.LPStr)]string filePath); + [DllImport(psLib, CharSet = CharSet.Ansi, SetLastError = true)] + [return: MarshalAs(UnmanagedType.I1)] + internal static extern bool CreateSymLink([MarshalAs(UnmanagedType.LPStr)]string filePath, + [MarshalAs(UnmanagedType.LPStr)]string target); - [DllImport(psLib, CharSet = CharSet.Ansi, SetLastError = true)] - [return: MarshalAs(UnmanagedType.I1)] - internal static extern bool IsDirectory([MarshalAs(UnmanagedType.LPStr)]string filePath); + [DllImport(psLib, CharSet = CharSet.Ansi, SetLastError = true)] + internal static extern int CreateHardLink([MarshalAs(UnmanagedType.LPStr)]string filePath, + [MarshalAs(UnmanagedType.LPStr)]string target); + + [DllImport(psLib, CharSet = CharSet.Ansi, SetLastError = true)] + [return: MarshalAs(UnmanagedType.LPStr)] + internal static extern string FollowSymLink([MarshalAs(UnmanagedType.LPStr)]string filePath); + + [DllImport(psLib, CharSet = CharSet.Ansi, SetLastError = true)] + [return: MarshalAs(UnmanagedType.LPStr)] + internal static extern string GetUserFromPid(int pid); + + [DllImport(psLib, CharSet = CharSet.Ansi, SetLastError = true)] + [return: MarshalAs(UnmanagedType.I1)] + internal static extern bool IsFile([MarshalAs(UnmanagedType.LPStr)]string filePath); + + [DllImport(psLib, CharSet = CharSet.Ansi, SetLastError = true)] + [return: MarshalAs(UnmanagedType.I1)] + internal static extern bool IsDirectory([MarshalAs(UnmanagedType.LPStr)]string filePath); + } } } } // namespace System.Management.Automation