From 955d5f8bcbb38ba184b3f6ac8559ccb010ce852c Mon Sep 17 00:00:00 2001 From: Andrew Schwartzmeyer Date: Wed, 13 Jul 2016 20:27:34 -0700 Subject: [PATCH 01/30] Add bool IsDirectory(char*) to libpsl-native --- src/libpsl-native/src/CMakeLists.txt | 1 + src/libpsl-native/src/isdirectory.cpp | 51 +++++++++++++++++++++ src/libpsl-native/src/isdirectory.h | 10 ++++ src/libpsl-native/test/CMakeLists.txt | 1 + src/libpsl-native/test/test-isdirectory.cpp | 31 +++++++++++++ 5 files changed, 94 insertions(+) create mode 100644 src/libpsl-native/src/isdirectory.cpp create mode 100644 src/libpsl-native/src/isdirectory.h create mode 100644 src/libpsl-native/test/test-isdirectory.cpp diff --git a/src/libpsl-native/src/CMakeLists.txt b/src/libpsl-native/src/CMakeLists.txt index 8b3d0f19a..8fa6f89ec 100644 --- a/src/libpsl-native/src/CMakeLists.txt +++ b/src/libpsl-native/src/CMakeLists.txt @@ -8,6 +8,7 @@ add_library(psl-native SHARED getcomputername.cpp getlinkcount.cpp getfullyqualifiedname.cpp + isdirectory.cpp issymlink.cpp isexecutable.cpp setdate.cpp diff --git a/src/libpsl-native/src/isdirectory.cpp b/src/libpsl-native/src/isdirectory.cpp new file mode 100644 index 000000000..01ca0d9bb --- /dev/null +++ b/src/libpsl-native/src/isdirectory.cpp @@ -0,0 +1,51 @@ +//! @file isdirectory.cpp +//! @author Andrew Schwartzmeyer +//! @brief returns if the path is a directory + +#include +#include +#include +#include +#include +#include +#include "getstat.h" +#include "getpwuid.h" +#include "getfileowner.h" +#include "isdirectory.h" + +//! @brief returns if the path is a directory; uses stat and so follows symlinks +//! +//! IsDirectory +//! +//! @param[in] path +//! @parblock +//! A pointer to the buffer that contains the file name +//! +//! char* is marshaled as an LPStr, which on Linux is UTF-8. +//! @endparblock +//! +//! @exception errno Passes this error via errno to GetLastError: +//! - ERROR_INVALID_PARAMETER: parameter is not valid +//! +//! @retval true if directory, false otherwise +//! +bool IsDirectory(const char* path) +{ + int32_t ret = 0; + errno = 0; + + if (!path) + { + errno = ERROR_INVALID_PARAMETER; + return false; + } + + struct stat buf; + ret = GetStat(path, &buf); + if (ret != 0) + { + return false; + } + + return S_ISDIR(buf.st_mode); +} diff --git a/src/libpsl-native/src/isdirectory.h b/src/libpsl-native/src/isdirectory.h new file mode 100644 index 000000000..746d1c579 --- /dev/null +++ b/src/libpsl-native/src/isdirectory.h @@ -0,0 +1,10 @@ +#pragma once + +#include "pal.h" +#include + +PAL_BEGIN_EXTERNC + +bool IsDirectory(const char* path); + +PAL_END_EXTERNC diff --git a/src/libpsl-native/test/CMakeLists.txt b/src/libpsl-native/test/CMakeLists.txt index ed4440d2a..d3859cb7b 100644 --- a/src/libpsl-native/test/CMakeLists.txt +++ b/src/libpsl-native/test/CMakeLists.txt @@ -9,6 +9,7 @@ add_executable(psl-native-test test-getcomputername.cpp test-getlinkcount.cpp test-getfullyqualifiedname.cpp + test-isdirectory.cpp test-issymlink.cpp test-isexecutable.cpp test-createsymlink.cpp diff --git a/src/libpsl-native/test/test-isdirectory.cpp b/src/libpsl-native/test/test-isdirectory.cpp new file mode 100644 index 000000000..27c840cba --- /dev/null +++ b/src/libpsl-native/test/test-isdirectory.cpp @@ -0,0 +1,31 @@ +//! @file test-isdirectory.cpp +//! @author Andrew Schwartzmeyer +//! @brief Tests IsDirectory + +#include +#include +#include +#include "isdirectory.h" + +TEST(IsDirectoryTest, RootIsDirectory) +{ + EXPECT_TRUE(IsDirectory("/")); +} + +TEST(IsDirectoryTest, BinLsIsNotDirectory) +{ + EXPECT_FALSE(IsDirectory("/bin/ls")); +} + + +TEST(IsDirectoryTest, ReturnsFalseForFakeDirectory) +{ + EXPECT_FALSE(IsDirectory("SomeMadeUpFileNameThatDoesNotExist")); + EXPECT_EQ(errno, ERROR_FILE_NOT_FOUND); +} + +TEST(IsDirectoryTest, ReturnsFalseForNullInput) +{ + EXPECT_FALSE(IsDirectory(NULL)); + EXPECT_EQ(errno, ERROR_INVALID_PARAMETER); +} From 3dacf45789d76d64606adddd420d35759ea743a0 Mon Sep 17 00:00:00 2001 From: Andrew Schwartzmeyer Date: Wed, 13 Jul 2016 20:34:03 -0700 Subject: [PATCH 02/30] Revert NativeItemExists changes from baseline --- .../engine/Utils.cs | 86 +------------------ 1 file changed, 4 insertions(+), 82 deletions(-) diff --git a/src/System.Management.Automation/engine/Utils.cs b/src/System.Management.Automation/engine/Utils.cs index 8dd8f96be..4cd800298 100644 --- a/src/System.Management.Automation/engine/Utils.cs +++ b/src/System.Management.Automation/engine/Utils.cs @@ -984,38 +984,9 @@ namespace System.Management.Automation return NativeItemExists(path, out unusedIsDirectory, out unusedException); } + // This is done through P/Invoke since File.Exists and Directory.Exists pay 13% performance degradation + // through the CAS checks, and are terribly slow for network paths. internal static bool NativeItemExists(string path, out bool isDirectory, out Exception exception) - { - if (Platform.UseDotNetToQueryFileAttributes()) - { - // TODO:PSL replace by System.IO.File.GetAttributes - exception = null; - if (NativeDirectoryExists(path)) - { - isDirectory = true; - return true; - } - else if (NativeFileExists(path)) - { - isDirectory = false; - return true; - } - else - { - isDirectory = false; - return false; - } - } - else - { - // This is done through P/Invoke since File.Exists and Directory.Exists - // pay 13% performance degradation through the CAS checks, and are - // terribly slow for network paths. - return WinNativeItemExists(path,out isDirectory,out exception); - } - } - - internal static bool WinNativeItemExists(string path, out bool isDirectory, out Exception exception) { exception = null; @@ -1059,21 +1030,9 @@ namespace System.Management.Automation return true; } + // This is done through P/Invoke since we pay 13% performance degradation + // through the CAS checks required by File.Exists and Directory.Exists internal static bool NativeFileExists(string path) - { - if (Platform.UseDotNetToQueryFileAttributes()) - { - return System.IO.File.Exists(path); - } - else - { - // This is done through P/Invoke since we pay 13% performance degradation - // through the CAS checks required by File.Exists and Directory.Exists - return WinNativeFileExists(path); - } - } - - internal static bool WinNativeFileExists(string path) { bool isDirectory; Exception ioException; @@ -1090,18 +1049,6 @@ namespace System.Management.Automation // This is done through P/Invoke since we pay 13% performance degradation // through the CAS checks required by File.Exists and Directory.Exists internal static bool NativeDirectoryExists(string path) - { - if (Platform.UseDotNetToQueryFileAttributes()) - { - return System.IO.Directory.Exists(path); - } - else - { - return WinNativeDirectoryExists(path); - } - } - - internal static bool WinNativeDirectoryExists(string path) { bool isDirectory; Exception ioException; @@ -1116,31 +1063,6 @@ namespace System.Management.Automation } internal static void NativeEnumerateDirectory(string directory, out List directories, out List files) - { - if (Platform.UseDotNetToQueryFileAttributes()) - { - IEnumerable fileEnum = System.IO.Directory.EnumerateFiles(directory); - IEnumerable dirEnum = System.IO.Directory.EnumerateDirectories(directory); - - files = new List(); - directories = new List(); - - foreach (string entry in fileEnum) - { - files.Add(directory + "/" + entry); - } - foreach (string entry in dirEnum) - { - directories.Add(directory + "/" + entry); - } - } - else - { - WinNativeEnumerateDirectory(directory, out directories, out files); - } - } - - internal static void WinNativeEnumerateDirectory(string directory, out List directories, out List files) { IntPtr INVALID_HANDLE_VALUE = new IntPtr(-1); NativeMethods.WIN32_FIND_DATA findData; From 90a5382b30053019324a5d591c66073b41994a45 Mon Sep 17 00:00:00 2001 From: Andrew Schwartzmeyer Date: Wed, 13 Jul 2016 20:50:00 -0700 Subject: [PATCH 03/30] Add bool IsFile(char*) to libpsl-native --- src/libpsl-native/src/CMakeLists.txt | 1 + src/libpsl-native/src/isfile.cpp | 40 ++++++++++++++++++++++++++ src/libpsl-native/src/isfile.h | 10 +++++++ src/libpsl-native/test/CMakeLists.txt | 1 + src/libpsl-native/test/test-isfile.cpp | 30 +++++++++++++++++++ 5 files changed, 82 insertions(+) create mode 100644 src/libpsl-native/src/isfile.cpp create mode 100644 src/libpsl-native/src/isfile.h create mode 100644 src/libpsl-native/test/test-isfile.cpp diff --git a/src/libpsl-native/src/CMakeLists.txt b/src/libpsl-native/src/CMakeLists.txt index 8fa6f89ec..22e8f5dd8 100644 --- a/src/libpsl-native/src/CMakeLists.txt +++ b/src/libpsl-native/src/CMakeLists.txt @@ -8,6 +8,7 @@ add_library(psl-native SHARED getcomputername.cpp getlinkcount.cpp getfullyqualifiedname.cpp + isfile.cpp isdirectory.cpp issymlink.cpp isexecutable.cpp diff --git a/src/libpsl-native/src/isfile.cpp b/src/libpsl-native/src/isfile.cpp new file mode 100644 index 000000000..b2cead6cd --- /dev/null +++ b/src/libpsl-native/src/isfile.cpp @@ -0,0 +1,40 @@ +//! @file isfile.cpp +//! @author Andrew Schwartzmeyer +//! @brief returns if the path exists + +#include +#include +#include +#include +#include +#include +#include "isfile.h" + +//! @brief returns if the path is a file or directory +//! +//! IsFile +//! +//! @param[in] path +//! @parblock +//! A pointer to the buffer that contains the file name +//! +//! char* is marshaled as an LPStr, which on Linux is UTF-8. +//! @endparblock +//! +//! @exception errno Passes this error via errno to GetLastError: +//! - ERROR_INVALID_PARAMETER: parameter is not valid +//! +//! @retval true if path exists, false otherwise +//! +bool IsFile(const char* path) +{ + errno = 0; + + if (!path) + { + errno = ERROR_INVALID_PARAMETER; + return false; + } + + return access(path, F_OK) != -1; +} diff --git a/src/libpsl-native/src/isfile.h b/src/libpsl-native/src/isfile.h new file mode 100644 index 000000000..53a15f97d --- /dev/null +++ b/src/libpsl-native/src/isfile.h @@ -0,0 +1,10 @@ +#pragma once + +#include "pal.h" +#include + +PAL_BEGIN_EXTERNC + +bool IsFile(const char* path); + +PAL_END_EXTERNC diff --git a/src/libpsl-native/test/CMakeLists.txt b/src/libpsl-native/test/CMakeLists.txt index d3859cb7b..2f57741b0 100644 --- a/src/libpsl-native/test/CMakeLists.txt +++ b/src/libpsl-native/test/CMakeLists.txt @@ -10,6 +10,7 @@ add_executable(psl-native-test test-getlinkcount.cpp test-getfullyqualifiedname.cpp test-isdirectory.cpp + test-isfile.cpp test-issymlink.cpp test-isexecutable.cpp test-createsymlink.cpp diff --git a/src/libpsl-native/test/test-isfile.cpp b/src/libpsl-native/test/test-isfile.cpp new file mode 100644 index 000000000..09d72f5bf --- /dev/null +++ b/src/libpsl-native/test/test-isfile.cpp @@ -0,0 +1,30 @@ +//! @file test-isfile.cpp +//! @author Andrew Schwartzmeyer +//! @brief Tests Isfile + +#include +#include +#include +#include "isfile.h" + +TEST(IsFileTest, RootIsFile) +{ + EXPECT_TRUE(IsFile("/")); +} + +TEST(IsFileTest, BinLsIsFile) +{ + EXPECT_TRUE(IsFile("/bin/ls")); +} + +TEST(IsFileTest, CannotGetOwnerOfFakeFile) +{ + EXPECT_FALSE(IsFile("SomeMadeUpFileNameThatDoesNotExist")); + EXPECT_EQ(errno, ERROR_FILE_NOT_FOUND); +} + +TEST(IsFileTest, ReturnsFalseForNullInput) +{ + EXPECT_FALSE(IsFile(NULL)); + EXPECT_EQ(errno, ERROR_INVALID_PARAMETER); +} From 77a9b4b5d22c377e1f637a574d76b073772f45cd Mon Sep 17 00:00:00 2001 From: Andrew Schwartzmeyer Date: Wed, 13 Jul 2016 21:02:00 -0700 Subject: [PATCH 04/30] Remove unnecessary throws in CorePsPlatform --- .../CoreCLR/CorePsPlatform.cs | 164 ++++-------------- 1 file changed, 35 insertions(+), 129 deletions(-) diff --git a/src/System.Management.Automation/CoreCLR/CorePsPlatform.cs b/src/System.Management.Automation/CoreCLR/CorePsPlatform.cs index eb9d3b262..5a4dfccb6 100644 --- a/src/System.Management.Automation/CoreCLR/CorePsPlatform.cs +++ b/src/System.Management.Automation/CoreCLR/CorePsPlatform.cs @@ -318,22 +318,12 @@ namespace System.Management.Automation internal static bool NonWindowsIsHardLink(FileSystemInfo fileInfo) { - if (!IsWindows) - { - return LinuxPlatform.IsHardLink(fileInfo); - } - - throw new PlatformNotSupportedException(); + return LinuxPlatform.IsHardLink(fileInfo); } internal static bool NonWindowsIsSymLink(FileSystemInfo fileInfo) { - if (!IsWindows) - { - return LinuxPlatform.IsSymLink(fileInfo); - } - - throw new PlatformNotSupportedException(); + return LinuxPlatform.IsSymLink(fileInfo); } internal static string NonWindowsInternalGetTarget(SafeFileHandle handle) @@ -344,166 +334,91 @@ namespace System.Management.Automation internal static string NonWindowsInternalGetTarget(string path) { - if (!IsWindows) - { - return LinuxPlatform.FollowSymLink(path); - } - else - { - throw new PlatformNotSupportedException(); - } + return LinuxPlatform.FollowSymLink(path); } internal static string NonWindowsGetUserFromPid(int path) { - if (!IsWindows) - { - return LinuxPlatform.GetUserFromPid(path); - } - else - { - throw new PlatformNotSupportedException(); - } + return LinuxPlatform.GetUserFromPid(path); } #if CORECLR internal static string NonWindowsGetFolderPath(SpecialFolder folder) { - if (!IsWindows) - { - return LinuxPlatform.GetFolderPath(folder); - } - else - { - throw new PlatformNotSupportedException(); - } + return LinuxPlatform.GetFolderPath(folder); } #endif internal static string NonWindowsInternalGetLinkType(FileSystemInfo fileInfo) { - if (!IsWindows) + if (NonWindowsIsSymLink(fileInfo)) { - if (NonWindowsIsSymLink(fileInfo)) - { - return "SymbolicLink"; - } - if (NonWindowsIsHardLink(fileInfo)) - { - return "HardLink"; - } - return null; - } - else - { - throw new PlatformNotSupportedException(); + return "SymbolicLink"; } + if (NonWindowsIsHardLink(fileInfo)) + { + return "HardLink"; + } + + return null; } internal static bool NonWindowsCreateSymbolicLink(string path, string strTargetPath, bool isDirectory) { - if (!IsWindows) - { - // Linux doesn't care if target is a directory or not - return LinuxPlatform.CreateSymbolicLink(path, strTargetPath); - } - else - { - throw new PlatformNotSupportedException(); - } + // Linux doesn't care if target is a directory or not + return LinuxPlatform.CreateSymbolicLink(path, strTargetPath); } internal static bool NonWindowsCreateHardLink(string path, string strTargetPath) { - if (!IsWindows) - { - return LinuxPlatform.CreateHardLink(path, strTargetPath); - } - else - { - throw new PlatformNotSupportedException(); - } + return LinuxPlatform.CreateHardLink(path, strTargetPath); } internal static void NonWindowsSetDate(DateTime dateToUse) { - if (!IsWindows) - { - LinuxPlatform.SetDateInfoInternal date = new LinuxPlatform.SetDateInfoInternal(dateToUse); - LinuxPlatform.SetDate(date); - } - else - { - throw new PlatformNotSupportedException(); - } + LinuxPlatform.SetDateInfoInternal date = new LinuxPlatform.SetDateInfoInternal(dateToUse); + LinuxPlatform.SetDate(date); } internal static string NonWindowsGetDomainName() { - if (!IsWindows) + string fullyQualifiedName = LinuxPlatform.Native.GetFullyQualifiedName(); + if (string.IsNullOrEmpty(fullyQualifiedName)) { - string fullyQualifiedName = LinuxPlatform.Native.GetFullyQualifiedName(); - if (string.IsNullOrEmpty(fullyQualifiedName)) - { - int lastError = Marshal.GetLastWin32Error(); - throw new InvalidOperationException("LinuxPlatform.NonWindowsGetDomainName error: " + lastError); - } - - int index = fullyQualifiedName.IndexOf('.'); - if (index >= 0) - { - return fullyQualifiedName.Substring(index + 1); - } - - return ""; + int lastError = Marshal.GetLastWin32Error(); + throw new InvalidOperationException("LinuxPlatform.NonWindowsGetDomainName error: " + lastError); } - else + + int index = fullyQualifiedName.IndexOf('.'); + if (index >= 0) { - throw new PlatformNotSupportedException(); + return fullyQualifiedName.Substring(index + 1); } + + return ""; } internal static string NonWindowsGetUserName() { - if (!IsWindows) - { - return LinuxPlatform.UserName; - } - else - { - throw new PlatformNotSupportedException(); - } + return LinuxPlatform.UserName; } // Hostname in this context seems to be the FQDN internal static string NonWindowsGetHostName() { - if (!IsWindows) + string hostName = LinuxPlatform.Native.GetFullyQualifiedName(); + if (string.IsNullOrEmpty(hostName)) { - string hostName = LinuxPlatform.Native.GetFullyQualifiedName(); - if (string.IsNullOrEmpty(hostName)) - { - int lastError = Marshal.GetLastWin32Error(); - throw new InvalidOperationException("LinuxPlatform.NonWindowsHostName error: " + lastError); - } - return hostName; - - } - else - { - throw new PlatformNotSupportedException(); + int lastError = Marshal.GetLastWin32Error(); + throw new InvalidOperationException("LinuxPlatform.NonWindowsHostName error: " + lastError); } + return hostName; } internal static bool NonWindowsIsExecutable(string path) { - if (!IsWindows) - { - return LinuxPlatform.IsExecutable(path); - } - - throw new PlatformNotSupportedException(); + return LinuxPlatform.IsExecutable(path); } internal static uint NonWindowsGetThreadId() @@ -512,15 +427,6 @@ namespace System.Management.Automation return 0; } - /// - /// This exception is meant to be thrown if a code path is not supported due - /// to platform restrictions - /// - internal class PlatformNotSupportedException : System.Exception - { - public PlatformNotSupportedException() : base() {} - } - /// /// This models the native call CommandLineToArgvW in managed code. /// From 551e2e6fc4fb6ed470092ab3fa3de69764f3f062 Mon Sep 17 00:00:00 2001 From: Andrew Schwartzmeyer Date: Wed, 13 Jul 2016 21:10:43 -0700 Subject: [PATCH 05/30] Format CorePsPlatform --- .../CoreCLR/CorePsPlatform.cs | 98 +++++++++---------- 1 file changed, 49 insertions(+), 49 deletions(-) diff --git a/src/System.Management.Automation/CoreCLR/CorePsPlatform.cs b/src/System.Management.Automation/CoreCLR/CorePsPlatform.cs index 5a4dfccb6..104eed8bc 100644 --- a/src/System.Management.Automation/CoreCLR/CorePsPlatform.cs +++ b/src/System.Management.Automation/CoreCLR/CorePsPlatform.cs @@ -143,12 +143,12 @@ namespace System.Management.Automation //the user has set XDG_DATA_HOME corresponding to module path if (String.IsNullOrEmpty(xdgdatahome)){ - // create the xdg folder if needed - if (!Directory.Exists(xdgDataHomeDefault)) - { - Directory.CreateDirectory(xdgDataHomeDefault); - } - return xdgDataHomeDefault; + // create the xdg folder if needed + if (!Directory.Exists(xdgDataHomeDefault)) + { + Directory.CreateDirectory(xdgDataHomeDefault); + } + return xdgDataHomeDefault; } else { @@ -159,12 +159,12 @@ namespace System.Management.Automation //the user has set XDG_DATA_HOME corresponding to module path if (String.IsNullOrEmpty(xdgdatahome)){ - //xdg values have not been set - if (!Directory.Exists(xdgModuleDefault)) //module folder not always guaranteed to exist - { - Directory.CreateDirectory(xdgModuleDefault); - } - return xdgModuleDefault; + //xdg values have not been set + if (!Directory.Exists(xdgModuleDefault)) //module folder not always guaranteed to exist + { + Directory.CreateDirectory(xdgModuleDefault); + } + return xdgModuleDefault; } else { @@ -175,7 +175,7 @@ namespace System.Management.Automation //the user has set XDG_CACHE_HOME if (String.IsNullOrEmpty(xdgcachehome)) { - //xdg values have not been set + //xdg values have not been set if (!Directory.Exists(xdgCacheDefault)) //module folder not always guaranteed to exist { Directory.CreateDirectory(xdgCacheDefault); @@ -342,12 +342,12 @@ namespace System.Management.Automation return LinuxPlatform.GetUserFromPid(path); } -#if CORECLR + #if CORECLR internal static string NonWindowsGetFolderPath(SpecialFolder folder) { return LinuxPlatform.GetFolderPath(folder); } -#endif + #endif internal static string NonWindowsInternalGetLinkType(FileSystemInfo fileInfo) { @@ -526,40 +526,40 @@ namespace System.Management.Automation } } -#if CORECLR + #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(); + 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 + #endif public static bool IsHardLink(ref IntPtr handle) { @@ -602,12 +602,12 @@ namespace System.Management.Automation switch(ret) { case 1: - return true; + return true; case 0: - return false; + return false; default: - int lastError = Marshal.GetLastWin32Error(); - throw new InvalidOperationException("LinuxPlatform.IsSymLink error: " + lastError); + int lastError = Marshal.GetLastWin32Error(); + throw new InvalidOperationException("LinuxPlatform.IsSymLink error: " + lastError); } } @@ -622,12 +622,12 @@ namespace System.Management.Automation switch(ret) { case 1: - return true; + return true; case 0: - return false; + return false; default: - int lastError = Marshal.GetLastWin32Error(); - throw new InvalidOperationException("LinuxPlatform.IsExecutable error: " + lastError); + int lastError = Marshal.GetLastWin32Error(); + throw new InvalidOperationException("LinuxPlatform.IsExecutable error: " + lastError); } } From 6a23655b2f1e6e7632d766bd0ac69d5882221b72 Mon Sep 17 00:00:00 2001 From: Andrew Schwartzmeyer Date: Wed, 13 Jul 2016 21:11:34 -0700 Subject: [PATCH 06/30] Rename LinuxPlatform to Unix Since it supports both Linux and OS X. This follows the .NET Core convention. --- .../CoreCLR/CorePsPlatform.cs | 44 +++++++++---------- 1 file changed, 22 insertions(+), 22 deletions(-) diff --git a/src/System.Management.Automation/CoreCLR/CorePsPlatform.cs b/src/System.Management.Automation/CoreCLR/CorePsPlatform.cs index 104eed8bc..3487d4113 100644 --- a/src/System.Management.Automation/CoreCLR/CorePsPlatform.cs +++ b/src/System.Management.Automation/CoreCLR/CorePsPlatform.cs @@ -313,17 +313,17 @@ namespace System.Management.Automation internal static bool NonWindowsIsHardLink(ref IntPtr handle) { - return LinuxPlatform.IsHardLink(ref handle); + return Unix.IsHardLink(ref handle); } internal static bool NonWindowsIsHardLink(FileSystemInfo fileInfo) { - return LinuxPlatform.IsHardLink(fileInfo); + return Unix.IsHardLink(fileInfo); } internal static bool NonWindowsIsSymLink(FileSystemInfo fileInfo) { - return LinuxPlatform.IsSymLink(fileInfo); + return Unix.IsSymLink(fileInfo); } internal static string NonWindowsInternalGetTarget(SafeFileHandle handle) @@ -334,18 +334,18 @@ namespace System.Management.Automation internal static string NonWindowsInternalGetTarget(string path) { - return LinuxPlatform.FollowSymLink(path); + return Unix.FollowSymLink(path); } internal static string NonWindowsGetUserFromPid(int path) { - return LinuxPlatform.GetUserFromPid(path); + return Unix.GetUserFromPid(path); } #if CORECLR internal static string NonWindowsGetFolderPath(SpecialFolder folder) { - return LinuxPlatform.GetFolderPath(folder); + return Unix.GetFolderPath(folder); } #endif @@ -367,27 +367,27 @@ namespace System.Management.Automation internal static bool NonWindowsCreateSymbolicLink(string path, string strTargetPath, bool isDirectory) { // Linux doesn't care if target is a directory or not - return LinuxPlatform.CreateSymbolicLink(path, strTargetPath); + return Unix.CreateSymbolicLink(path, strTargetPath); } internal static bool NonWindowsCreateHardLink(string path, string strTargetPath) { - return LinuxPlatform.CreateHardLink(path, strTargetPath); + return Unix.CreateHardLink(path, strTargetPath); } internal static void NonWindowsSetDate(DateTime dateToUse) { - LinuxPlatform.SetDateInfoInternal date = new LinuxPlatform.SetDateInfoInternal(dateToUse); - LinuxPlatform.SetDate(date); + Unix.SetDateInfoInternal date = new Unix.SetDateInfoInternal(dateToUse); + Unix.SetDate(date); } internal static string NonWindowsGetDomainName() { - string fullyQualifiedName = LinuxPlatform.Native.GetFullyQualifiedName(); + string fullyQualifiedName = Unix.Native.GetFullyQualifiedName(); if (string.IsNullOrEmpty(fullyQualifiedName)) { int lastError = Marshal.GetLastWin32Error(); - throw new InvalidOperationException("LinuxPlatform.NonWindowsGetDomainName error: " + lastError); + throw new InvalidOperationException("Unix.NonWindowsGetDomainName error: " + lastError); } int index = fullyQualifiedName.IndexOf('.'); @@ -401,24 +401,24 @@ namespace System.Management.Automation internal static string NonWindowsGetUserName() { - return LinuxPlatform.UserName; + return Unix.UserName; } // Hostname in this context seems to be the FQDN internal static string NonWindowsGetHostName() { - string hostName = LinuxPlatform.Native.GetFullyQualifiedName(); + string hostName = Unix.Native.GetFullyQualifiedName(); if (string.IsNullOrEmpty(hostName)) { int lastError = Marshal.GetLastWin32Error(); - throw new InvalidOperationException("LinuxPlatform.NonWindowsHostName error: " + lastError); + throw new InvalidOperationException("Unix.NonWindowsHostName error: " + lastError); } return hostName; } internal static bool NonWindowsIsExecutable(string path) { - return LinuxPlatform.IsExecutable(path); + return Unix.IsExecutable(path); } internal static uint NonWindowsGetThreadId() @@ -487,7 +487,7 @@ namespace System.Management.Automation } } - internal static class LinuxPlatform + internal static class Unix { private static string _userName; public static string UserName @@ -500,7 +500,7 @@ namespace System.Management.Automation if (string.IsNullOrEmpty(_userName)) { int lastError = Marshal.GetLastWin32Error(); - throw new InvalidOperationException("LinuxPlatform.UserName error: " + lastError); + throw new InvalidOperationException("Unix.UserName error: " + lastError); } } return _userName; @@ -585,7 +585,7 @@ namespace System.Management.Automation else { int lastError = Marshal.GetLastWin32Error(); - throw new InvalidOperationException("LinuxPlatform.IsHardLink error: " + lastError); + throw new InvalidOperationException("Unix.IsHardLink error: " + lastError); } } @@ -607,7 +607,7 @@ namespace System.Management.Automation return false; default: int lastError = Marshal.GetLastWin32Error(); - throw new InvalidOperationException("LinuxPlatform.IsSymLink error: " + lastError); + throw new InvalidOperationException("Unix.IsSymLink error: " + lastError); } } @@ -627,7 +627,7 @@ namespace System.Management.Automation return false; default: int lastError = Marshal.GetLastWin32Error(); - throw new InvalidOperationException("LinuxPlatform.IsExecutable error: " + lastError); + throw new InvalidOperationException("Unix.IsExecutable error: " + lastError); } } @@ -637,7 +637,7 @@ namespace System.Management.Automation if (ret == -1) { int lastError = Marshal.GetLastWin32Error(); - throw new InvalidOperationException("LinuxPlatform.NonWindowsSetDate error: " + lastError); + throw new InvalidOperationException("Unix.NonWindowsSetDate error: " + lastError); } } From 093587fecbdf51e252ddca0a1ff0fd0372e6b147 Mon Sep 17 00:00:00 2001 From: Andrew Schwartzmeyer Date: Wed, 13 Jul 2016 21:12:45 -0700 Subject: [PATCH 07/30] Rename Native so it is Unix.NativeMethods Like the rest of PowerShell. --- .../CoreCLR/CorePsPlatform.cs | 24 +++++++++---------- 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/src/System.Management.Automation/CoreCLR/CorePsPlatform.cs b/src/System.Management.Automation/CoreCLR/CorePsPlatform.cs index 3487d4113..27d5d2091 100644 --- a/src/System.Management.Automation/CoreCLR/CorePsPlatform.cs +++ b/src/System.Management.Automation/CoreCLR/CorePsPlatform.cs @@ -383,7 +383,7 @@ namespace System.Management.Automation internal static string NonWindowsGetDomainName() { - string fullyQualifiedName = Unix.Native.GetFullyQualifiedName(); + string fullyQualifiedName = Unix.NativeMethods.GetFullyQualifiedName(); if (string.IsNullOrEmpty(fullyQualifiedName)) { int lastError = Marshal.GetLastWin32Error(); @@ -407,7 +407,7 @@ namespace System.Management.Automation // Hostname in this context seems to be the FQDN internal static string NonWindowsGetHostName() { - string hostName = Unix.Native.GetFullyQualifiedName(); + string hostName = Unix.NativeMethods.GetFullyQualifiedName(); if (string.IsNullOrEmpty(hostName)) { int lastError = Marshal.GetLastWin32Error(); @@ -496,7 +496,7 @@ namespace System.Management.Automation { if (string.IsNullOrEmpty(_userName)) { - _userName = Native.GetUserName(); + _userName = NativeMethods.GetUserName(); if (string.IsNullOrEmpty(_userName)) { int lastError = Marshal.GetLastWin32Error(); @@ -577,7 +577,7 @@ namespace System.Management.Automation int count; string filePath = fs.FullName; - int ret = Native.GetLinkCount(filePath, out count); + int ret = NativeMethods.GetLinkCount(filePath, out count); if (ret == 1) { return count > 1; @@ -598,7 +598,7 @@ namespace System.Management.Automation } string filePath = fs.FullName; - int ret = Native.IsSymLink(filePath); + int ret = NativeMethods.IsSymLink(filePath); switch(ret) { case 1: @@ -618,7 +618,7 @@ namespace System.Management.Automation return false; } - int ret = Native.IsExecutable(filePath); + int ret = NativeMethods.IsExecutable(filePath); switch(ret) { case 1: @@ -633,7 +633,7 @@ namespace System.Management.Automation public static void SetDate(SetDateInfoInternal info) { - int ret = Native.SetDate(info); + int ret = NativeMethods.SetDate(info); if (ret == -1) { int lastError = Marshal.GetLastWin32Error(); @@ -643,24 +643,24 @@ namespace System.Management.Automation public static bool CreateSymbolicLink(string path, string strTargetPath) { - int ret = Native.CreateSymLink(path, strTargetPath); + int ret = NativeMethods.CreateSymLink(path, strTargetPath); return ret == 1 ? true : false; } public static bool CreateHardLink(string path, string strTargetPath) { - int ret = Native.CreateHardLink(path, strTargetPath); + int ret = NativeMethods.CreateHardLink(path, strTargetPath); return ret == 1 ? true : false; } public static string FollowSymLink(string path) { - return Native.FollowSymLink(path); + return NativeMethods.FollowSymLink(path); } public static string GetUserFromPid(int pid) { - return Native.GetUserFromPid(pid); + return NativeMethods.GetUserFromPid(pid); } [StructLayout(LayoutKind.Sequential)] @@ -694,7 +694,7 @@ namespace System.Management.Automation } } - internal static class Native + internal static class NativeMethods { const string psLib = "libpsl-native"; From 4e518fe1c7bcca9c7a7cbbc978dd4829afa288fd Mon Sep 17 00:00:00 2001 From: Andrew Schwartzmeyer Date: Wed, 13 Jul 2016 21:15:45 -0700 Subject: [PATCH 08/30] Remove Platform class override of PlatformNotSupportedException This was confusing and unused in most places, exception itself removed in cleanup. --- .../namespaces/FileSystemProvider.cs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/System.Management.Automation/namespaces/FileSystemProvider.cs b/src/System.Management.Automation/namespaces/FileSystemProvider.cs index 39c60e005..50a84e98b 100644 --- a/src/System.Management.Automation/namespaces/FileSystemProvider.cs +++ b/src/System.Management.Automation/namespaces/FileSystemProvider.cs @@ -496,7 +496,7 @@ namespace Microsoft.PowerShell.Commands } else { - throw new Platform.PlatformNotSupportedException(); + throw new PlatformNotSupportedException(); } } @@ -753,7 +753,7 @@ namespace Microsoft.PowerShell.Commands } else { - throw new Platform.PlatformNotSupportedException(); + throw new PlatformNotSupportedException(); } } @@ -8202,7 +8202,7 @@ namespace Microsoft.PowerShell.Commands { if (!Platform.IsWindows) { - throw new Platform.PlatformNotSupportedException(); + throw new PlatformNotSupportedException(); } using (SafeFileHandle handle = OpenReparsePoint(filePath, FileDesiredAccess.GenericRead)) @@ -8601,7 +8601,7 @@ namespace Microsoft.PowerShell.Commands } else { - throw new Platform.PlatformNotSupportedException(); + throw new PlatformNotSupportedException(); } } From e89fa7b1dc779e8fa28b28b80658e8bac462da0e Mon Sep 17 00:00:00 2001 From: Andrew Schwartzmeyer Date: Wed, 13 Jul 2016 21:39:34 -0700 Subject: [PATCH 09/30] Clean up IsExecutable and IsSymLink --- .../CoreCLR/CorePsPlatform.cs | 8 ++- src/libpsl-native/src/isexecutable.cpp | 58 +++---------------- src/libpsl-native/src/isexecutable.h | 3 +- src/libpsl-native/src/issymlink.cpp | 27 ++++----- src/libpsl-native/src/issymlink.h | 3 +- src/libpsl-native/test/test-isexecutable.cpp | 30 ++++------ src/libpsl-native/test/test-issymlink.cpp | 47 +++++---------- 7 files changed, 56 insertions(+), 120 deletions(-) diff --git a/src/System.Management.Automation/CoreCLR/CorePsPlatform.cs b/src/System.Management.Automation/CoreCLR/CorePsPlatform.cs index 27d5d2091..5d3a05290 100644 --- a/src/System.Management.Automation/CoreCLR/CorePsPlatform.cs +++ b/src/System.Management.Automation/CoreCLR/CorePsPlatform.cs @@ -700,6 +700,8 @@ namespace System.Management.Automation // Ansi is a misnomer, it is hardcoded to UTF-8 on Linux and OS X + // 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 GetUserName(); @@ -708,10 +710,12 @@ namespace System.Management.Automation internal static extern int GetLinkCount([MarshalAs(UnmanagedType.LPStr)]string filePath, out int linkCount); [DllImport(psLib, CharSet = CharSet.Ansi, SetLastError = true)] - internal static extern int IsSymLink([MarshalAs(UnmanagedType.LPStr)]string filePath); + [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 IsExecutable([MarshalAs(UnmanagedType.LPStr)]string filePath); + [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)] diff --git a/src/libpsl-native/src/isexecutable.cpp b/src/libpsl-native/src/isexecutable.cpp index 38f6ad184..a06fab57a 100644 --- a/src/libpsl-native/src/isexecutable.cpp +++ b/src/libpsl-native/src/isexecutable.cpp @@ -1,5 +1,5 @@ -//! @file isExecutable.cpp -//! @author George FLeming +//! @file isexecutable.cpp +//! @author George Fleming //! @brief returns whether a file is executable #include @@ -11,7 +11,7 @@ //! //! IsExecutable //! -//! @param[in] fileName +//! @param[in] path //! @parblock //! A pointer to the buffer that contains the file name //! @@ -19,63 +19,21 @@ //! @endparblock //! //! @exception errno Passes these errors via errno to GetLastError: -//! - ERROR_FILE_NOT_FOUND: the system cannot find the file specified //! - ERROR_INVALID_ADDRESS: attempt to access invalid address -//! - ERROR_GEN_FAILURE: device attached to the system is not functioning -//! - ERROR_INVALID_NAME: filename, directory name, or volume label syntax is incorrect -//! - ERROR_INVALID_FUNCTION: incorrect function -//! - ERROR_INVALID_PARAMETER: parameter to access(2) call is incorrect //! -//! @retval 1 if path is an executable -//! @retval 0 if path is not a executable -//! @retval -1 If the function fails.. To get extended error information, call GetLastError. +//! @retval true if path is an executable, false otherwise //! -int32_t IsExecutable(const char* fileName) +bool IsExecutable(const char* path) { errno = 0; // Check parameters - if (!fileName) + if (!path) { errno = ERROR_INVALID_PARAMETER; - return -1; + return false; } - int returnCode = access(fileName, X_OK); - - if (returnCode == 0) - { - return 1; - } - - switch(errno) - { - case EACCES: - return 0; - case EBADF: - case ENOENT: - errno = ERROR_FILE_NOT_FOUND; - break; - case EFAULT: - errno = ERROR_INVALID_ADDRESS; - break; - case ELOOP: - errno = ERROR_STOPPED_ON_SYMLINK; - break; - case EIO: - case ENOMEM: - errno = ERROR_GEN_FAILURE; - break; - case ENOTDIR: - case ENAMETOOLONG: - errno = ERROR_INVALID_NAME; - break; - case EINVAL: - errno = ERROR_INVALID_PARAMETER; - break; - default: - errno = ERROR_INVALID_FUNCTION; - } - return -1; + return access(path, X_OK) != -1; } diff --git a/src/libpsl-native/src/isexecutable.h b/src/libpsl-native/src/isexecutable.h index da4e9f8f3..f4278b954 100644 --- a/src/libpsl-native/src/isexecutable.h +++ b/src/libpsl-native/src/isexecutable.h @@ -1,9 +1,10 @@ #pragma once #include "pal.h" +#include PAL_BEGIN_EXTERNC -int32_t IsExecutable(const char* fileName); +bool IsExecutable(const char* path); PAL_END_EXTERNC diff --git a/src/libpsl-native/src/issymlink.cpp b/src/libpsl-native/src/issymlink.cpp index d4ce011cb..dfd37d8bc 100644 --- a/src/libpsl-native/src/issymlink.cpp +++ b/src/libpsl-native/src/issymlink.cpp @@ -9,11 +9,11 @@ #include #include "issymlink.h" -//! @brief IsSymLink determines if path is a symbolic link +//! @brief IsSymlink determines if path is a symbolic link //! -//! IsSymLink +//! IsSymlink //! -//! @param[in] fileName +//! @param[in] path //! @parblock //! A pointer to the buffer that contains the file name //! @@ -34,28 +34,25 @@ //! - ERROR_INVALID_FUNCTION: incorrect function //! - ERROR_BAD_PATH_NAME: pathname is too long, or contains invalid characters //! -//! @retval 1 if path is a symbolic link -//! @retval 0 if path is not a symbolic link -//! @retval -1 If the function fails.. To get extended error information, call GetLastError. +//! @retval true if path is a symbolic link, false otherwise //! -int32_t IsSymLink(const char* fileName) +bool IsSymLink(const char* path) { - - errno = 0; + errno = 0; // Check parameters - if (!fileName) + if (!path) { errno = ERROR_INVALID_PARAMETER; - return -1; + return false; } struct stat statBuf; - int returnCode = lstat(fileName, &statBuf); + int ret = lstat(path, &statBuf); - if (returnCode != 0) + if (ret != 0) { switch(errno) { @@ -89,8 +86,8 @@ int32_t IsSymLink(const char* fileName) default: errno = ERROR_INVALID_FUNCTION; } - return -1; + return false; } - return S_ISLNK(statBuf.st_mode) ? 1 : 0; + return S_ISLNK(statBuf.st_mode); } diff --git a/src/libpsl-native/src/issymlink.h b/src/libpsl-native/src/issymlink.h index 066a4060c..ebe3733c5 100644 --- a/src/libpsl-native/src/issymlink.h +++ b/src/libpsl-native/src/issymlink.h @@ -1,9 +1,10 @@ #pragma once #include "pal.h" +#include PAL_BEGIN_EXTERNC -int32_t IsSymLink(const char* fileName); +bool IsSymLink(const char* path); PAL_END_EXTERNC diff --git a/src/libpsl-native/test/test-isexecutable.cpp b/src/libpsl-native/test/test-isexecutable.cpp index 36955912f..d97d7d315 100644 --- a/src/libpsl-native/test/test-isexecutable.cpp +++ b/src/libpsl-native/test/test-isexecutable.cpp @@ -33,62 +33,52 @@ protected: // First create a file int fd = mkstemp(fileTemplateBuf); EXPECT_TRUE(fd != -1); - file = fileTemplateBuf; + file = fileTemplateBuf; } ~IsExecutableTest() { - int ret; - - ret = unlink(file); - EXPECT_EQ(0, ret); + EXPECT_FALSE(unlink(file)); } void ChangeFilePermission(const char* file, mode_t mode) { - int ret = chmod(file, mode); - EXPECT_EQ(ret, 0); + EXPECT_FALSE(chmod(file, mode)); } }; TEST_F(IsExecutableTest, FilePathNameIsNull) { - int32_t retVal = IsExecutable(NULL); - EXPECT_EQ(retVal, -1); + EXPECT_FALSE(IsExecutable(NULL)); EXPECT_EQ(ERROR_INVALID_PARAMETER, errno); } TEST_F(IsExecutableTest, FilePathNameDoesNotExist) { std::string invalidFile = "/tmp/isexecutabletest_invalidFile"; - int32_t retVal = IsExecutable(invalidFile.c_str()); - EXPECT_EQ(retVal, -1); + EXPECT_FALSE(IsExecutable(invalidFile.c_str())); EXPECT_EQ(ERROR_FILE_NOT_FOUND, errno); } TEST_F(IsExecutableTest, NormalFileIsNotIsexecutable) { - int32_t retVal = IsExecutable(file); - EXPECT_EQ(0, retVal); - + EXPECT_FALSE(IsExecutable(file)); + ChangeFilePermission(file, mode_444); - retVal = IsExecutable(file); - EXPECT_EQ(0, retVal); + EXPECT_FALSE(IsExecutable(file)); } TEST_F(IsExecutableTest, FilePermission_700) { ChangeFilePermission(file, mode_700); - int32_t retVal = IsExecutable(file); - EXPECT_EQ(1, retVal); + EXPECT_TRUE(IsExecutable(file)); } TEST_F(IsExecutableTest, FilePermission_777) { ChangeFilePermission(file, mode_777); - int32_t retVal = IsExecutable(file); - EXPECT_EQ(1, retVal); + EXPECT_TRUE(IsExecutable(file)); } diff --git a/src/libpsl-native/test/test-issymlink.cpp b/src/libpsl-native/test/test-issymlink.cpp index 4aaa3eb54..512a4053a 100644 --- a/src/libpsl-native/test/test-issymlink.cpp +++ b/src/libpsl-native/test/test-issymlink.cpp @@ -30,75 +30,60 @@ protected: // First create a file int fd = mkstemp(fileTemplateBuf); EXPECT_TRUE(fd != -1); - file = fileTemplateBuf; + file = fileTemplateBuf; - // Create a temp directory - dir = mkdtemp(dirTemplateBuf); + // Create a temp directory + dir = mkdtemp(dirTemplateBuf); EXPECT_TRUE(dir != NULL); // Create symbolic link to file - int ret1 = symlink(file, fileSymLink.c_str()); - EXPECT_EQ(ret1, 0); - + EXPECT_FALSE(symlink(file, fileSymLink.c_str())); + // Create symbolic link to directory - int ret2 = symlink(dir, dirSymLink.c_str()); - EXPECT_EQ(ret2, 0); + EXPECT_FALSE(symlink(dir, dirSymLink.c_str())); } ~isSymLinkTest() { - int ret; + EXPECT_FALSE(unlink(fileSymLink.c_str())); - ret = unlink(fileSymLink.c_str()); - EXPECT_EQ(0, ret); + EXPECT_FALSE(unlink(dirSymLink.c_str())); - ret = unlink(dirSymLink.c_str()); - EXPECT_EQ(0, ret); + EXPECT_FALSE(unlink(file)); - ret = unlink(file); - EXPECT_EQ(0, ret); - - ret = rmdir(dir); - EXPECT_EQ(0, ret); + EXPECT_FALSE(rmdir(dir)); } }; TEST_F(isSymLinkTest, FilePathNameIsNull) { - int retVal = IsSymLink(NULL); - EXPECT_EQ(retVal, -1); + EXPECT_FALSE(IsSymLink(NULL)); EXPECT_EQ(ERROR_INVALID_PARAMETER, errno); } TEST_F(isSymLinkTest, FilePathNameDoesNotExist) { std::string invalidFile = "/tmp/symlinktest_invalidFile"; - int retVal = IsSymLink(invalidFile.c_str()); - EXPECT_EQ(retVal, -1); + EXPECT_FALSE(IsSymLink(invalidFile.c_str())); EXPECT_EQ(ERROR_FILE_NOT_FOUND, errno); } TEST_F(isSymLinkTest, NormalFileIsNotSymLink) { - int retVal = IsSymLink(file); - EXPECT_EQ(0, retVal); + EXPECT_FALSE(IsSymLink(file)); } TEST_F(isSymLinkTest, SymLinkToFile) { - int retVal = IsSymLink(fileSymLink.c_str()); - EXPECT_EQ(1, retVal); + EXPECT_TRUE(IsSymLink(fileSymLink.c_str())); } TEST_F(isSymLinkTest, NormalDirectoryIsNotSymbLink) { - int retVal = IsSymLink(dir); - EXPECT_EQ(0, retVal); + EXPECT_FALSE(IsSymLink(dir)); } TEST_F(isSymLinkTest, SymLinkToDirectory) { - int retVal = IsSymLink(dirSymLink.c_str()); - EXPECT_EQ(1, retVal); + EXPECT_TRUE(IsSymLink(dirSymLink.c_str())); } - From 5ef851a1704f277a3174ded0c9a534fba701f8c7 Mon Sep 17 00:00:00 2001 From: Andrew Schwartzmeyer Date: Wed, 13 Jul 2016 21:44:04 -0700 Subject: [PATCH 10/30] Port NativeItemExists for Linux Without using .NET --- .../CoreCLR/CorePsPlatform.cs | 54 ++++++++----------- .../engine/Utils.cs | 5 ++ 2 files changed, 26 insertions(+), 33 deletions(-) diff --git a/src/System.Management.Automation/CoreCLR/CorePsPlatform.cs b/src/System.Management.Automation/CoreCLR/CorePsPlatform.cs index 5d3a05290..1050e96b6 100644 --- a/src/System.Management.Automation/CoreCLR/CorePsPlatform.cs +++ b/src/System.Management.Automation/CoreCLR/CorePsPlatform.cs @@ -416,6 +416,16 @@ namespace System.Management.Automation return hostName; } + internal static bool NonWindowsIsFile(string path) + { + return Unix.NativeMethods.IsFile(path); + } + + internal static bool NonWindowsIsDirectory(string path) + { + return Unix.NativeMethods.IsDirectory(path); + } + internal static bool NonWindowsIsExecutable(string path) { return Unix.IsExecutable(path); @@ -592,43 +602,12 @@ namespace System.Management.Automation public static bool IsSymLink(FileSystemInfo fs) { - if (!fs.Exists) - { - return false; - } - - string filePath = fs.FullName; - int ret = NativeMethods.IsSymLink(filePath); - switch(ret) - { - case 1: - return true; - case 0: - return false; - default: - int lastError = Marshal.GetLastWin32Error(); - throw new InvalidOperationException("Unix.IsSymLink error: " + lastError); - } + return NativeMethods.IsSymLink(fs.FullName); } public static bool IsExecutable(string filePath) { - if (!File.Exists(filePath)) - { - return false; - } - - int ret = NativeMethods.IsExecutable(filePath); - switch(ret) - { - case 1: - return true; - case 0: - return false; - default: - int lastError = Marshal.GetLastWin32Error(); - throw new InvalidOperationException("Unix.IsExecutable error: " + lastError); - } + return NativeMethods.IsExecutable(filePath); } public static void SetDate(SetDateInfoInternal info) @@ -739,6 +718,15 @@ namespace System.Management.Automation [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); + } } diff --git a/src/System.Management.Automation/engine/Utils.cs b/src/System.Management.Automation/engine/Utils.cs index 4cd800298..ec06e5250 100644 --- a/src/System.Management.Automation/engine/Utils.cs +++ b/src/System.Management.Automation/engine/Utils.cs @@ -995,6 +995,10 @@ namespace System.Management.Automation isDirectory = false; return false; } +#if LINUX + isDirectory = Platform.NonWindowsIsDirectory(path); + return Platform.NonWindowsIsFile(path); +#else if (IsReservedDeviceName(path)) { @@ -1028,6 +1032,7 @@ namespace System.Management.Automation ((int)NativeMethods.FileAttributes.Directory); return true; +#endif } // This is done through P/Invoke since we pay 13% performance degradation From 46cfa268121dffa6b230e19c41db4c88fddf3813 Mon Sep 17 00:00:00 2001 From: Andrew Schwartzmeyer Date: Thu, 14 Jul 2016 11:25:13 -0700 Subject: [PATCH 11/30] Remove Platform.HasCom query --- .../CoreCLR/CorePsPlatform.cs | 8 -------- .../engine/runtime/Binding/Binders.cs | 13 +++++-------- .../utils/ExtensionMethods.cs | 9 +++------ test/csharp/test_CorePsPlatform.cs | 6 ------ 4 files changed, 8 insertions(+), 28 deletions(-) diff --git a/src/System.Management.Automation/CoreCLR/CorePsPlatform.cs b/src/System.Management.Automation/CoreCLR/CorePsPlatform.cs index 1050e96b6..8c016c54e 100644 --- a/src/System.Management.Automation/CoreCLR/CorePsPlatform.cs +++ b/src/System.Management.Automation/CoreCLR/CorePsPlatform.cs @@ -217,14 +217,6 @@ namespace System.Management.Automation } - // ComObjectType is null on CoreCLR for Linux since there is - // no COM support on Linux - internal static bool HasCom() - { - // TODO: catch exception from Type.IsComObject - return IsWindows; - } - // The Antimalware Scan Interface is not supported on Linux internal static bool HasAmsi() { diff --git a/src/System.Management.Automation/engine/runtime/Binding/Binders.cs b/src/System.Management.Automation/engine/runtime/Binding/Binders.cs index 50592a4e4..8d598b13b 100644 --- a/src/System.Management.Automation/engine/runtime/Binding/Binders.cs +++ b/src/System.Management.Automation/engine/runtime/Binding/Binders.cs @@ -677,14 +677,11 @@ namespace System.Management.Automation.Language private static TypeInfo GetComObjectType() { - if (Platform.HasCom()) - { - return typeof(object).GetTypeInfo().Assembly.GetType("System.__ComObject").GetTypeInfo(); - } - else - { - return null; - } +#if LINUX + return null; +#else + return typeof(object).GetTypeInfo().Assembly.GetType("System.__ComObject").GetTypeInfo(); +#endif } internal static bool IsComObject(object obj) diff --git a/src/System.Management.Automation/utils/ExtensionMethods.cs b/src/System.Management.Automation/utils/ExtensionMethods.cs index 0e58cc55f..1c1c76f19 100644 --- a/src/System.Management.Automation/utils/ExtensionMethods.cs +++ b/src/System.Management.Automation/utils/ExtensionMethods.cs @@ -130,12 +130,9 @@ namespace System.Management.Automation [MethodImpl(MethodImplOptions.AggressiveInlining)] internal static bool IsComObject(this Type type) { - if (!Platform.HasCom()) - { - return false; - } - -#if CORECLR // Type.IsComObject(Type) is not in CoreCLR +#if LINUX + return false; +#elif CORECLR // Type.IsComObject(Type) is not in CoreCLR return ComObjectType.IsAssignableFrom(type); #else return type.IsCOMObject; diff --git a/test/csharp/test_CorePsPlatform.cs b/test/csharp/test_CorePsPlatform.cs index d0132b121..ce979e818 100644 --- a/test/csharp/test_CorePsPlatform.cs +++ b/test/csharp/test_CorePsPlatform.cs @@ -15,12 +15,6 @@ namespace PSTests Assert.True(Platform.IsCore); } - [Fact] - public static void TestHasCom() - { - Assert.False(Platform.HasCom()); - } - [Fact] public static void TestHasAmsi() { From c9a4197af1ad7d473dcdd85c768714c3b2b92f54 Mon Sep 17 00:00:00 2001 From: Andrew Schwartzmeyer Date: Thu, 14 Jul 2016 11:29:55 -0700 Subject: [PATCH 12/30] Remove Platform.HasAmsi query --- .../CoreCLR/CorePsPlatform.cs | 6 --- .../security/SecuritySupport.cs | 50 ++++++------------- test/csharp/test_CorePsPlatform.cs | 6 --- 3 files changed, 14 insertions(+), 48 deletions(-) diff --git a/src/System.Management.Automation/CoreCLR/CorePsPlatform.cs b/src/System.Management.Automation/CoreCLR/CorePsPlatform.cs index 8c016c54e..f56051716 100644 --- a/src/System.Management.Automation/CoreCLR/CorePsPlatform.cs +++ b/src/System.Management.Automation/CoreCLR/CorePsPlatform.cs @@ -217,12 +217,6 @@ namespace System.Management.Automation } - // The Antimalware Scan Interface is not supported on Linux - internal static bool HasAmsi() - { - return IsWindows; - } - // This is mainly with respect to the auto-mounting of // disconnected network drives on Windows internal static bool HasDriveAutoMounting() diff --git a/src/System.Management.Automation/security/SecuritySupport.cs b/src/System.Management.Automation/security/SecuritySupport.cs index 05ae9f77d..f66d8094c 100644 --- a/src/System.Management.Automation/security/SecuritySupport.cs +++ b/src/System.Management.Automation/security/SecuritySupport.cs @@ -1633,14 +1633,11 @@ namespace System.Management.Automation /// AMSI_RESULT_DETECTED if malware was detected in the sample. internal static AmsiNativeMethods.AMSI_RESULT ScanContent(string content, string sourceMetadata) { - if (Platform.HasAmsi()) - { - return WinScanContent(content,sourceMetadata); - } - else - { - return AmsiNativeMethods.AMSI_RESULT.AMSI_RESULT_NOT_DETECTED; - } +#if LINUX + return AmsiNativeMethods.AMSI_RESULT.AMSI_RESULT_NOT_DETECTED; +#else + return WinScanContent(content,sourceMetadata); +#endif } internal static AmsiNativeMethods.AMSI_RESULT WinScanContent(string content, string sourceMetadata) @@ -1730,14 +1727,9 @@ namespace System.Management.Automation internal static void CurrentDomain_ProcessExit(object sender, EventArgs e) { - if (Platform.HasAmsi()) - { - VerifyAmsiUninitializeCalled(); - } - else - { - throw new PlatformNotSupportedException(); - } +#if !LINUX + VerifyAmsiUninitializeCalled(); +#endif } [SuppressMessage("Microsoft.Reliability", "CA2006:UseSafeHandleToEncapsulateNativeResources")] @@ -1753,16 +1745,9 @@ namespace System.Management.Automation /// internal static void CloseSession() { - if (Platform.HasAmsi()) - { - WinCloseSession(); - } - else - { - // Porting note: cannot throw here because this is called whether or not - // AMSI was initialized in the first place - return; - } +#if !LINUX + WinCloseSession(); +#endif } internal static void WinCloseSession() @@ -1789,16 +1774,9 @@ namespace System.Management.Automation /// internal static void Uninitialize() { - if (Platform.HasAmsi()) - { - WinUninitialize(); - } - else - { - // Porting note: cannot throw here because this is called whether or not - // AMSI was initialized in the first place - return; - } +#if !LINUX + WinUninitialize(); +#endif } internal static void WinUninitialize() diff --git a/test/csharp/test_CorePsPlatform.cs b/test/csharp/test_CorePsPlatform.cs index ce979e818..8709dccab 100644 --- a/test/csharp/test_CorePsPlatform.cs +++ b/test/csharp/test_CorePsPlatform.cs @@ -15,12 +15,6 @@ namespace PSTests Assert.True(Platform.IsCore); } - [Fact] - public static void TestHasAmsi() - { - Assert.False(Platform.HasAmsi()); - } - [Fact] public static void TestHasDriveAutoMounting() { From c2cd059aa80ad79557cbad56c2c721a6bbdea90c Mon Sep 17 00:00:00 2001 From: Andrew Schwartzmeyer Date: Thu, 14 Jul 2016 11:40:07 -0700 Subject: [PATCH 13/30] Remove Platform.HasDriveAutoMounting query --- src/System.Management.Automation/CoreCLR/CorePsPlatform.cs | 7 ------- .../engine/SessionStateDriveAPIs.cs | 5 +++-- test/csharp/test_CorePsPlatform.cs | 6 ------ 3 files changed, 3 insertions(+), 15 deletions(-) diff --git a/src/System.Management.Automation/CoreCLR/CorePsPlatform.cs b/src/System.Management.Automation/CoreCLR/CorePsPlatform.cs index f56051716..35ba1a55e 100644 --- a/src/System.Management.Automation/CoreCLR/CorePsPlatform.cs +++ b/src/System.Management.Automation/CoreCLR/CorePsPlatform.cs @@ -217,13 +217,6 @@ namespace System.Management.Automation } - // This is mainly with respect to the auto-mounting of - // disconnected network drives on Windows - internal static bool HasDriveAutoMounting() - { - return IsWindows; - } - // Linux does not have a registry internal static bool HasRegistrySupport() { diff --git a/src/System.Management.Automation/engine/SessionStateDriveAPIs.cs b/src/System.Management.Automation/engine/SessionStateDriveAPIs.cs index d7e0f8e38..6de20eee2 100644 --- a/src/System.Management.Automation/engine/SessionStateDriveAPIs.cs +++ b/src/System.Management.Automation/engine/SessionStateDriveAPIs.cs @@ -1469,11 +1469,12 @@ namespace System.Management.Automation bool driveIsValid = true; // If the drive is auto-mounted, ensure that it still exists, or remove the drive. - // note: not all platforms support drive auto-mounting - if (Platform.HasDriveAutoMounting() && (drive.IsAutoMounted || IsAStaleVhdMountedDrive(drive))) +#if !LINUX + if (drive.IsAutoMounted || IsAStaleVhdMountedDrive(drive)) { driveIsValid = ValidateOrRemoveAutoMountedDrive(drive, lookupScope); } +#endif if(drive.Name.Length == 1) { if(!(driveNames.Contains(drive.Name))) diff --git a/test/csharp/test_CorePsPlatform.cs b/test/csharp/test_CorePsPlatform.cs index 8709dccab..44784983f 100644 --- a/test/csharp/test_CorePsPlatform.cs +++ b/test/csharp/test_CorePsPlatform.cs @@ -15,12 +15,6 @@ namespace PSTests Assert.True(Platform.IsCore); } - [Fact] - public static void TestHasDriveAutoMounting() - { - Assert.False(Platform.HasDriveAutoMounting()); - } - [Fact] public static void TestHasRegistrySupport() { From 73a1a51f69c64ee27f9cc18b7dad1eb59fab1ed0 Mon Sep 17 00:00:00 2001 From: Andrew Schwartzmeyer Date: Thu, 14 Jul 2016 11:54:54 -0700 Subject: [PATCH 14/30] Remove Platform.HasRegistry query --- .../CoreCLR/CorePsExtensions.cs | 23 ++++++++----------- .../CoreCLR/CorePsPlatform.cs | 6 ----- .../engine/CommandDiscovery.cs | 7 ++---- .../engine/PSVersionInfo.cs | 7 ++---- .../engine/Utils.cs | 13 ++++------- .../remoting/commands/remotingcommandutil.cs | 11 ++++----- .../namespaces/RegistryProvider.cs | 7 ++---- .../namespaces/SafeRegistryHandle.cs | 8 +++---- test/csharp/test_CorePsPlatform.cs | 6 ----- 9 files changed, 29 insertions(+), 59 deletions(-) diff --git a/src/System.Management.Automation/CoreCLR/CorePsExtensions.cs b/src/System.Management.Automation/CoreCLR/CorePsExtensions.cs index 5674327cd..59a864d01 100644 --- a/src/System.Management.Automation/CoreCLR/CorePsExtensions.cs +++ b/src/System.Management.Automation/CoreCLR/CorePsExtensions.cs @@ -893,13 +893,10 @@ namespace System.Management.Automation return GetEnvironmentVariables(); } - if (!Platform.HasRegistrySupport()) - { - // Porting note: Does not throw a PlatformUnsupported because - // GetEnvironmentVariable cannot throw, and we want the same interface. - return null; - } - +#if LINUX + return null; +#else + if( target == EnvironmentVariableTarget.Machine) { using (RegistryKey environmentKey = @@ -916,6 +913,7 @@ namespace System.Management.Automation return GetRegistryKeyNameValuePairs(environmentKey); } } +#endif } /// @@ -956,13 +954,9 @@ namespace System.Management.Automation return System.Environment.GetEnvironmentVariable(variable); } - if (!Platform.HasRegistrySupport()) - { - // Porting note: This cannot throw since it would otherwise throw while - // creating a runspace. Returning null is appropriate to signal that there - // is no value for a registry key with no registry. - return null; - } +#if LINUX + return null; +#else if (target == EnvironmentVariableTarget.Machine) { @@ -985,6 +979,7 @@ namespace System.Management.Automation return value; } } +#endif } #endregion EnvironmentVariable_Extensions diff --git a/src/System.Management.Automation/CoreCLR/CorePsPlatform.cs b/src/System.Management.Automation/CoreCLR/CorePsPlatform.cs index 35ba1a55e..134291ed6 100644 --- a/src/System.Management.Automation/CoreCLR/CorePsPlatform.cs +++ b/src/System.Management.Automation/CoreCLR/CorePsPlatform.cs @@ -217,12 +217,6 @@ namespace System.Management.Automation } - // Linux does not have a registry - internal static bool HasRegistrySupport() - { - return IsWindows; - } - // Linux does not have PowerShell execution policies internal static bool HasExecutionPolicy() { diff --git a/src/System.Management.Automation/engine/CommandDiscovery.cs b/src/System.Management.Automation/engine/CommandDiscovery.cs index 2d0e2e917..23c95b432 100644 --- a/src/System.Management.Automation/engine/CommandDiscovery.cs +++ b/src/System.Management.Automation/engine/CommandDiscovery.cs @@ -1903,13 +1903,9 @@ namespace System.Management.Automation /// internal static string GetShellPathFromRegistry(string shellID) { - if (!Platform.HasRegistrySupport()) - { - return null; - } - string result = null; +#if !LINUX try { RegistryKey shellKey = Registry.LocalMachine.OpenSubKey(Utils.GetRegistryConfigurationPath(shellID)); @@ -1935,6 +1931,7 @@ namespace System.Management.Automation catch (ArgumentException) { } +#endif return result; } diff --git a/src/System.Management.Automation/engine/PSVersionInfo.cs b/src/System.Management.Automation/engine/PSVersionInfo.cs index d500e7e85..92aaee14e 100644 --- a/src/System.Management.Automation/engine/PSVersionInfo.cs +++ b/src/System.Management.Automation/engine/PSVersionInfo.cs @@ -103,13 +103,9 @@ namespace System.Management.Automation // Gets the current WSMan stack version from the registry. private static Version GetWSManStackVersion() { - if (!Platform.HasRegistrySupport()) - { - return new Version(1, 0); - } - Version version = null; +#if !LINUX try { using (RegistryKey wsManStackVersionKey = Registry.LocalMachine.OpenSubKey(@"Software\Microsoft\Windows\CurrentVersion\WSMAN")) @@ -133,6 +129,7 @@ namespace System.Management.Automation catch (FormatException) { } catch (OverflowException) { } catch (InvalidCastException) { } +#endif return version ?? System.Management.Automation.Remoting.Client.WSManNativeApi.WSMAN_STACK_VERSION; } diff --git a/src/System.Management.Automation/engine/Utils.cs b/src/System.Management.Automation/engine/Utils.cs index ec06e5250..878908be5 100644 --- a/src/System.Management.Automation/engine/Utils.cs +++ b/src/System.Management.Automation/engine/Utils.cs @@ -368,14 +368,11 @@ namespace System.Management.Automation /// internal static bool IsWinPEHost() { - if (Platform.HasRegistrySupport()) - { - return WinIsWinPEHost(); - } - else - { - return false; - } +#if LINUX + return false; +#else + return WinIsWinPEHost(); +#endif } internal static bool WinIsWinPEHost() diff --git a/src/System.Management.Automation/engine/remoting/commands/remotingcommandutil.cs b/src/System.Management.Automation/engine/remoting/commands/remotingcommandutil.cs index 2f0fa35d5..c3e9cc006 100644 --- a/src/System.Management.Automation/engine/remoting/commands/remotingcommandutil.cs +++ b/src/System.Management.Automation/engine/remoting/commands/remotingcommandutil.cs @@ -96,12 +96,10 @@ namespace Microsoft.PowerShell.Commands /// internal static void CheckRemotingCmdletPrerequisites() { - //If the operating system (ie Linux) does not support the registry, simply return to avoid calls to the Windows registry. - if (!Platform.HasRegistrySupport()) - { - return; - } - +#if LINUX + // TODO: check that PSRP requirements are installed + return; +#else bool notSupported = true; String WSManKeyPath = "Software\\Microsoft\\Windows\\CurrentVersion\\WSMAN\\"; @@ -155,6 +153,7 @@ namespace Microsoft.PowerShell.Commands throw new InvalidOperationException( "Windows PowerShell remoting features are not enabled or not supported on this machine.\nThis may be because you do not have the correct version of WS-Management installed or this version of Windows does not support remoting currently.\n For more information, type 'get-help about_remote_requirements'."); } +#endif } /// diff --git a/src/System.Management.Automation/namespaces/RegistryProvider.cs b/src/System.Management.Automation/namespaces/RegistryProvider.cs index 1951f59ee..9a168ff7f 100644 --- a/src/System.Management.Automation/namespaces/RegistryProvider.cs +++ b/src/System.Management.Automation/namespaces/RegistryProvider.cs @@ -136,11 +136,7 @@ namespace Microsoft.PowerShell.Commands { Collection drives = new Collection(); - if (!Platform.HasRegistrySupport()) - { - return drives; - } - +#if !LINUX drives.Add( new PSDriveInfo( "HKLM", @@ -156,6 +152,7 @@ namespace Microsoft.PowerShell.Commands "HKEY_CURRENT_USER", RegistryProviderStrings.HKCUDriveDescription, null)); +#endif return drives; } // InitializeDefaultDrives diff --git a/src/System.Management.Automation/namespaces/SafeRegistryHandle.cs b/src/System.Management.Automation/namespaces/SafeRegistryHandle.cs index 1e817966b..80120a702 100644 --- a/src/System.Management.Automation/namespaces/SafeRegistryHandle.cs +++ b/src/System.Management.Automation/namespaces/SafeRegistryHandle.cs @@ -58,13 +58,13 @@ namespace Microsoft.PowerShell.Commands.Internal override protected bool ReleaseHandle() { - if (!Platform.HasRegistrySupport()) - { - return true; - } +#if LINUX + return true; +#else // Returns a Win32 error code, 0 for success int r = RegCloseKey(handle); return r == 0; +#endif } } } diff --git a/test/csharp/test_CorePsPlatform.cs b/test/csharp/test_CorePsPlatform.cs index 44784983f..80d387891 100644 --- a/test/csharp/test_CorePsPlatform.cs +++ b/test/csharp/test_CorePsPlatform.cs @@ -15,12 +15,6 @@ namespace PSTests Assert.True(Platform.IsCore); } - [Fact] - public static void TestHasRegistrySupport() - { - Assert.False(Platform.HasRegistrySupport()); - } - [Fact] public static void TestGetUserName() { From e6c037c666ac35ea16d5e9920688f59c756de038 Mon Sep 17 00:00:00 2001 From: Andrew Schwartzmeyer Date: Thu, 14 Jul 2016 14:31:31 -0700 Subject: [PATCH 15/30] Remove Platform.HasExecutionPolicy query Also change Get-ExecutionPolicy to not throw, but to return Unrestricted (which is the effect of the actual policy). --- .../CoreCLR/CorePsPlatform.cs | 6 ---- .../security/SecuritySupport.cs | 18 ++++++------ .../ExecutionPolicy.Tests.ps1 | 28 +++++++++---------- 3 files changed, 22 insertions(+), 30 deletions(-) diff --git a/src/System.Management.Automation/CoreCLR/CorePsPlatform.cs b/src/System.Management.Automation/CoreCLR/CorePsPlatform.cs index 134291ed6..6edfbaa90 100644 --- a/src/System.Management.Automation/CoreCLR/CorePsPlatform.cs +++ b/src/System.Management.Automation/CoreCLR/CorePsPlatform.cs @@ -217,12 +217,6 @@ namespace System.Management.Automation } - // Linux does not have PowerShell execution policies - internal static bool HasExecutionPolicy() - { - return IsWindows; - } - // Linux has a single rooted file system internal static bool HasSingleRootFilesystem() { diff --git a/src/System.Management.Automation/security/SecuritySupport.cs b/src/System.Management.Automation/security/SecuritySupport.cs index f66d8094c..8d3fc91f2 100644 --- a/src/System.Management.Automation/security/SecuritySupport.cs +++ b/src/System.Management.Automation/security/SecuritySupport.cs @@ -138,11 +138,9 @@ namespace System.Management.Automation internal static void SetExecutionPolicy(ExecutionPolicyScope scope, ExecutionPolicy policy, string shellId) { - if (!Platform.HasExecutionPolicy()) - { - throw new PlatformNotSupportedException(); - } - +#if LINUX + throw new PlatformNotSupportedException(); +#else string executionPolicy = "Restricted"; string preferenceKey = Utils.GetRegistryConfigurationPath(shellId); const string PolicyKeyValueName = "ExecutionPolicy"; @@ -227,6 +225,7 @@ namespace System.Management.Automation break; } } +#endif } // Clean up the parents of a registry key as long as they @@ -283,11 +282,9 @@ namespace System.Management.Automation internal static ExecutionPolicy GetExecutionPolicy(string shellId, ExecutionPolicyScope scope) { - if (!Platform.HasExecutionPolicy()) - { - throw new PlatformNotSupportedException(); - } - +#if LINUX + return ExecutionPolicy.Unrestricted; +#else switch (scope) { case ExecutionPolicyScope.Process: @@ -368,6 +365,7 @@ namespace System.Management.Automation } return ExecutionPolicy.Restricted; +#endif } internal static ExecutionPolicy ParseExecutionPolicy(string policy) diff --git a/test/powershell/Modules/Microsoft.PowerShell.Security/ExecutionPolicy.Tests.ps1 b/test/powershell/Modules/Microsoft.PowerShell.Security/ExecutionPolicy.Tests.ps1 index b5631218d..cdc5a239c 100644 --- a/test/powershell/Modules/Microsoft.PowerShell.Security/ExecutionPolicy.Tests.ps1 +++ b/test/powershell/Modules/Microsoft.PowerShell.Security/ExecutionPolicy.Tests.ps1 @@ -1,24 +1,24 @@ Describe "ExecutionPolicy" { Context "Check Get-ExecutionPolicy behavior" { - It "Should throw PlatformNotSupported when not on Windows" -Skip:$IsWindows { - { Get-ExecutionPolicy } | Should Throw "Operation is not supported on this platform." - } + It "Should unrestricted when not on Windows" -Skip:$IsWindows { + Get-ExecutionPolicy | Should Be Unrestricted + } - It "Should return Microsoft.Powershell.ExecutionPolicy PSObject on Windows" -Skip:($IsLinux -Or $IsOSX) { - (Get-ExecutionPolicy).GetType() | Should Be Microsoft.Powershell.ExecutionPolicy - } + It "Should return Microsoft.Powershell.ExecutionPolicy PSObject on Windows" -Skip:($IsLinux -Or $IsOSX) { + (Get-ExecutionPolicy).GetType() | Should Be Microsoft.Powershell.ExecutionPolicy + } } Context "Check Set-ExecutionPolicy behavior" { - It "Should throw PlatformNotSupported when not on Windows" -Skip:$IsWindows { - { Set-ExecutionPolicy Unrestricted } | Should Throw "Operation is not supported on this platform." - } + It "Should throw PlatformNotSupported when not on Windows" -Skip:$IsWindows { + { Set-ExecutionPolicy Unrestricted } | Should Throw "Operation is not supported on this platform." + } - It "Should succeed on Windows" -Skip:($IsLinux -Or $IsOSX) { - # We use the Process scope to avoid affecting the system - # Unrestricted is assumed "safe", otherwise these tests would not be running - { Set-ExecutionPolicy -Force -Scope Process -ExecutionPolicy Unrestricted } | Should Not Throw - } + It "Should succeed on Windows" -Skip:($IsLinux -Or $IsOSX) { + # We use the Process scope to avoid affecting the system + # Unrestricted is assumed "safe", otherwise these tests would not be running + { Set-ExecutionPolicy -Force -Scope Process -ExecutionPolicy Unrestricted } | Should Not Throw + } } } From 527f30a0139ac2b7ca73bb401786102d1ba9c4f4 Mon Sep 17 00:00:00 2001 From: Andrew Schwartzmeyer Date: Thu, 14 Jul 2016 14:36:41 -0700 Subject: [PATCH 16/30] Remove Platform.HasSingleRootFilesystem query --- .../CoreCLR/CorePsPlatform.cs | 8 +------- .../namespaces/FileSystemProvider.cs | 4 +++- .../namespaces/LocationGlobber.cs | 9 ++++++--- 3 files changed, 10 insertions(+), 11 deletions(-) diff --git a/src/System.Management.Automation/CoreCLR/CorePsPlatform.cs b/src/System.Management.Automation/CoreCLR/CorePsPlatform.cs index 6edfbaa90..c4edc350c 100644 --- a/src/System.Management.Automation/CoreCLR/CorePsPlatform.cs +++ b/src/System.Management.Automation/CoreCLR/CorePsPlatform.cs @@ -217,18 +217,12 @@ namespace System.Management.Automation } - // Linux has a single rooted file system - internal static bool HasSingleRootFilesystem() - { - return !IsWindows; - } - // Linux has no notion of file shares. It has mount points // instead, which are subdirectories of its single-root // filesystem. internal static bool HasFileShares() { - return !HasSingleRootFilesystem(); + return IsWindows(); } // Linux has no support for UNC, just mounts in a single rooted hierarchy diff --git a/src/System.Management.Automation/namespaces/FileSystemProvider.cs b/src/System.Management.Automation/namespaces/FileSystemProvider.cs index 50a84e98b..6af52e291 100644 --- a/src/System.Management.Automation/namespaces/FileSystemProvider.cs +++ b/src/System.Management.Automation/namespaces/FileSystemProvider.cs @@ -947,12 +947,14 @@ namespace Microsoft.PowerShell.Commands root = newDrive.RootDirectory.FullName; } +#if LINUX // Porting notes: On platforms with single root filesystems, only // add the filesystem with the root "/" to the initial drive list, // otherwise path handling will not work correctly because there // is no : available to separate the filesystems from each other - if (Platform.HasSingleRootFilesystem() && root != StringLiterals.DefaultPathSeparatorString) + if (root != StringLiterals.DefaultPathSeparatorString) continue; +#endif // Porting notes: On non-windows platforms .net can report two // drives with the same root, make sure to only add one of those diff --git a/src/System.Management.Automation/namespaces/LocationGlobber.cs b/src/System.Management.Automation/namespaces/LocationGlobber.cs index 313e9e0e6..c150dd717 100644 --- a/src/System.Management.Automation/namespaces/LocationGlobber.cs +++ b/src/System.Management.Automation/namespaces/LocationGlobber.cs @@ -1589,9 +1589,12 @@ namespace System.Management.Automation /// internal static bool IsSingleFileSystemAbsolutePath(string path) { - return Platform.HasSingleRootFilesystem() && - (path.StartsWith(StringLiterals.DefaultPathSeparatorString, StringComparison.Ordinal) || - path.StartsWith(StringLiterals.AlternatePathSeparatorString, StringComparison.Ordinal)); +#if LINUX + return path.StartsWith(StringLiterals.DefaultPathSeparatorString, StringComparison.Ordinal) + || path.StartsWith(StringLiterals.AlternatePathSeparatorString, StringComparison.Ordinal); +#else + return false; +#endif } // IsSingleFileSystemAbsolutePath /// From 58fe228dc0c4d418a9e2fddfdfa2a33d6e613856 Mon Sep 17 00:00:00 2001 From: Andrew Schwartzmeyer Date: Thu, 14 Jul 2016 14:38:19 -0700 Subject: [PATCH 17/30] Remove Platform.HasFileShares query --- .../CoreCLR/CorePsPlatform.cs | 8 -------- .../engine/CommandCompletion/CompletionCompleters.cs | 10 ++++------ 2 files changed, 4 insertions(+), 14 deletions(-) diff --git a/src/System.Management.Automation/CoreCLR/CorePsPlatform.cs b/src/System.Management.Automation/CoreCLR/CorePsPlatform.cs index c4edc350c..4a9bda08c 100644 --- a/src/System.Management.Automation/CoreCLR/CorePsPlatform.cs +++ b/src/System.Management.Automation/CoreCLR/CorePsPlatform.cs @@ -217,14 +217,6 @@ namespace System.Management.Automation } - // Linux has no notion of file shares. It has mount points - // instead, which are subdirectories of its single-root - // filesystem. - internal static bool HasFileShares() - { - return IsWindows(); - } - // Linux has no support for UNC, just mounts in a single rooted hierarchy // the UNC equivalent of a "network drive" aka mount would be the mount itself internal static bool HasUNCSupport() diff --git a/src/System.Management.Automation/engine/CommandCompletion/CompletionCompleters.cs b/src/System.Management.Automation/engine/CommandCompletion/CompletionCompleters.cs index 8c3eb882b..d3fba6c14 100644 --- a/src/System.Management.Automation/engine/CommandCompletion/CompletionCompleters.cs +++ b/src/System.Management.Automation/engine/CommandCompletion/CompletionCompleters.cs @@ -4464,12 +4464,9 @@ namespace System.Management.Automation internal static List GetFileShares(string machine, bool ignoreHidden) { - // Platform notes: don't throw an exception since this is being used in auto-completion - if (!Platform.HasFileShares()) - { - return new List(); - } - +#if LINUX + return new List(); +#else IntPtr shBuf; uint numEntries; uint totalEntries; @@ -4495,6 +4492,7 @@ namespace System.Management.Automation } } return shares; +#endif } private static bool CheckFileExtension(string path, HashSet extension) From 2249afcd0ab8f06e0cff9e031a9b97eea2ca9818 Mon Sep 17 00:00:00 2001 From: Andrew Schwartzmeyer Date: Thu, 14 Jul 2016 14:51:59 -0700 Subject: [PATCH 18/30] Remove Platform.HasUNCSupport query --- .../CoreCLR/CorePsPlatform.cs | 7 ------- src/System.Management.Automation/engine/Utils.cs | 8 ++++---- .../namespaces/FileSystemProvider.cs | 14 +++++--------- 3 files changed, 9 insertions(+), 20 deletions(-) diff --git a/src/System.Management.Automation/CoreCLR/CorePsPlatform.cs b/src/System.Management.Automation/CoreCLR/CorePsPlatform.cs index 4a9bda08c..7082e29c1 100644 --- a/src/System.Management.Automation/CoreCLR/CorePsPlatform.cs +++ b/src/System.Management.Automation/CoreCLR/CorePsPlatform.cs @@ -217,13 +217,6 @@ namespace System.Management.Automation } - // Linux has no support for UNC, just mounts in a single rooted hierarchy - // the UNC equivalent of a "network drive" aka mount would be the mount itself - internal static bool HasUNCSupport() - { - return IsWindows; - } - // Linux uses .net to query file attributes internal static bool UseDotNetToQueryFileAttributes() { diff --git a/src/System.Management.Automation/engine/Utils.cs b/src/System.Management.Automation/engine/Utils.cs index 878908be5..7c5cdbe3a 100644 --- a/src/System.Management.Automation/engine/Utils.cs +++ b/src/System.Management.Automation/engine/Utils.cs @@ -1129,12 +1129,12 @@ namespace System.Management.Automation internal static bool PathIsUnc(string path) { - if (!Platform.HasUNCSupport()) - { - return false; - } +#if LINUX + return false; +#else Uri uri; return !string.IsNullOrEmpty(path) && Uri.TryCreate(path, UriKind.Absolute, out uri) && uri.IsUnc; +#endif } internal class NativeMethods diff --git a/src/System.Management.Automation/namespaces/FileSystemProvider.cs b/src/System.Management.Automation/namespaces/FileSystemProvider.cs index 6af52e291..60664ee73 100644 --- a/src/System.Management.Automation/namespaces/FileSystemProvider.cs +++ b/src/System.Management.Automation/namespaces/FileSystemProvider.cs @@ -685,15 +685,11 @@ namespace Microsoft.PowerShell.Commands /// internal static string GetUNCForNetworkDrive(string driveName) { - // Porting note: on systems that do not support UNC paths, the UNC equivalent is the path itself - if (Platform.HasUNCSupport()) - { - return WinGetUNCForNetworkDrive(driveName); - } - else - { - return driveName; - } +#if LINUX + return driveName; +#else + return WinGetUNCForNetworkDrive(driveName); +#endif } private static string WinGetUNCForNetworkDrive(string driveName) From ab882cb04d2cbfb4798521828b2c703b9b3cbe24 Mon Sep 17 00:00:00 2001 From: Andrew Schwartzmeyer Date: Thu, 14 Jul 2016 14:54:51 -0700 Subject: [PATCH 19/30] Remove Platform.UseDotNetToQueryFileAttributes query --- .../CoreCLR/CorePsPlatform.cs | 6 -- .../namespaces/FileSystemProvider.cs | 79 +++++++++---------- 2 files changed, 39 insertions(+), 46 deletions(-) diff --git a/src/System.Management.Automation/CoreCLR/CorePsPlatform.cs b/src/System.Management.Automation/CoreCLR/CorePsPlatform.cs index 7082e29c1..1e7e979e5 100644 --- a/src/System.Management.Automation/CoreCLR/CorePsPlatform.cs +++ b/src/System.Management.Automation/CoreCLR/CorePsPlatform.cs @@ -217,12 +217,6 @@ namespace System.Management.Automation } - // Linux uses .net to query file attributes - internal static bool UseDotNetToQueryFileAttributes() - { - return true; - } - // Linux does not have group policy support internal static bool HasGroupPolicySupport() { diff --git a/src/System.Management.Automation/namespaces/FileSystemProvider.cs b/src/System.Management.Automation/namespaces/FileSystemProvider.cs index 60664ee73..893337255 100644 --- a/src/System.Management.Automation/namespaces/FileSystemProvider.cs +++ b/src/System.Management.Automation/namespaces/FileSystemProvider.cs @@ -6969,48 +6969,47 @@ namespace Microsoft.PowerShell.Commands internal static int SafeGetFileAttributes(string path) { - if (Platform.UseDotNetToQueryFileAttributes()) - { - System.IO.FileAttributes attr = System.IO.File.GetAttributes(path); +#if LINUX + System.IO.FileAttributes attr = System.IO.File.GetAttributes(path); - int result = 0; - if ((attr & FileAttributes.Archive) == FileAttributes.Archive) - result |= 0x20; - if ((attr & FileAttributes.Compressed) == FileAttributes.Compressed) - result |= 0x800; - if ((attr & FileAttributes.Device) == FileAttributes.Device) - result |= 0x40; - if ((attr & FileAttributes.Directory) == FileAttributes.Directory) - result |= 0x10; - if ((attr & FileAttributes.Encrypted) == FileAttributes.Encrypted) - result |= 0x4000; - if ((attr & FileAttributes.Hidden) == FileAttributes.Hidden) - result |= 0x2; - if ((attr & FileAttributes.IntegrityStream) == FileAttributes.IntegrityStream) - result |= 0x8000; - if ((attr & FileAttributes.Normal) == FileAttributes.Normal) - result |= 0x80; - if ((attr & FileAttributes.NoScrubData) == FileAttributes.NoScrubData) - result |= 0x20000; - if ((attr & FileAttributes.NotContentIndexed) == FileAttributes.NotContentIndexed) - result |= 0x2000; - if ((attr & FileAttributes.Offline) == FileAttributes.Offline) - result |= 0x1000; - if ((attr & FileAttributes.ReadOnly) == FileAttributes.ReadOnly) - result |= 0x1; - if ((attr & FileAttributes.ReparsePoint) == FileAttributes.ReparsePoint) - result |= 0x400; - if ((attr & FileAttributes.SparseFile) == FileAttributes.SparseFile) - result |= 0x200; - if ((attr & FileAttributes.System) == FileAttributes.System) - result |= 0x4; - if ((attr & FileAttributes.Temporary) == FileAttributes.Temporary) - result |= 0x100; + int result = 0; + if ((attr & FileAttributes.Archive) == FileAttributes.Archive) + result |= 0x20; + if ((attr & FileAttributes.Compressed) == FileAttributes.Compressed) + result |= 0x800; + if ((attr & FileAttributes.Device) == FileAttributes.Device) + result |= 0x40; + if ((attr & FileAttributes.Directory) == FileAttributes.Directory) + result |= 0x10; + if ((attr & FileAttributes.Encrypted) == FileAttributes.Encrypted) + result |= 0x4000; + if ((attr & FileAttributes.Hidden) == FileAttributes.Hidden) + result |= 0x2; + if ((attr & FileAttributes.IntegrityStream) == FileAttributes.IntegrityStream) + result |= 0x8000; + if ((attr & FileAttributes.Normal) == FileAttributes.Normal) + result |= 0x80; + if ((attr & FileAttributes.NoScrubData) == FileAttributes.NoScrubData) + result |= 0x20000; + if ((attr & FileAttributes.NotContentIndexed) == FileAttributes.NotContentIndexed) + result |= 0x2000; + if ((attr & FileAttributes.Offline) == FileAttributes.Offline) + result |= 0x1000; + if ((attr & FileAttributes.ReadOnly) == FileAttributes.ReadOnly) + result |= 0x1; + if ((attr & FileAttributes.ReparsePoint) == FileAttributes.ReparsePoint) + result |= 0x400; + if ((attr & FileAttributes.SparseFile) == FileAttributes.SparseFile) + result |= 0x200; + if ((attr & FileAttributes.System) == FileAttributes.System) + result |= 0x4; + if ((attr & FileAttributes.Temporary) == FileAttributes.Temporary) + result |= 0x100; - return result; - } - else - return WinSafeGetFileAttributes(path); + return result; +#else + return WinSafeGetFileAttributes(path); +#endif } internal static int WinSafeGetFileAttributes(string path) From 662e3909027db661d3a0413f8a76d04dbb635126 Mon Sep 17 00:00:00 2001 From: Andrew Schwartzmeyer Date: Thu, 14 Jul 2016 14:57:46 -0700 Subject: [PATCH 20/30] Remove Platform.HasGroupPolicySupport query --- .../CoreCLR/CorePsPlatform.cs | 6 ------ src/System.Management.Automation/engine/Utils.cs | 11 ++++------- 2 files changed, 4 insertions(+), 13 deletions(-) diff --git a/src/System.Management.Automation/CoreCLR/CorePsPlatform.cs b/src/System.Management.Automation/CoreCLR/CorePsPlatform.cs index 1e7e979e5..2cac3ebd5 100644 --- a/src/System.Management.Automation/CoreCLR/CorePsPlatform.cs +++ b/src/System.Management.Automation/CoreCLR/CorePsPlatform.cs @@ -217,12 +217,6 @@ namespace System.Management.Automation } - // Linux does not have group policy support - internal static bool HasGroupPolicySupport() - { - return IsWindows; - } - // non-windows does not have network drive support internal static bool HasNetworkDriveSupport() { diff --git a/src/System.Management.Automation/engine/Utils.cs b/src/System.Management.Automation/engine/Utils.cs index 7c5cdbe3a..87c2962ea 100644 --- a/src/System.Management.Automation/engine/Utils.cs +++ b/src/System.Management.Automation/engine/Utils.cs @@ -649,13 +649,9 @@ namespace System.Management.Automation internal static Dictionary GetGroupPolicySetting(string groupPolicyBase, string settingName, RegistryKey[] preferenceOrder) { - if (!Platform.HasGroupPolicySupport()) - { - // Porting note: No group policy support means we have an empty set of - // policies. - return _emptyDictionary; - } - +#if LINUX + return _emptyDictionary; +#else lock (cachedGroupPolicySettings) { // Return cached information, if we have it @@ -730,6 +726,7 @@ namespace System.Management.Automation return settings; } +#endif } static ConcurrentDictionary> cachedGroupPolicySettings = new ConcurrentDictionary>(); From 465e55d32a903f704954d3d74aae12f9771403d1 Mon Sep 17 00:00:00 2001 From: Andrew Schwartzmeyer Date: Thu, 14 Jul 2016 15:41:17 -0700 Subject: [PATCH 21/30] Remove Platform.HasNetworkDriveSupport query --- .../CoreCLR/CorePsPlatform.cs | 6 ---- .../namespaces/FileSystemProvider.cs | 33 +++++++++---------- 2 files changed, 15 insertions(+), 24 deletions(-) diff --git a/src/System.Management.Automation/CoreCLR/CorePsPlatform.cs b/src/System.Management.Automation/CoreCLR/CorePsPlatform.cs index 2cac3ebd5..7f72c54fb 100644 --- a/src/System.Management.Automation/CoreCLR/CorePsPlatform.cs +++ b/src/System.Management.Automation/CoreCLR/CorePsPlatform.cs @@ -217,12 +217,6 @@ namespace System.Management.Automation } - // non-windows does not have network drive support - internal static bool HasNetworkDriveSupport() - { - return IsWindows; - } - // non-windows does not have reparse points internal static bool SupportsReparsePoints() { diff --git a/src/System.Management.Automation/namespaces/FileSystemProvider.cs b/src/System.Management.Automation/namespaces/FileSystemProvider.cs index 893337255..c9d7236b2 100644 --- a/src/System.Management.Automation/namespaces/FileSystemProvider.cs +++ b/src/System.Management.Automation/namespaces/FileSystemProvider.cs @@ -743,14 +743,11 @@ namespace Microsoft.PowerShell.Commands /// internal static string GetSubstitutedPathForNetworkDosDevice(string driveName) { - if (Platform.HasNetworkDriveSupport()) - { - return WinGetSubstitutedPathForNetworkDosDevice(driveName); - } - else - { - throw new PlatformNotSupportedException(); - } +#if LINUX + throw new PlatformNotSupportedException(); +#else + return WinGetSubstitutedPathForNetworkDosDevice(driveName); +#endif } private static string WinGetSubstitutedPathForNetworkDosDevice(string driveName) @@ -922,15 +919,15 @@ namespace Microsoft.PowerShell.Commands if (newDrive.DriveType == DriveType.Network) { // Platform notes: This is important because certain mount - // points on non-Windows are enumerated as drives by .net, but + // points on non-Windows are enumerated as drives by .NET, but // the platform itself then has no real network drive support // as required by this context. Solution: check for network // drive support before using it. - if (!Platform.HasNetworkDriveSupport()) - { - continue; - } +#if LINUX + continue; +#else displayRoot = GetRootPathForNetworkDriveOrDosDevice(newDrive); +#endif } if (newDrive.DriveType == DriveType.Fixed) @@ -7071,11 +7068,11 @@ namespace Microsoft.PowerShell.Commands /// internal static bool PathIsNetworkPath(string path) { - // no other logic possible for now on linux - if (Platform.HasNetworkDriveSupport()) - return WinPathIsNetworkPath(path); - else - return false; +#if LINUX + return false; +#else + return WinPathIsNetworkPath(path); +#endif } internal static bool WinPathIsNetworkPath(string path) From dbe16ca5d72a59431bfa0dd7043ed08abc0dbe0e Mon Sep 17 00:00:00 2001 From: Andrew Schwartzmeyer Date: Thu, 14 Jul 2016 15:44:47 -0700 Subject: [PATCH 22/30] Remove Platform.SupportsReparsePoints query --- .../CoreCLR/CorePsPlatform.cs | 6 ------ .../namespaces/FileSystemProvider.cs | 13 +++++-------- 2 files changed, 5 insertions(+), 14 deletions(-) diff --git a/src/System.Management.Automation/CoreCLR/CorePsPlatform.cs b/src/System.Management.Automation/CoreCLR/CorePsPlatform.cs index 7f72c54fb..5f780cef1 100644 --- a/src/System.Management.Automation/CoreCLR/CorePsPlatform.cs +++ b/src/System.Management.Automation/CoreCLR/CorePsPlatform.cs @@ -217,12 +217,6 @@ namespace System.Management.Automation } - // non-windows does not have reparse points - internal static bool SupportsReparsePoints() - { - return IsWindows; - } - // non-windows does not support removing drives internal static bool SupportsRemoveDrive() { diff --git a/src/System.Management.Automation/namespaces/FileSystemProvider.cs b/src/System.Management.Automation/namespaces/FileSystemProvider.cs index c9d7236b2..4b4c024c7 100644 --- a/src/System.Management.Automation/namespaces/FileSystemProvider.cs +++ b/src/System.Management.Automation/namespaces/FileSystemProvider.cs @@ -8589,14 +8589,11 @@ namespace Microsoft.PowerShell.Commands private static SafeFileHandle OpenReparsePoint(string reparsePoint, FileDesiredAccess accessMode) { - if (Platform.SupportsReparsePoints()) - { - return WinOpenReparsePoint(reparsePoint,accessMode); - } - else - { - throw new PlatformNotSupportedException(); - } +#if LINUX + throw new PlatformNotSupportedException(); +#else + return WinOpenReparsePoint(reparsePoint,accessMode); +#endif } private static SafeFileHandle WinOpenReparsePoint(string reparsePoint, FileDesiredAccess accessMode) From a9484e45e91a4bc575ff21928847171fc72c6eae Mon Sep 17 00:00:00 2001 From: Andrew Schwartzmeyer Date: Thu, 14 Jul 2016 15:46:59 -0700 Subject: [PATCH 23/30] Remove Platform.SupportsRemoveDrive query --- .../CoreCLR/CorePsPlatform.cs | 6 ------ .../namespaces/FileSystemProvider.cs | 14 +++++--------- 2 files changed, 5 insertions(+), 15 deletions(-) diff --git a/src/System.Management.Automation/CoreCLR/CorePsPlatform.cs b/src/System.Management.Automation/CoreCLR/CorePsPlatform.cs index 5f780cef1..8f10fa2bd 100644 --- a/src/System.Management.Automation/CoreCLR/CorePsPlatform.cs +++ b/src/System.Management.Automation/CoreCLR/CorePsPlatform.cs @@ -217,12 +217,6 @@ namespace System.Management.Automation } - // non-windows does not support removing drives - internal static bool SupportsRemoveDrive() - { - return IsWindows; - } - // Platform methods prefixed NonWindows are: // - non-windows by the definition of the IsWindows method above // - here, because porting to Linux and other operating systems diff --git a/src/System.Management.Automation/namespaces/FileSystemProvider.cs b/src/System.Management.Automation/namespaces/FileSystemProvider.cs index 4b4c024c7..d5e370e6c 100644 --- a/src/System.Management.Automation/namespaces/FileSystemProvider.cs +++ b/src/System.Management.Automation/namespaces/FileSystemProvider.cs @@ -607,15 +607,11 @@ namespace Microsoft.PowerShell.Commands /// protected override PSDriveInfo RemoveDrive(PSDriveInfo drive) { - // if removing the drive is not supported, just return the drive - if (Platform.SupportsRemoveDrive()) - { - return WinRemoveDrive(drive); - } - else - { - return drive; - } +#if LINUX + return drive; +#else + return WinRemoveDrive(drive); +#endif } private PSDriveInfo WinRemoveDrive(PSDriveInfo drive) From 89508ae99daa3811f588864d4f7c4432fc139194 Mon Sep 17 00:00:00 2001 From: Andrew Schwartzmeyer Date: Thu, 14 Jul 2016 15:58:37 -0700 Subject: [PATCH 24/30] Revert IsWinPEHost changes --- .../engine/Utils.cs | 66 +++++-------------- 1 file changed, 16 insertions(+), 50 deletions(-) diff --git a/src/System.Management.Automation/engine/Utils.cs b/src/System.Management.Automation/engine/Utils.cs index 87c2962ea..51d990c9a 100644 --- a/src/System.Management.Automation/engine/Utils.cs +++ b/src/System.Management.Automation/engine/Utils.cs @@ -62,15 +62,6 @@ namespace System.Management.Automation return CombineHashCodes(CombineHashCodes(h1, h2, h3, h4), CombineHashCodes(h5, h6, h7, h8)); } - /// - /// IsWinPEHost indicates if the machine on which PowerShell is hosted is WinPE or not. - /// This is a helper variable used to kep track if the IsWinPE() helper method has - /// already checked for the WinPE specific registry key or not. - /// If the WinPE specific registry key has not yet been checked even - /// once then this variable will point to null. - /// - internal static bool? isWinPEHost = null; - /// /// The existence of the following registry confirms that the host machine is a WinPE /// HKLM\System\CurrentControlSet\Control\MiniNT @@ -368,55 +359,30 @@ namespace System.Management.Automation /// internal static bool IsWinPEHost() { -#if LINUX - return false; -#else - return WinIsWinPEHost(); -#endif - } - - internal static bool WinIsWinPEHost() - { RegistryKey winPEKey = null; - if (!isWinPEHost.HasValue) + try { - try - { - // The existence of the following registry confirms that the host machine is a WinPE - // HKLM\System\CurrentControlSet\Control\MiniNT - winPEKey = Registry.LocalMachine.OpenSubKey(WinPEIdentificationRegKey); + // The existence of the following registry confirms that the host machine is a WinPE + // HKLM\System\CurrentControlSet\Control\MiniNT + winPEKey = Registry.LocalMachine.OpenSubKey(WinPEIdentificationRegKey); - if (null != winPEKey) - { - isWinPEHost = true; - } - else - { - isWinPEHost = false; - } - } - catch (ArgumentException) { } - catch (SecurityException) { } - catch (ObjectDisposedException) { } - finally + return winPEKey != null; + } + catch (ArgumentException) { } + catch (SecurityException) { } + catch (ObjectDisposedException) { } + finally + { + if (winPEKey != null) { - if (winPEKey != null) - { - winPEKey.Dispose(); - } + winPEKey.Dispose(); } } - if (isWinPEHost.HasValue) - { - return (bool)isWinPEHost; - } - else - { - return false; - } - } + return false; + } + #region Versioning related methods From ad94ddb3f1808ce7d79c3c6c6e1ddfcf3814f20c Mon Sep 17 00:00:00 2001 From: Andrew Schwartzmeyer Date: Thu, 14 Jul 2016 15:59:54 -0700 Subject: [PATCH 25/30] Guard IsWinPEHost --- src/System.Management.Automation/engine/Utils.cs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/System.Management.Automation/engine/Utils.cs b/src/System.Management.Automation/engine/Utils.cs index 51d990c9a..d5b29ad01 100644 --- a/src/System.Management.Automation/engine/Utils.cs +++ b/src/System.Management.Automation/engine/Utils.cs @@ -359,6 +359,7 @@ namespace System.Management.Automation /// internal static bool IsWinPEHost() { +#if !LINUX RegistryKey winPEKey = null; try @@ -379,7 +380,7 @@ namespace System.Management.Automation winPEKey.Dispose(); } } - +#endif return false; } From 32e0a7dcaa5f8c764cf4a06c37c6adc35d21de66 Mon Sep 17 00:00:00 2001 From: Andrew Schwartzmeyer Date: Thu, 14 Jul 2016 16:12:09 -0700 Subject: [PATCH 26/30] Format New-Item.Tests.ps1 --- .../New-Item.Tests.ps1 | 80 +++++++++---------- 1 file changed, 40 insertions(+), 40 deletions(-) diff --git a/test/powershell/Modules/Microsoft.PowerShell.Management/New-Item.Tests.ps1 b/test/powershell/Modules/Microsoft.PowerShell.Management/New-Item.Tests.ps1 index 593f892ad..155f2226f 100644 --- a/test/powershell/Modules/Microsoft.PowerShell.Management/New-Item.Tests.ps1 +++ b/test/powershell/Modules/Microsoft.PowerShell.Management/New-Item.Tests.ps1 @@ -2,17 +2,17 @@ function Clean-State { if (Test-Path $FullyQualifiedLink) { - Remove-Item $FullyQualifiedLink -Force + Remove-Item $FullyQualifiedLink -Force } if (Test-Path $FullyQualifiedFile) { - Remove-Item $FullyQualifiedFile -Force + Remove-Item $FullyQualifiedFile -Force } if (Test-Path $FullyQualifiedFolder) { - Remove-Item $FullyQualifiedFolder -Force + Remove-Item $FullyQualifiedFolder -Force } } @@ -26,17 +26,17 @@ Describe "New-Item" { $FullyQualifiedLink = Join-Path -Path $tmpDirectory -ChildPath $testlink BeforeEach { - Clean-State + Clean-State } It "should call the function without error" { - { New-Item -Name $testfile -Path $tmpDirectory -ItemType file } | Should Not Throw + { New-Item -Name $testfile -Path $tmpDirectory -ItemType file } | Should Not Throw } It "Should create a file without error" { - New-Item -Name $testfile -Path $tmpDirectory -ItemType file + New-Item -Name $testfile -Path $tmpDirectory -ItemType file - Test-Path $FullyQualifiedFile | Should Be $true + Test-Path $FullyQualifiedFile | Should Be $true $fileInfo = Get-ChildItem $FullyQualifiedFile $fileInfo.Target | Should Be $null @@ -44,72 +44,72 @@ Describe "New-Item" { } It "Should create a folder without an error" { - New-Item -Name newDirectory -Path $tmpDirectory -ItemType directory + New-Item -Name newDirectory -Path $tmpDirectory -ItemType directory - Test-Path $FullyQualifiedFolder | Should Be $true + Test-Path $FullyQualifiedFolder | Should Be $true } It "Should create a file using the ni alias" { - ni -Name $testfile -Path $tmpDirectory -ItemType file + ni -Name $testfile -Path $tmpDirectory -ItemType file - Test-Path $FullyQualifiedFile | Should Be $true + Test-Path $FullyQualifiedFile | Should Be $true } It "Should create a file using the Type alias instead of ItemType" { - New-Item -Name $testfile -Path $tmpDirectory -Type file + New-Item -Name $testfile -Path $tmpDirectory -Type file - Test-Path $FullyQualifiedFile | Should Be $true + Test-Path $FullyQualifiedFile | Should Be $true } It "Should create a file with sample text inside the file using the Value switch" { - $expected = "This is test string" - New-Item -Name $testfile -Path $tmpDirectory -ItemType file -Value $expected + $expected = "This is test string" + New-Item -Name $testfile -Path $tmpDirectory -ItemType file -Value $expected - Test-Path $FullyQualifiedFile | Should Be $true + Test-Path $FullyQualifiedFile | Should Be $true - Get-Content $FullyQualifiedFile | Should Be $expected + Get-Content $FullyQualifiedFile | Should Be $expected } It "Should not create a file when the Name switch is not used and only a directory specified" { - #errorAction used because permissions issue in Windows - New-Item -Path $tmpDirectory -ItemType file -ErrorAction SilentlyContinue + #errorAction used because permissions issue in Windows + New-Item -Path $tmpDirectory -ItemType file -ErrorAction SilentlyContinue - Test-Path $FullyQualifiedFile | Should Be $false + Test-Path $FullyQualifiedFile | Should Be $false } It "Should create a file when the Name switch is not used but a fully qualified path is specified" { - New-Item -Path $FullyQualifiedFile -ItemType file + New-Item -Path $FullyQualifiedFile -ItemType file - Test-Path $FullyQualifiedFile | Should Be $true + Test-Path $FullyQualifiedFile | Should Be $true } It "Should be able to create a multiple items in different directories" { - $FullyQualifiedFile2 = Join-Path -Path $tmpDirectory -ChildPath test2.txt - New-Item -ItemType file -Path $FullyQualifiedFile, $FullyQualifiedFile2 + $FullyQualifiedFile2 = Join-Path -Path $tmpDirectory -ChildPath test2.txt + New-Item -ItemType file -Path $FullyQualifiedFile, $FullyQualifiedFile2 - Test-Path $FullyQualifiedFile | Should Be $true - Test-Path $FullyQualifiedFile2 | Should Be $true + Test-Path $FullyQualifiedFile | Should Be $true + Test-Path $FullyQualifiedFile2 | Should Be $true - Remove-Item $FullyQualifiedFile2 + Remove-Item $FullyQualifiedFile2 } It "Should be able to call the whatif switch without error" { - { New-Item -Name testfile.txt -Path $tmpDirectory -ItemType file -WhatIf } | Should Not Throw + { New-Item -Name testfile.txt -Path $tmpDirectory -ItemType file -WhatIf } | Should Not Throw } It "Should not create a new file when the whatif switch is used" { - New-Item -Name $testfile -Path $tmpDirectory -ItemType file -WhatIf + New-Item -Name $testfile -Path $tmpDirectory -ItemType file -WhatIf - Test-Path $FullyQualifiedFile | Should Be $false + Test-Path $FullyQualifiedFile | Should Be $false } It "Should create a symbolic link of a file without error" { - New-Item -Name $testfile -Path $tmpDirectory -ItemType file - Test-Path $FullyQualifiedFile | Should Be $true + New-Item -Name $testfile -Path $tmpDirectory -ItemType file + Test-Path $FullyQualifiedFile | Should Be $true - New-Item -ItemType SymbolicLink -Target $FullyQualifiedFile -Name $testlink -Path $tmpDirectory - Test-Path $FullyQualifiedLink | Should Be $true + New-Item -ItemType SymbolicLink -Target $FullyQualifiedFile -Name $testlink -Path $tmpDirectory + Test-Path $FullyQualifiedLink | Should Be $true $fileInfo = Get-ChildItem $FullyQualifiedLink $fileInfo.Target | Should Match ([regex]::Escape($FullyQualifiedFile)) @@ -128,18 +128,18 @@ Describe "New-Item" { } It "Should create a symbolic link from directory without error" { - New-Item -Name $testFolder -Path $tmpDirectory -ItemType directory - Test-Path $FullyQualifiedFolder | Should Be $true + New-Item -Name $testFolder -Path $tmpDirectory -ItemType directory + Test-Path $FullyQualifiedFolder | Should Be $true - New-Item -ItemType SymbolicLink -Target $FullyQualifiedFolder -Name $testlink -Path $tmpDirectory - Test-Path $FullyQualifiedLink | Should Be $true + New-Item -ItemType SymbolicLink -Target $FullyQualifiedFolder -Name $testlink -Path $tmpDirectory + Test-Path $FullyQualifiedLink | Should Be $true $fileInfo = Get-ChildItem $FullyQualifiedLink $fileInfo.Target | Should Match ([regex]::Escape($FullyQualifiedFolder)) $fileInfo.LinkType | Should Be "SymbolicLink" - # Remove the link explicitly to avoid broken symlink issue - Remove-Item $FullyQualifiedLink -Force + # Remove the link explicitly to avoid broken symlink issue + Remove-Item $FullyQualifiedLink -Force } It "Should create a hard link of a file without error" { From 35e24ce6d44b63ad6582d6ade8363f614348aa99 Mon Sep 17 00:00:00 2001 From: Andrew Schwartzmeyer Date: Thu, 14 Jul 2016 17:13:45 -0700 Subject: [PATCH 27/30] Clean up CreateSymLink() --- .../CoreCLR/CorePsPlatform.cs | 13 ++----- .../namespaces/FileSystemProvider.cs | 2 +- src/libpsl-native/src/createsymlink.cpp | 18 ++++----- src/libpsl-native/src/createsymlink.h | 3 +- src/libpsl-native/test/test-createsymlink.cpp | 38 +++++++++---------- 5 files changed, 35 insertions(+), 39 deletions(-) diff --git a/src/System.Management.Automation/CoreCLR/CorePsPlatform.cs b/src/System.Management.Automation/CoreCLR/CorePsPlatform.cs index 8f10fa2bd..80d434265 100644 --- a/src/System.Management.Automation/CoreCLR/CorePsPlatform.cs +++ b/src/System.Management.Automation/CoreCLR/CorePsPlatform.cs @@ -280,10 +280,10 @@ namespace System.Management.Automation return null; } - internal static bool NonWindowsCreateSymbolicLink(string path, string strTargetPath, bool isDirectory) + internal static bool NonWindowsCreateSymbolicLink(string path, string target) { // Linux doesn't care if target is a directory or not - return Unix.CreateSymbolicLink(path, strTargetPath); + return Unix.NativeMethods.CreateSymLink(path, target); } internal static bool NonWindowsCreateHardLink(string path, string strTargetPath) @@ -536,12 +536,6 @@ namespace System.Management.Automation } } - public static bool CreateSymbolicLink(string path, string strTargetPath) - { - int ret = NativeMethods.CreateSymLink(path, strTargetPath); - return ret == 1 ? true : false; - } - public static bool CreateHardLink(string path, string strTargetPath) { int ret = NativeMethods.CreateHardLink(path, strTargetPath); @@ -620,7 +614,8 @@ namespace System.Management.Automation internal static extern int SetDate(SetDateInfoInternal info); [DllImport(psLib, CharSet = CharSet.Ansi, SetLastError = true)] - internal static extern int CreateSymLink([MarshalAs(UnmanagedType.LPStr)]string filePath, + [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)] diff --git a/src/System.Management.Automation/namespaces/FileSystemProvider.cs b/src/System.Management.Automation/namespaces/FileSystemProvider.cs index d5e370e6c..225caeffc 100644 --- a/src/System.Management.Automation/namespaces/FileSystemProvider.cs +++ b/src/System.Management.Automation/namespaces/FileSystemProvider.cs @@ -2220,7 +2220,7 @@ namespace Microsoft.PowerShell.Commands } else { - success = Platform.NonWindowsCreateSymbolicLink(path,strTargetPath,isDirectory); + success = Platform.NonWindowsCreateSymbolicLink(path,strTargetPath); } } else if(itemType == ItemType.HardLink) diff --git a/src/libpsl-native/src/createsymlink.cpp b/src/libpsl-native/src/createsymlink.cpp index 4ea8d6fd9..b9ce2b18d 100644 --- a/src/libpsl-native/src/createsymlink.cpp +++ b/src/libpsl-native/src/createsymlink.cpp @@ -39,26 +39,25 @@ //! - ERROR_INVALID_FUNCTION: incorrect function //! - ERROR_BAD_PATH_NAME: pathname is too long, or contains invalid characters //! -//! @retval 1 if creation is successful -//! @retval 0 if createion failed +//! @retval boolean successful //! -int32_t CreateSymLink(const char *link, const char *target) +bool CreateSymLink(const char *link, const char *target) { - errno = 0; + errno = 0; // Check parameters if (!link || !target) { errno = ERROR_INVALID_PARAMETER; - return 0; + return false; } - int returnCode = symlink(target, link); + int ret = symlink(target, link); - if (returnCode == 0) + if (ret == 0) { - return 1; + return true; } switch(errno) @@ -102,5 +101,6 @@ int32_t CreateSymLink(const char *link, const char *target) default: errno = ERROR_INVALID_FUNCTION; } - return 0; + + return false; } diff --git a/src/libpsl-native/src/createsymlink.h b/src/libpsl-native/src/createsymlink.h index e47bce3fa..45da92890 100644 --- a/src/libpsl-native/src/createsymlink.h +++ b/src/libpsl-native/src/createsymlink.h @@ -1,9 +1,10 @@ #pragma once #include "pal.h" +#include PAL_BEGIN_EXTERNC -int32_t CreateSymLink(const char *link, const char *target); +bool CreateSymLink(const char *link, const char *target); PAL_END_EXTERNC diff --git a/src/libpsl-native/test/test-createsymlink.cpp b/src/libpsl-native/test/test-createsymlink.cpp index 7bb9997b3..1aab3379a 100644 --- a/src/libpsl-native/test/test-createsymlink.cpp +++ b/src/libpsl-native/test/test-createsymlink.cpp @@ -39,36 +39,36 @@ protected: EXPECT_TRUE(dir != NULL); // Create symbolic link to file - int ret1 = CreateSymLink(fileSymLink.c_str(), file); - EXPECT_EQ(ret1, 1); + bool ret1 = CreateSymLink(fileSymLink.c_str(), file); + EXPECT_TRUE(ret1); // Create symbolic link to directory - int ret2 = CreateSymLink(dirSymLink.c_str(), dir); - EXPECT_EQ(ret2, 1); + bool ret2 = CreateSymLink(dirSymLink.c_str(), dir); + EXPECT_TRUE(ret2); } ~CreateSymLinkTest() { - int ret; + bool ret; ret = unlink(fileSymLink.c_str()); - EXPECT_EQ(0, ret); + EXPECT_FALSE(ret); ret = unlink(dirSymLink.c_str()); - EXPECT_EQ(0, ret); + EXPECT_FALSE(ret); ret = unlink(file); - EXPECT_EQ(0, ret); + EXPECT_FALSE(ret); ret = rmdir(dir); - EXPECT_EQ(0, ret); + EXPECT_FALSE(ret); } }; TEST_F(CreateSymLinkTest, FilePathNameIsNull) { - int retVal = CreateSymLink(NULL, NULL); - EXPECT_EQ(retVal, 0); + bool retVal = CreateSymLink(NULL, NULL); + EXPECT_FALSE(retVal); EXPECT_EQ(ERROR_INVALID_PARAMETER, errno); } @@ -82,8 +82,8 @@ TEST_F(CreateSymLinkTest, FilePathNameDoesNotExist) unlink(invalidLink.c_str()); // Linux allows creation of symbolic link that points to an invalid file - int retVal = CreateSymLink(invalidLink.c_str(), invalidFile.c_str()); - EXPECT_EQ(retVal, 1); + bool retVal = CreateSymLink(invalidLink.c_str(), invalidFile.c_str()); + EXPECT_TRUE(retVal); std::string target = FollowSymLink(invalidLink.c_str()); EXPECT_EQ(target, invalidFile); @@ -93,8 +93,8 @@ TEST_F(CreateSymLinkTest, FilePathNameDoesNotExist) TEST_F(CreateSymLinkTest, SymLinkToFile) { - int retVal = IsSymLink(fileSymLink.c_str()); - EXPECT_EQ(1, retVal); + bool retVal = IsSymLink(fileSymLink.c_str()); + EXPECT_TRUE(retVal); std::string target = FollowSymLink(fileSymLink.c_str()); char buffer[PATH_MAX]; @@ -104,8 +104,8 @@ TEST_F(CreateSymLinkTest, SymLinkToFile) TEST_F(CreateSymLinkTest, SymLinkToDirectory) { - int retVal = IsSymLink(dirSymLink.c_str()); - EXPECT_EQ(1, retVal); + bool retVal = IsSymLink(dirSymLink.c_str()); + EXPECT_TRUE(retVal); std::string target = FollowSymLink(dirSymLink.c_str()); char buffer[PATH_MAX]; @@ -115,7 +115,7 @@ TEST_F(CreateSymLinkTest, SymLinkToDirectory) TEST_F(CreateSymLinkTest, SymLinkAgain) { - int retVal = CreateSymLink(fileSymLink.c_str(), file); - EXPECT_EQ(0, retVal); + bool retVal = CreateSymLink(fileSymLink.c_str(), file); + EXPECT_FALSE(retVal); EXPECT_EQ(ERROR_FILE_EXISTS, errno); } From 74c3262f03c4ea1c842402d265f93a83df5e3864 Mon Sep 17 00:00:00 2001 From: Andrew Schwartzmeyer Date: Thu, 14 Jul 2016 17:24:00 -0700 Subject: [PATCH 28/30] Fix failing New-Item tests PowerShell expects the behavior of NativeItemExists to not follow symbolic links. --- src/libpsl-native/src/isfile.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/libpsl-native/src/isfile.cpp b/src/libpsl-native/src/isfile.cpp index b2cead6cd..89c415f47 100644 --- a/src/libpsl-native/src/isfile.cpp +++ b/src/libpsl-native/src/isfile.cpp @@ -7,6 +7,7 @@ #include #include #include +#include #include #include "isfile.h" @@ -36,5 +37,6 @@ bool IsFile(const char* path) return false; } - return access(path, F_OK) != -1; + // Resolve relative paths to cwd of process, and do not follow symlinks + return faccessat(AT_FDCWD, path, F_OK, AT_SYMLINK_NOFOLLOW) != -1; } From 70aa6af9604ca5c8ac2e4c8ffe8b96d4d47de20d Mon Sep 17 00:00:00 2001 From: Andrew Schwartzmeyer Date: Thu, 14 Jul 2016 17:30:54 -0700 Subject: [PATCH 29/30] Remove unnecessary indirection from Platform.Unix --- .../CoreCLR/CorePsPlatform.cs | 28 +++---------------- 1 file changed, 4 insertions(+), 24 deletions(-) diff --git a/src/System.Management.Automation/CoreCLR/CorePsPlatform.cs b/src/System.Management.Automation/CoreCLR/CorePsPlatform.cs index 80d434265..e4a8701b6 100644 --- a/src/System.Management.Automation/CoreCLR/CorePsPlatform.cs +++ b/src/System.Management.Automation/CoreCLR/CorePsPlatform.cs @@ -239,7 +239,7 @@ namespace System.Management.Automation internal static bool NonWindowsIsSymLink(FileSystemInfo fileInfo) { - return Unix.IsSymLink(fileInfo); + return Unix.NativeMethods.IsSymLink(fileInfo.FullName); } internal static string NonWindowsInternalGetTarget(SafeFileHandle handle) @@ -250,12 +250,12 @@ namespace System.Management.Automation internal static string NonWindowsInternalGetTarget(string path) { - return Unix.FollowSymLink(path); + return Unix.NativeMethods.FollowSymLink(path); } internal static string NonWindowsGetUserFromPid(int path) { - return Unix.GetUserFromPid(path); + return Unix.NativeMethods.GetUserFromPid(path); } #if CORECLR @@ -344,7 +344,7 @@ namespace System.Management.Automation internal static bool NonWindowsIsExecutable(string path) { - return Unix.IsExecutable(path); + return Unix.NativeMethods.IsExecutable(path); } internal static uint NonWindowsGetThreadId() @@ -516,16 +516,6 @@ namespace System.Management.Automation } - public static bool IsSymLink(FileSystemInfo fs) - { - return NativeMethods.IsSymLink(fs.FullName); - } - - public static bool IsExecutable(string filePath) - { - return NativeMethods.IsExecutable(filePath); - } - public static void SetDate(SetDateInfoInternal info) { int ret = NativeMethods.SetDate(info); @@ -542,16 +532,6 @@ namespace System.Management.Automation return ret == 1 ? true : false; } - public static string FollowSymLink(string path) - { - return NativeMethods.FollowSymLink(path); - } - - public static string GetUserFromPid(int pid) - { - return NativeMethods.GetUserFromPid(pid); - } - [StructLayout(LayoutKind.Sequential)] internal class SetDateInfoInternal { From ed39a00f2913183db009d4a5e420443decda090c Mon Sep 17 00:00:00 2001 From: Andrew Schwartzmeyer Date: Thu, 14 Jul 2016 19:38:43 -0700 Subject: [PATCH 30/30] Add GetLStat faccessat() does not support AT_SYMLINK_NOFOLLOW on OS X, so instead, we use the success of lstat() to determine if the file (not following symbolic links) exists. Also allowed for some refactoring. --- src/libpsl-native/src/CMakeLists.txt | 1 + src/libpsl-native/src/getlstat.cpp | 95 +++++++++++++++++++++++++++ src/libpsl-native/src/getlstat.h | 10 +++ src/libpsl-native/src/getstat.cpp | 3 +- src/libpsl-native/src/isdirectory.cpp | 3 +- src/libpsl-native/src/isfile.cpp | 5 +- src/libpsl-native/src/issymlink.cpp | 41 ++---------- 7 files changed, 115 insertions(+), 43 deletions(-) create mode 100644 src/libpsl-native/src/getlstat.cpp create mode 100644 src/libpsl-native/src/getlstat.h diff --git a/src/libpsl-native/src/CMakeLists.txt b/src/libpsl-native/src/CMakeLists.txt index 22e8f5dd8..5d4c432b4 100644 --- a/src/libpsl-native/src/CMakeLists.txt +++ b/src/libpsl-native/src/CMakeLists.txt @@ -1,5 +1,6 @@ add_library(psl-native SHARED getstat.cpp + getlstat.cpp getpwuid.cpp getuserfrompid.cpp getfileowner.cpp diff --git a/src/libpsl-native/src/getlstat.cpp b/src/libpsl-native/src/getlstat.cpp new file mode 100644 index 000000000..d2fcb6969 --- /dev/null +++ b/src/libpsl-native/src/getlstat.cpp @@ -0,0 +1,95 @@ +//! @file getlstat.cpp +//! @author Andrew Schwartzmeyer +//! @brief returns the lstat of a file + +#include +#include +#include +#include +#include +#include +#include "getlstat.h" + +//! @brief GetLStat returns the lstat of a file. This simply delegates to the +//! lstat() system call and maps errno to the expected values for GetLastError. +//! +//! GetLstat +//! +//! @param[in] path +//! @parblock +//! A pointer to the buffer that contains the file name +//! +//! char* is marshaled as an LPStr, which on Linux is UTF-8. +//! @endparblock +//! +//! @param[in] lstat +//! @parblock +//! A pointer to the buffer in which to place the lstat information +//! @endparblock +//! +//! @exception errno Passes these errors via errno to GetLastError: +//! - ERROR_INVALID_PARAMETER: parameter is not valid +//! - ERROR_FILE_NOT_FOUND: file does not exist +//! - ERROR_ACCESS_DENIED: access is denied +//! - ERROR_INVALID_ADDRESS: attempt to access invalid address +//! - ERROR_STOPPED_ON_SYMLINK: too many symbolic links +//! - ERROR_GEN_FAILURE: I/O error occurred +//! - ERROR_INVALID_NAME: file provided is not a symbolic link +//! - ERROR_INVALID_FUNCTION: incorrect function +//! - ERROR_BAD_PATH_NAME: pathname is too long +//! - ERROR_OUTOFMEMORY insufficient kernel memory +//! +//! @retval 0 if successful +//! @retval -1 if failed +//! + +int32_t GetLStat(const char* path, struct stat* buf) +{ + errno = 0; + + if (!path) + { + errno = ERROR_INVALID_PARAMETER; + return -1; + } + + int32_t ret = lstat(path, buf); + + if (ret != 0) + { + switch(errno) + { + case EACCES: + errno = ERROR_ACCESS_DENIED; + break; + case EBADF: + errno = ERROR_FILE_NOT_FOUND; + break; + case EFAULT: + errno = ERROR_INVALID_ADDRESS; + break; + case ELOOP: + errno = ERROR_STOPPED_ON_SYMLINK; + break; + case ENAMETOOLONG: + errno = ERROR_GEN_FAILURE; + break; + case ENOENT: + errno = ERROR_FILE_NOT_FOUND; + break; + case ENOMEM: + errno = ERROR_NO_SUCH_USER; + break; + case ENOTDIR: + errno = ERROR_INVALID_NAME; + break; + case EOVERFLOW: + errno = ERROR_BUFFER_OVERFLOW; + break; + default: + errno = ERROR_INVALID_FUNCTION; + } + } + + return ret; +} diff --git a/src/libpsl-native/src/getlstat.h b/src/libpsl-native/src/getlstat.h new file mode 100644 index 000000000..ba746dd35 --- /dev/null +++ b/src/libpsl-native/src/getlstat.h @@ -0,0 +1,10 @@ +#pragma once + +#include +#include "pal.h" + +PAL_BEGIN_EXTERNC + +int32_t GetLStat(const char* path, struct stat* buf); + +PAL_END_EXTERNC diff --git a/src/libpsl-native/src/getstat.cpp b/src/libpsl-native/src/getstat.cpp index 3e89d1a6e..8fd666221 100644 --- a/src/libpsl-native/src/getstat.cpp +++ b/src/libpsl-native/src/getstat.cpp @@ -89,8 +89,7 @@ int32_t GetStat(const char* path, struct stat* buf) default: errno = ERROR_INVALID_FUNCTION; } - return -1; } - return 0; + return ret; } diff --git a/src/libpsl-native/src/isdirectory.cpp b/src/libpsl-native/src/isdirectory.cpp index 01ca0d9bb..f8b6bfe74 100644 --- a/src/libpsl-native/src/isdirectory.cpp +++ b/src/libpsl-native/src/isdirectory.cpp @@ -31,7 +31,6 @@ //! bool IsDirectory(const char* path) { - int32_t ret = 0; errno = 0; if (!path) @@ -41,7 +40,7 @@ bool IsDirectory(const char* path) } struct stat buf; - ret = GetStat(path, &buf); + int32_t ret = GetStat(path, &buf); if (ret != 0) { return false; diff --git a/src/libpsl-native/src/isfile.cpp b/src/libpsl-native/src/isfile.cpp index 89c415f47..1f6d0c59e 100644 --- a/src/libpsl-native/src/isfile.cpp +++ b/src/libpsl-native/src/isfile.cpp @@ -9,6 +9,7 @@ #include #include #include +#include "getlstat.h" #include "isfile.h" //! @brief returns if the path is a file or directory @@ -37,6 +38,6 @@ bool IsFile(const char* path) return false; } - // Resolve relative paths to cwd of process, and do not follow symlinks - return faccessat(AT_FDCWD, path, F_OK, AT_SYMLINK_NOFOLLOW) != -1; + struct stat buf; + return GetLStat(path, &buf) == 0; } diff --git a/src/libpsl-native/src/issymlink.cpp b/src/libpsl-native/src/issymlink.cpp index dfd37d8bc..87a8a2e8d 100644 --- a/src/libpsl-native/src/issymlink.cpp +++ b/src/libpsl-native/src/issymlink.cpp @@ -7,6 +7,7 @@ #include #include #include +#include "getlstat.h" #include "issymlink.h" //! @brief IsSymlink determines if path is a symbolic link @@ -48,46 +49,12 @@ bool IsSymLink(const char* path) return false; } - struct stat statBuf; - - int ret = lstat(path, &statBuf); - + struct stat buf; + int32_t ret = GetLStat(path, &buf); if (ret != 0) { - switch(errno) - { - case EACCES: - errno = ERROR_ACCESS_DENIED; - break; - case EBADF: - errno = ERROR_FILE_NOT_FOUND; - break; - case EFAULT: - errno = ERROR_INVALID_ADDRESS; - break; - case ELOOP: - errno = ERROR_STOPPED_ON_SYMLINK; - break; - case ENAMETOOLONG: - errno = ERROR_GEN_FAILURE; - break; - case ENOENT: - errno = ERROR_FILE_NOT_FOUND; - break; - case ENOMEM: - errno = ERROR_NO_SUCH_USER; - break; - case ENOTDIR: - errno = ERROR_INVALID_NAME; - break; - case EOVERFLOW: - errno = ERROR_BUFFER_OVERFLOW; - break; - default: - errno = ERROR_INVALID_FUNCTION; - } return false; } - return S_ISLNK(statBuf.st_mode); + return S_ISLNK(buf.st_mode); }