From b0cd7ba3dcf94021ff37129ef344fc32ad42024e Mon Sep 17 00:00:00 2001 From: Andrew Schwartzmeyer Date: Wed, 28 Sep 2016 18:17:03 -0700 Subject: [PATCH 01/20] Clean up libpsl-native headers --- src/libpsl-native/src/createhardlink.cpp | 3 ++- src/libpsl-native/src/createsymlink.cpp | 3 ++- src/libpsl-native/src/createsymlink.h | 1 + src/libpsl-native/src/followsymlink.cpp | 5 +++-- src/libpsl-native/src/getcomputername.cpp | 3 ++- src/libpsl-native/src/getcurrentprocessorid.cpp | 7 +++---- src/libpsl-native/src/getcurrentprocessorid.h | 3 ++- src/libpsl-native/src/getcurrentthreadid.cpp | 6 +++--- src/libpsl-native/src/getcurrentthreadid.h | 4 +++- src/libpsl-native/src/getfileowner.cpp | 7 ++++--- src/libpsl-native/src/getfullyqualifiedname.cpp | 5 +++-- src/libpsl-native/src/getlinkcount.cpp | 3 ++- src/libpsl-native/src/getlstat.cpp | 3 ++- src/libpsl-native/src/getlstat.h | 3 ++- src/libpsl-native/src/getpwuid.cpp | 3 ++- src/libpsl-native/src/getpwuid.h | 3 ++- src/libpsl-native/src/getstat.cpp | 3 ++- src/libpsl-native/src/getstat.h | 3 ++- src/libpsl-native/src/getuserfrompid.cpp | 9 +++++---- src/libpsl-native/src/getuserfrompid.h | 2 ++ src/libpsl-native/src/getusername.cpp | 3 ++- src/libpsl-native/src/isdirectory.cpp | 9 +++++---- src/libpsl-native/src/isdirectory.h | 1 + src/libpsl-native/src/isexecutable.cpp | 3 ++- src/libpsl-native/src/isexecutable.h | 1 + src/libpsl-native/src/isfile.cpp | 5 +++-- src/libpsl-native/src/isfile.h | 1 + src/libpsl-native/src/issymlink.cpp | 5 +++-- src/libpsl-native/src/issymlink.h | 1 + src/libpsl-native/src/setdate.cpp | 3 ++- 30 files changed, 70 insertions(+), 41 deletions(-) diff --git a/src/libpsl-native/src/createhardlink.cpp b/src/libpsl-native/src/createhardlink.cpp index 29727c2cf6..8cbc1d6663 100644 --- a/src/libpsl-native/src/createhardlink.cpp +++ b/src/libpsl-native/src/createhardlink.cpp @@ -2,10 +2,11 @@ //! @author George FLeming //! @brief create new hard link +#include "createhardlink.h" + #include #include #include -#include "createhardlink.h" //! @brief Createhardlink create new symbolic link //! diff --git a/src/libpsl-native/src/createsymlink.cpp b/src/libpsl-native/src/createsymlink.cpp index b9ce2b18d1..6cd712781c 100644 --- a/src/libpsl-native/src/createsymlink.cpp +++ b/src/libpsl-native/src/createsymlink.cpp @@ -2,10 +2,11 @@ //! @author George FLeming //! @brief create new symbolic link +#include "createsymlink.h" + #include #include #include -#include "createsymlink.h" //! @brief Createsymlink create new symbolic link //! diff --git a/src/libpsl-native/src/createsymlink.h b/src/libpsl-native/src/createsymlink.h index 45da928902..e2f4bd3d18 100644 --- a/src/libpsl-native/src/createsymlink.h +++ b/src/libpsl-native/src/createsymlink.h @@ -1,6 +1,7 @@ #pragma once #include "pal.h" + #include PAL_BEGIN_EXTERNC diff --git a/src/libpsl-native/src/followsymlink.cpp b/src/libpsl-native/src/followsymlink.cpp index 47d0883958..78b6831beb 100644 --- a/src/libpsl-native/src/followsymlink.cpp +++ b/src/libpsl-native/src/followsymlink.cpp @@ -2,12 +2,13 @@ //! @author George FLeming //! @brief returns whether a path is a symbolic link +#include "followsymlink.h" +#include "issymlink.h" + #include #include #include #include -#include "followsymlink.h" -#include "issymlink.h" //! @brief Followsymlink determines target path of a sym link //! diff --git a/src/libpsl-native/src/getcomputername.cpp b/src/libpsl-native/src/getcomputername.cpp index 3e480b9ad4..1c257e1fa7 100644 --- a/src/libpsl-native/src/getcomputername.cpp +++ b/src/libpsl-native/src/getcomputername.cpp @@ -2,10 +2,11 @@ //! @author George Fleming //! @brief Implements GetComputerName Win32 API +#include "getcomputername.h" + #include #include #include -#include "getcomputername.h" //! @brief GetComputerName retrieves the name of the host associated with //! the current thread. diff --git a/src/libpsl-native/src/getcurrentprocessorid.cpp b/src/libpsl-native/src/getcurrentprocessorid.cpp index eea80937b9..6ef7ddb685 100644 --- a/src/libpsl-native/src/getcurrentprocessorid.cpp +++ b/src/libpsl-native/src/getcurrentprocessorid.cpp @@ -1,9 +1,8 @@ #include "getcurrentprocessorid.h" + #include -int32_t GetCurrentProcessId() +pid_t GetCurrentProcessId() { - pid_t pid = getpid(); - return static_cast(pid); + return getpid(); } - diff --git a/src/libpsl-native/src/getcurrentprocessorid.h b/src/libpsl-native/src/getcurrentprocessorid.h index 3c768e72e5..ece2f5c358 100644 --- a/src/libpsl-native/src/getcurrentprocessorid.h +++ b/src/libpsl-native/src/getcurrentprocessorid.h @@ -1,10 +1,11 @@ #pragma once #include "pal.h" +#include PAL_BEGIN_EXTERNC -int32_t GetCurrentProcessId(); +pid_t GetCurrentProcessId(); PAL_END_EXTERNC diff --git a/src/libpsl-native/src/getcurrentthreadid.cpp b/src/libpsl-native/src/getcurrentthreadid.cpp index efd7a31361..7422d57af2 100644 --- a/src/libpsl-native/src/getcurrentthreadid.cpp +++ b/src/libpsl-native/src/getcurrentthreadid.cpp @@ -1,9 +1,9 @@ #include "getcurrentthreadid.h" + #include #include -HANDLE GetCurrentThreadId() +pid_t GetCurrentThreadId() { - pid_t tid = pthread_self(); - return reinterpret_cast(tid); + return pthread_self(); } diff --git a/src/libpsl-native/src/getcurrentthreadid.h b/src/libpsl-native/src/getcurrentthreadid.h index 258c3c397f..cc388ec411 100644 --- a/src/libpsl-native/src/getcurrentthreadid.h +++ b/src/libpsl-native/src/getcurrentthreadid.h @@ -2,9 +2,11 @@ #include "pal.h" +#include + PAL_BEGIN_EXTERNC -HANDLE GetCurrentThreadId(); +pid_t GetCurrentThreadId(); PAL_END_EXTERNC diff --git a/src/libpsl-native/src/getfileowner.cpp b/src/libpsl-native/src/getfileowner.cpp index c1bd5b69f6..de3deaee79 100644 --- a/src/libpsl-native/src/getfileowner.cpp +++ b/src/libpsl-native/src/getfileowner.cpp @@ -2,15 +2,16 @@ //! @author Andrew Schwartzmeyer //! @brief returns the owner of a file +#include "getstat.h" +#include "getpwuid.h" +#include "getfileowner.h" + #include #include #include #include #include #include -#include "getstat.h" -#include "getpwuid.h" -#include "getfileowner.h" //! @brief GetFileOwner returns the owner of a file //! diff --git a/src/libpsl-native/src/getfullyqualifiedname.cpp b/src/libpsl-native/src/getfullyqualifiedname.cpp index e88ab988e7..75e5af4b36 100644 --- a/src/libpsl-native/src/getfullyqualifiedname.cpp +++ b/src/libpsl-native/src/getfullyqualifiedname.cpp @@ -2,12 +2,13 @@ //! @author George Fleming //! @brief Implements GetFullyQualifiedName on Linux +#include "getcomputername.h" +#include "getfullyqualifiedname.h" + #include #include #include #include -#include "getcomputername.h" -#include "getfullyqualifiedname.h" //! @brief GetFullyQualifiedName retrieves the fully qualified dns name of the host //! diff --git a/src/libpsl-native/src/getlinkcount.cpp b/src/libpsl-native/src/getlinkcount.cpp index 2230d7a388..552b46ce50 100644 --- a/src/libpsl-native/src/getlinkcount.cpp +++ b/src/libpsl-native/src/getlinkcount.cpp @@ -2,13 +2,14 @@ //! @author George FLeming //! @brief Retrieve link count of a file +#include "getlinkcount.h" + #include #include #include #include #include #include -#include "getlinkcount.h" //! @brief GetLinkCount retrieves the file link count (number of hard links) //! for the given file diff --git a/src/libpsl-native/src/getlstat.cpp b/src/libpsl-native/src/getlstat.cpp index d2fcb69697..b8ba8a00c2 100644 --- a/src/libpsl-native/src/getlstat.cpp +++ b/src/libpsl-native/src/getlstat.cpp @@ -2,13 +2,14 @@ //! @author Andrew Schwartzmeyer //! @brief returns the lstat of a file +#include "getlstat.h" + #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. diff --git a/src/libpsl-native/src/getlstat.h b/src/libpsl-native/src/getlstat.h index ba746dd35a..6cb4d47198 100644 --- a/src/libpsl-native/src/getlstat.h +++ b/src/libpsl-native/src/getlstat.h @@ -1,8 +1,9 @@ #pragma once -#include #include "pal.h" +#include + PAL_BEGIN_EXTERNC int32_t GetLStat(const char* path, struct stat* buf); diff --git a/src/libpsl-native/src/getpwuid.cpp b/src/libpsl-native/src/getpwuid.cpp index 62263067e2..d28a28de27 100644 --- a/src/libpsl-native/src/getpwuid.cpp +++ b/src/libpsl-native/src/getpwuid.cpp @@ -2,13 +2,14 @@ //! @author Andrew Schwartzmeyer //! @brief returns the username for a uid +#include "getpwuid.h" + #include #include #include #include #include #include -#include "getpwuid.h" //! @brief GetPwUid returns the username for a uid //! diff --git a/src/libpsl-native/src/getpwuid.h b/src/libpsl-native/src/getpwuid.h index cbf2cca911..d573a8292b 100644 --- a/src/libpsl-native/src/getpwuid.h +++ b/src/libpsl-native/src/getpwuid.h @@ -1,8 +1,9 @@ #pragma once -#include #include "pal.h" +#include + PAL_BEGIN_EXTERNC char* GetPwUid(uid_t uid); diff --git a/src/libpsl-native/src/getstat.cpp b/src/libpsl-native/src/getstat.cpp index 8fd6662219..05e9ea479e 100644 --- a/src/libpsl-native/src/getstat.cpp +++ b/src/libpsl-native/src/getstat.cpp @@ -2,13 +2,14 @@ //! @author Andrew Schwartzmeyer //! @brief returns the stat of a file +#include "getstat.h" + #include #include #include #include #include #include -#include "getstat.h" //! @brief GetStat returns the stat of a file. This simply delegates to the //! stat() system call and maps errno to the expected values for GetLastError. diff --git a/src/libpsl-native/src/getstat.h b/src/libpsl-native/src/getstat.h index 00bc26e9fa..7f680470d9 100644 --- a/src/libpsl-native/src/getstat.h +++ b/src/libpsl-native/src/getstat.h @@ -1,8 +1,9 @@ #pragma once -#include #include "pal.h" +#include + PAL_BEGIN_EXTERNC int32_t GetStat(const char* path, struct stat* buf); diff --git a/src/libpsl-native/src/getuserfrompid.cpp b/src/libpsl-native/src/getuserfrompid.cpp index fd148a9ff2..2211becf87 100644 --- a/src/libpsl-native/src/getuserfrompid.cpp +++ b/src/libpsl-native/src/getuserfrompid.cpp @@ -1,12 +1,13 @@ -#include -#include -#include -#include #include "pal.h" #include "getfileowner.h" #include "getpwuid.h" #include "getuserfrompid.h" +#include +#include +#include +#include + char* GetUserFromPid(pid_t pid) { diff --git a/src/libpsl-native/src/getuserfrompid.h b/src/libpsl-native/src/getuserfrompid.h index c019f475fc..65ce612daa 100644 --- a/src/libpsl-native/src/getuserfrompid.h +++ b/src/libpsl-native/src/getuserfrompid.h @@ -2,6 +2,8 @@ #include "pal.h" +#include + PAL_BEGIN_EXTERNC char* GetUserFromPid(pid_t pid); diff --git a/src/libpsl-native/src/getusername.cpp b/src/libpsl-native/src/getusername.cpp index 56c3d6d080..e2bbe95bd4 100644 --- a/src/libpsl-native/src/getusername.cpp +++ b/src/libpsl-native/src/getusername.cpp @@ -2,10 +2,11 @@ //! @author Andrew Schwartzmeyer //! @brief Implements GetUserName for Linux -#include #include "getpwuid.h" #include "getusername.h" +#include + //! @brief GetUserName retrieves the name of the user associated with //! the current thread. //! diff --git a/src/libpsl-native/src/isdirectory.cpp b/src/libpsl-native/src/isdirectory.cpp index f8b6bfe742..5e61311626 100644 --- a/src/libpsl-native/src/isdirectory.cpp +++ b/src/libpsl-native/src/isdirectory.cpp @@ -2,16 +2,17 @@ //! @author Andrew Schwartzmeyer //! @brief returns if the path is a directory +#include "getstat.h" +#include "getpwuid.h" +#include "getfileowner.h" +#include "isdirectory.h" + #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 //! diff --git a/src/libpsl-native/src/isdirectory.h b/src/libpsl-native/src/isdirectory.h index 746d1c5793..fdf52b22b1 100644 --- a/src/libpsl-native/src/isdirectory.h +++ b/src/libpsl-native/src/isdirectory.h @@ -1,6 +1,7 @@ #pragma once #include "pal.h" + #include PAL_BEGIN_EXTERNC diff --git a/src/libpsl-native/src/isexecutable.cpp b/src/libpsl-native/src/isexecutable.cpp index a06fab57ab..c702ccf3ba 100644 --- a/src/libpsl-native/src/isexecutable.cpp +++ b/src/libpsl-native/src/isexecutable.cpp @@ -2,10 +2,11 @@ //! @author George Fleming //! @brief returns whether a file is executable +#include "isexecutable.h" + #include #include #include -#include "isexecutable.h" //! @brief IsExecutable determines if path is executable //! diff --git a/src/libpsl-native/src/isexecutable.h b/src/libpsl-native/src/isexecutable.h index f4278b954e..f5fcb5b742 100644 --- a/src/libpsl-native/src/isexecutable.h +++ b/src/libpsl-native/src/isexecutable.h @@ -1,6 +1,7 @@ #pragma once #include "pal.h" + #include PAL_BEGIN_EXTERNC diff --git a/src/libpsl-native/src/isfile.cpp b/src/libpsl-native/src/isfile.cpp index 1f6d0c59e5..e348b105ee 100644 --- a/src/libpsl-native/src/isfile.cpp +++ b/src/libpsl-native/src/isfile.cpp @@ -2,6 +2,9 @@ //! @author Andrew Schwartzmeyer //! @brief returns if the path exists +#include "getlstat.h" +#include "isfile.h" + #include #include #include @@ -9,8 +12,6 @@ #include #include #include -#include "getlstat.h" -#include "isfile.h" //! @brief returns if the path is a file or directory //! diff --git a/src/libpsl-native/src/isfile.h b/src/libpsl-native/src/isfile.h index 53a15f97d3..1aa6677c2f 100644 --- a/src/libpsl-native/src/isfile.h +++ b/src/libpsl-native/src/isfile.h @@ -1,6 +1,7 @@ #pragma once #include "pal.h" + #include PAL_BEGIN_EXTERNC diff --git a/src/libpsl-native/src/issymlink.cpp b/src/libpsl-native/src/issymlink.cpp index 87a8a2e8db..00a73f1ef2 100644 --- a/src/libpsl-native/src/issymlink.cpp +++ b/src/libpsl-native/src/issymlink.cpp @@ -2,13 +2,14 @@ //! @author George FLeming //! @brief returns whether a path is a symbolic link +#include "getlstat.h" +#include "issymlink.h" + #include #include #include #include #include -#include "getlstat.h" -#include "issymlink.h" //! @brief IsSymlink determines if path is a symbolic link //! diff --git a/src/libpsl-native/src/issymlink.h b/src/libpsl-native/src/issymlink.h index ebe3733c5a..1106484580 100644 --- a/src/libpsl-native/src/issymlink.h +++ b/src/libpsl-native/src/issymlink.h @@ -1,6 +1,7 @@ #pragma once #include "pal.h" + #include PAL_BEGIN_EXTERNC diff --git a/src/libpsl-native/src/setdate.cpp b/src/libpsl-native/src/setdate.cpp index 81bfa3417e..3a2c179d7e 100644 --- a/src/libpsl-native/src/setdate.cpp +++ b/src/libpsl-native/src/setdate.cpp @@ -2,13 +2,14 @@ //! @author George FLeming //! @brief set local/system date and time +#include "setdate.h" + #include #include #include #include #include #include -#include "setdate.h" //! @brief SetDate sets the date and time on local computer. You must //! be super-user to set the time. From 6c3e536ca869e95483773a7e9aa815b00af45eaf Mon Sep 17 00:00:00 2001 From: Andrew Schwartzmeyer Date: Fri, 30 Sep 2016 11:41:51 -0700 Subject: [PATCH 02/20] Add configure to CMake to detect GNU strerror_r * Add getstrerror to libpsl-native * Add Unix.GetLastPerror to CorePsPlatform --- .../CoreCLR/CorePsPlatform.cs | 9 +++++ src/libpsl-native/.gitignore | 1 + src/libpsl-native/src/CMakeLists.txt | 16 ++++++++ src/libpsl-native/src/config.h.in | 1 + src/libpsl-native/src/getstrerror.cpp | 40 +++++++++++++++++++ src/libpsl-native/src/getstrerror.h | 9 +++++ src/libpsl-native/src/pal.h | 2 + 7 files changed, 78 insertions(+) create mode 100644 src/libpsl-native/src/config.h.in create mode 100644 src/libpsl-native/src/getstrerror.cpp create mode 100644 src/libpsl-native/src/getstrerror.h diff --git a/src/System.Management.Automation/CoreCLR/CorePsPlatform.cs b/src/System.Management.Automation/CoreCLR/CorePsPlatform.cs index 29a4f189f5..2a6f6c99c7 100644 --- a/src/System.Management.Automation/CoreCLR/CorePsPlatform.cs +++ b/src/System.Management.Automation/CoreCLR/CorePsPlatform.cs @@ -453,6 +453,11 @@ namespace System.Management.Automation internal static class Unix { + internal static string GetLastPerror() + { + return Unix.NativeMethods.GetStrError(Marshal.GetLastWin32Error()); + } + private static string s_userName; public static string UserName { @@ -568,6 +573,10 @@ namespace System.Management.Automation // C bools are 1 byte and so must be marshaled as I1 + [DllImport(psLib, CharSet = CharSet.Ansi)] + [return: MarshalAs(UnmanagedType.LPStr)] + internal static extern string GetStrError(int errno); + [DllImport(psLib, CharSet = CharSet.Ansi, SetLastError = true)] [return: MarshalAs(UnmanagedType.LPStr)] internal static extern string GetUserName(); diff --git a/src/libpsl-native/.gitignore b/src/libpsl-native/.gitignore index 0dff693725..61884d84d1 100644 --- a/src/libpsl-native/.gitignore +++ b/src/libpsl-native/.gitignore @@ -9,4 +9,5 @@ Testing/ test/psl-native-test src/libpsl-native.so src/libpsl-native.dylib +src/config.h test/native-tests.xml diff --git a/src/libpsl-native/src/CMakeLists.txt b/src/libpsl-native/src/CMakeLists.txt index 5d4c432b40..0f7490d863 100644 --- a/src/libpsl-native/src/CMakeLists.txt +++ b/src/libpsl-native/src/CMakeLists.txt @@ -1,3 +1,18 @@ +include(CheckCXXSourceCompiles) +check_cxx_source_compiles( + " + #include + int main() + { + char buffer[1]; + char* c = strerror_r(0, buffer, 0); + (void)c; + } + " + HAVE_GNU_STRERROR_R) + +configure_file(${CMAKE_CURRENT_SOURCE_DIR}/config.h.in ${CMAKE_CURRENT_BINARY_DIR}/config.h) + add_library(psl-native SHARED getstat.cpp getlstat.cpp @@ -9,6 +24,7 @@ add_library(psl-native SHARED getcomputername.cpp getlinkcount.cpp getfullyqualifiedname.cpp + getstrerror.cpp isfile.cpp isdirectory.cpp issymlink.cpp diff --git a/src/libpsl-native/src/config.h.in b/src/libpsl-native/src/config.h.in new file mode 100644 index 0000000000..2b4d20c329 --- /dev/null +++ b/src/libpsl-native/src/config.h.in @@ -0,0 +1 @@ +#cmakedefine HAVE_GNU_STRERROR_R 1 diff --git a/src/libpsl-native/src/getstrerror.cpp b/src/libpsl-native/src/getstrerror.cpp new file mode 100644 index 0000000000..6d86cd8569 --- /dev/null +++ b/src/libpsl-native/src/getstrerror.cpp @@ -0,0 +1,40 @@ +#include "getstrerror.h" + +#include +#include +#include +#include +#include + +char* GetStrError(int errnum) +{ + size_t buflen = 256; + char* buf = (char*)calloc(buflen, sizeof(char)); + +// Note that we must use strerror_r because plain strerror is not +// thread-safe. +// +// However, there are two versions of strerror_r: +// - GNU: char* strerror_r(int, char*, size_t); +// - POSIX: int strerror_r(int, char*, size_t); +// +// The former may or may not use the supplied buffer, and returns +// the error message string. The latter stores the error message +// string into the supplied buffer and returns an error code. + +#if HAVE_GNU_STRERROR_R + const char* ret = strerror_r(errnum, buf, buflen); + assert(ret != NULL); + if (ret != buf) + { + // message was returned but is static, copy for return + strncpy(buf, ret, buflen); + } +#else + int ret = strerror_r(errnum, buf, buflen); + // EINVAL: unknown error but reasonable message returned. + // ERANGE: too small for entire message, but still filled and null-terminated. + assert(ret == 0 || ret == EINVAL || ret == ERANGE); +#endif + return buf; +} diff --git a/src/libpsl-native/src/getstrerror.h b/src/libpsl-native/src/getstrerror.h new file mode 100644 index 0000000000..5d97a32208 --- /dev/null +++ b/src/libpsl-native/src/getstrerror.h @@ -0,0 +1,9 @@ +#pragma once + +#include "pal.h" + +PAL_BEGIN_EXTERNC + +char* GetStrError(int); + +PAL_END_EXTERNC diff --git a/src/libpsl-native/src/pal.h b/src/libpsl-native/src/pal.h index 39fb6db82c..9c657bb030 100644 --- a/src/libpsl-native/src/pal.h +++ b/src/libpsl-native/src/pal.h @@ -1,5 +1,7 @@ #pragma once +#include "config.h" + #include #include #include From e1aeeaa9c22c75a27cf88f2a0f5106ad74a8f1a3 Mon Sep 17 00:00:00 2001 From: Andrew Schwartzmeyer Date: Mon, 3 Oct 2016 15:22:28 -0700 Subject: [PATCH 03/20] Switch to Win32Exception(GetLastWin32Error) This is verified to work "correctly" on Linux in that it gets the `perror` for the last set value of errno in native code. No extra mapping or handling needs to be done on our part. Keeping the strerror_r implementation in the history for the valuable implementation of config.h.in in the library. --- .../CoreCLR/CorePsPlatform.cs | 23 +++++------ .../namespaces/FileSystemProvider.cs | 1 + src/libpsl-native/.gitignore | 1 - src/libpsl-native/src/CMakeLists.txt | 16 -------- src/libpsl-native/src/config.h.in | 1 - src/libpsl-native/src/getstrerror.cpp | 40 ------------------- src/libpsl-native/src/getstrerror.h | 9 ----- src/libpsl-native/src/pal.h | 2 - 8 files changed, 11 insertions(+), 82 deletions(-) delete mode 100644 src/libpsl-native/src/config.h.in delete mode 100644 src/libpsl-native/src/getstrerror.cpp delete mode 100644 src/libpsl-native/src/getstrerror.h diff --git a/src/System.Management.Automation/CoreCLR/CorePsPlatform.cs b/src/System.Management.Automation/CoreCLR/CorePsPlatform.cs index 2a6f6c99c7..2e209daf82 100644 --- a/src/System.Management.Automation/CoreCLR/CorePsPlatform.cs +++ b/src/System.Management.Automation/CoreCLR/CorePsPlatform.cs @@ -4,6 +4,7 @@ Copyright (c) Microsoft Corporation. All rights reserved. using System.Collections.Generic; using System.Runtime.InteropServices; +using System.ComponentModel; using Microsoft.Win32; using Microsoft.Win32.SafeHandles; using System.IO; @@ -451,13 +452,15 @@ namespace System.Management.Automation return 0; } + // Unix specific implementations of required functionality + // + // Please note that `Win32Exception(Marshal.GetLastWin32Error())` + // works *correctly* on Linux in that it creates an exception with + // the string perror would give you for the last set value of errno. + // No manual mapping is required. .NET Core maps the Linux errno + // to a PAL value and calls strerror_r underneath to generate the message. internal static class Unix { - internal static string GetLastPerror() - { - return Unix.NativeMethods.GetStrError(Marshal.GetLastWin32Error()); - } - private static string s_userName; public static string UserName { @@ -513,8 +516,7 @@ namespace System.Management.Automation } else { - int lastError = Marshal.GetLastWin32Error(); - throw new InvalidOperationException("Unix.IsHardLink error: " + lastError); + throw new Win32Exception(Marshal.GetLastWin32Error()); } } @@ -523,8 +525,7 @@ namespace System.Management.Automation int ret = NativeMethods.SetDate(info); if (ret == -1) { - int lastError = Marshal.GetLastWin32Error(); - throw new InvalidOperationException("Unix.NonWindowsSetDate error: " + lastError); + throw new Win32Exception(Marshal.GetLastWin32Error()); } } @@ -573,10 +574,6 @@ namespace System.Management.Automation // C bools are 1 byte and so must be marshaled as I1 - [DllImport(psLib, CharSet = CharSet.Ansi)] - [return: MarshalAs(UnmanagedType.LPStr)] - internal static extern string GetStrError(int errno); - [DllImport(psLib, CharSet = CharSet.Ansi, SetLastError = true)] [return: MarshalAs(UnmanagedType.LPStr)] internal static extern string GetUserName(); diff --git a/src/System.Management.Automation/namespaces/FileSystemProvider.cs b/src/System.Management.Automation/namespaces/FileSystemProvider.cs index 3d8452367f..8ea6f317e4 100644 --- a/src/System.Management.Automation/namespaces/FileSystemProvider.cs +++ b/src/System.Management.Automation/namespaces/FileSystemProvider.cs @@ -2231,6 +2231,7 @@ namespace Microsoft.PowerShell.Commands if (!success) { + // Porting note: The Win32Exception will report the correct error on Linux int errorCode = Marshal.GetLastWin32Error(); Win32Exception w32Exception = new Win32Exception((int)errorCode); diff --git a/src/libpsl-native/.gitignore b/src/libpsl-native/.gitignore index 61884d84d1..0dff693725 100644 --- a/src/libpsl-native/.gitignore +++ b/src/libpsl-native/.gitignore @@ -9,5 +9,4 @@ Testing/ test/psl-native-test src/libpsl-native.so src/libpsl-native.dylib -src/config.h test/native-tests.xml diff --git a/src/libpsl-native/src/CMakeLists.txt b/src/libpsl-native/src/CMakeLists.txt index 0f7490d863..5d4c432b40 100644 --- a/src/libpsl-native/src/CMakeLists.txt +++ b/src/libpsl-native/src/CMakeLists.txt @@ -1,18 +1,3 @@ -include(CheckCXXSourceCompiles) -check_cxx_source_compiles( - " - #include - int main() - { - char buffer[1]; - char* c = strerror_r(0, buffer, 0); - (void)c; - } - " - HAVE_GNU_STRERROR_R) - -configure_file(${CMAKE_CURRENT_SOURCE_DIR}/config.h.in ${CMAKE_CURRENT_BINARY_DIR}/config.h) - add_library(psl-native SHARED getstat.cpp getlstat.cpp @@ -24,7 +9,6 @@ add_library(psl-native SHARED getcomputername.cpp getlinkcount.cpp getfullyqualifiedname.cpp - getstrerror.cpp isfile.cpp isdirectory.cpp issymlink.cpp diff --git a/src/libpsl-native/src/config.h.in b/src/libpsl-native/src/config.h.in deleted file mode 100644 index 2b4d20c329..0000000000 --- a/src/libpsl-native/src/config.h.in +++ /dev/null @@ -1 +0,0 @@ -#cmakedefine HAVE_GNU_STRERROR_R 1 diff --git a/src/libpsl-native/src/getstrerror.cpp b/src/libpsl-native/src/getstrerror.cpp deleted file mode 100644 index 6d86cd8569..0000000000 --- a/src/libpsl-native/src/getstrerror.cpp +++ /dev/null @@ -1,40 +0,0 @@ -#include "getstrerror.h" - -#include -#include -#include -#include -#include - -char* GetStrError(int errnum) -{ - size_t buflen = 256; - char* buf = (char*)calloc(buflen, sizeof(char)); - -// Note that we must use strerror_r because plain strerror is not -// thread-safe. -// -// However, there are two versions of strerror_r: -// - GNU: char* strerror_r(int, char*, size_t); -// - POSIX: int strerror_r(int, char*, size_t); -// -// The former may or may not use the supplied buffer, and returns -// the error message string. The latter stores the error message -// string into the supplied buffer and returns an error code. - -#if HAVE_GNU_STRERROR_R - const char* ret = strerror_r(errnum, buf, buflen); - assert(ret != NULL); - if (ret != buf) - { - // message was returned but is static, copy for return - strncpy(buf, ret, buflen); - } -#else - int ret = strerror_r(errnum, buf, buflen); - // EINVAL: unknown error but reasonable message returned. - // ERANGE: too small for entire message, but still filled and null-terminated. - assert(ret == 0 || ret == EINVAL || ret == ERANGE); -#endif - return buf; -} diff --git a/src/libpsl-native/src/getstrerror.h b/src/libpsl-native/src/getstrerror.h deleted file mode 100644 index 5d97a32208..0000000000 --- a/src/libpsl-native/src/getstrerror.h +++ /dev/null @@ -1,9 +0,0 @@ -#pragma once - -#include "pal.h" - -PAL_BEGIN_EXTERNC - -char* GetStrError(int); - -PAL_END_EXTERNC diff --git a/src/libpsl-native/src/pal.h b/src/libpsl-native/src/pal.h index 9c657bb030..39fb6db82c 100644 --- a/src/libpsl-native/src/pal.h +++ b/src/libpsl-native/src/pal.h @@ -1,7 +1,5 @@ #pragma once -#include "config.h" - #include #include #include From 196a37b1186d5d4901c515c02bc09bee9520cf59 Mon Sep 17 00:00:00 2001 From: Andrew Schwartzmeyer Date: Mon, 3 Oct 2016 15:41:38 -0700 Subject: [PATCH 04/20] Add native errno to ErrorCategory mapper --- .../CoreCLR/CorePsPlatform.cs | 9 +++ .../namespaces/FileSystemProvider.cs | 4 ++ src/libpsl-native/src/CMakeLists.txt | 1 + src/libpsl-native/src/geterrorcategory.cpp | 63 +++++++++++++++++++ src/libpsl-native/src/geterrorcategory.h | 9 +++ 5 files changed, 86 insertions(+) create mode 100644 src/libpsl-native/src/geterrorcategory.cpp create mode 100644 src/libpsl-native/src/geterrorcategory.h diff --git a/src/System.Management.Automation/CoreCLR/CorePsPlatform.cs b/src/System.Management.Automation/CoreCLR/CorePsPlatform.cs index 2e209daf82..34cb42a93c 100644 --- a/src/System.Management.Automation/CoreCLR/CorePsPlatform.cs +++ b/src/System.Management.Automation/CoreCLR/CorePsPlatform.cs @@ -461,6 +461,12 @@ namespace System.Management.Automation // to a PAL value and calls strerror_r underneath to generate the message. internal static class Unix { + // This is a helper that attempts to map errno into a PowerShell ErrorCategory + internal static ErrorCategory GetErrorCategory(int errno) + { + return (ErrorCategory)Unix.NativeMethods.GetErrorCategory(errno); + } + private static string s_userName; public static string UserName { @@ -574,6 +580,9 @@ namespace System.Management.Automation // C bools are 1 byte and so must be marshaled as I1 + [DllImport(psLib, CharSet = CharSet.Ansi)] + internal static extern int GetErrorCategory(int errno); + [DllImport(psLib, CharSet = CharSet.Ansi, SetLastError = true)] [return: MarshalAs(UnmanagedType.LPStr)] internal static extern string GetUserName(); diff --git a/src/System.Management.Automation/namespaces/FileSystemProvider.cs b/src/System.Management.Automation/namespaces/FileSystemProvider.cs index 8ea6f317e4..f04a76d5f7 100644 --- a/src/System.Management.Automation/namespaces/FileSystemProvider.cs +++ b/src/System.Management.Automation/namespaces/FileSystemProvider.cs @@ -2236,7 +2236,11 @@ namespace Microsoft.PowerShell.Commands Win32Exception w32Exception = new Win32Exception((int)errorCode); +#if UNIX + if (Platform.Unix.GetErrorCategory(errorCode) == ErrorCategory.PermissionDenied) +#else if (errorCode == 1314) //ERROR_PRIVILEGE_NOT_HELD +#endif { string message = FileSystemProviderStrings.ElevationRequired; WriteError(new ErrorRecord(new UnauthorizedAccessException(message, w32Exception), "NewItemSymbolicLinkElevationRequired", ErrorCategory.PermissionDenied, value.ToString())); diff --git a/src/libpsl-native/src/CMakeLists.txt b/src/libpsl-native/src/CMakeLists.txt index 5d4c432b40..1552ce3eec 100644 --- a/src/libpsl-native/src/CMakeLists.txt +++ b/src/libpsl-native/src/CMakeLists.txt @@ -9,6 +9,7 @@ add_library(psl-native SHARED getcomputername.cpp getlinkcount.cpp getfullyqualifiedname.cpp + geterrorcategory.cpp isfile.cpp isdirectory.cpp issymlink.cpp diff --git a/src/libpsl-native/src/geterrorcategory.cpp b/src/libpsl-native/src/geterrorcategory.cpp new file mode 100644 index 0000000000..52abf3e5dc --- /dev/null +++ b/src/libpsl-native/src/geterrorcategory.cpp @@ -0,0 +1,63 @@ +#include "geterrorcategory.h" + +#include +#include +#include +#include +#include + +// Copy of PowerShell ErrorCategory enum from ErrorPackage.cs +enum ErrorCategory { + NotSpecified = 0, + OpenError = 1, + CloseError = 2, + DeviceError = 3, + DeadlockDetected = 4, + InvalidArgument = 5, + InvalidData = 6, + InvalidOperation = 7, + InvalidResult = 8, + InvalidType = 9, + MetadataError = 10, + NotImplemented = 11, + NotInstalled = 12, + ObjectNotFound = 13, + OperationStopped = 14, + OperationTimeout = 15, + SyntaxError = 16, + ParserError = 17, + PermissionDenied = 18, + ResourceBusy = 19, + ResourceExists = 20, + ResourceUnavailable = 21, + ReadError = 22, + WriteError = 23, + FromStdErr = 24, + SecurityError = 25, + ProtocolError = 26, + ConnectionError = 27, + AuthenticationError = 28, + LimitsExceeded = 29, + QuotaExceeded = 30, + NotEnabled = 31, +}; + +//! @brief Maps Linux errno to PowerShell ErrorCategory +int32_t GetErrorCategory(int32_t errnum) +{ + switch (errnum) + { + case EINVAL: + return InvalidArgument; + case ENOENT: + case ESRCH: + return ObjectNotFound; + case EINTR: + return OperationStopped; + case EACCES: + case EPERM: + return PermissionDenied; + default: + return NotSpecified; + } +} diff --git a/src/libpsl-native/src/geterrorcategory.h b/src/libpsl-native/src/geterrorcategory.h new file mode 100644 index 0000000000..fe7a9437f4 --- /dev/null +++ b/src/libpsl-native/src/geterrorcategory.h @@ -0,0 +1,9 @@ +#pragma once + +#include "pal.h" + +PAL_BEGIN_EXTERNC + +int32_t GetErrorCategory(int32_t); + +PAL_END_EXTERNC From fc5a1ae6aac3f6357f673daee8ce2f29d1a5e09a Mon Sep 17 00:00:00 2001 From: Andrew Schwartzmeyer Date: Fri, 30 Sep 2016 14:47:24 -0700 Subject: [PATCH 05/20] Clean up SetDate Remove pass-by-reference from C API --- .../commands/utility/SetDateCommand.cs | 58 +++++++++---------- .../project.json | 8 +++ .../CoreCLR/CorePsPlatform.cs | 13 +---- src/libpsl-native/src/setdate.cpp | 31 +++------- src/libpsl-native/src/setdate.h | 2 +- 5 files changed, 45 insertions(+), 67 deletions(-) diff --git a/src/Microsoft.PowerShell.Commands.Utility/commands/utility/SetDateCommand.cs b/src/Microsoft.PowerShell.Commands.Utility/commands/utility/SetDateCommand.cs index b865b197b5..04f0033a37 100644 --- a/src/Microsoft.PowerShell.Commands.Utility/commands/utility/SetDateCommand.cs +++ b/src/Microsoft.PowerShell.Commands.Utility/commands/utility/SetDateCommand.cs @@ -69,42 +69,37 @@ namespace Microsoft.PowerShell.Commands goto case "Date"; } - // - - // build up the SystemTime struct to pass to SetSystemTime - NativeMethods.SystemTime systemTime = new NativeMethods.SystemTime(); - systemTime.Year = (UInt16)dateToUse.Year; - systemTime.Month = (UInt16)dateToUse.Month; - systemTime.Day = (UInt16)dateToUse.Day; - systemTime.Hour = (UInt16)dateToUse.Hour; - systemTime.Minute = (UInt16)dateToUse.Minute; - systemTime.Second = (UInt16)dateToUse.Second; - systemTime.Milliseconds = (UInt16)dateToUse.Millisecond; - if (ShouldProcess(dateToUse.ToString())) { - if (Platform.IsWindows) +#if UNIX + if (!Platform.NonWindowsSetDate(dateToUse)) { + throw new Win32Exception(Marshal.GetLastWin32Error()); + } +#else + // build up the SystemTime struct to pass to SetSystemTime + NativeMethods.SystemTime systemTime = new NativeMethods.SystemTime(); + systemTime.Year = (UInt16)dateToUse.Year; + systemTime.Month = (UInt16)dateToUse.Month; + systemTime.Day = (UInt16)dateToUse.Day; + systemTime.Hour = (UInt16)dateToUse.Hour; + systemTime.Minute = (UInt16)dateToUse.Minute; + systemTime.Second = (UInt16)dateToUse.Second; + systemTime.Milliseconds = (UInt16)dateToUse.Millisecond; #pragma warning disable 56523 - - if (!NativeMethods.SetLocalTime(ref systemTime)) - { - throw new Win32Exception(Marshal.GetLastWin32Error()); - } - - // MSDN says to call this twice to account for changes - // between DST - if (!NativeMethods.SetLocalTime(ref systemTime)) - { - throw new Win32Exception(Marshal.GetLastWin32Error()); - } - -#pragma warning restore 56523 - } - else + if (!NativeMethods.SetLocalTime(ref systemTime)) { - Platform.NonWindowsSetDate(dateToUse); + throw new Win32Exception(Marshal.GetLastWin32Error()); } + + // MSDN says to call this twice to account for changes + // between DST + if (!NativeMethods.SetLocalTime(ref systemTime)) + { + throw new Win32Exception(Marshal.GetLastWin32Error()); + } +#pragma warning restore 56523 +#endif } //output DateTime object wrapped in an PSObject with DisplayHint attached @@ -121,7 +116,8 @@ namespace Microsoft.PowerShell.Commands internal static class NativeMethods { - public struct SystemTime + [StructLayout(LayoutKind.Sequential)] + public class SystemTime { public UInt16 Year; public UInt16 Month; diff --git a/src/Microsoft.PowerShell.Commands.Utility/project.json b/src/Microsoft.PowerShell.Commands.Utility/project.json index a1443bd9a0..6e84936749 100644 --- a/src/Microsoft.PowerShell.Commands.Utility/project.json +++ b/src/Microsoft.PowerShell.Commands.Utility/project.json @@ -12,6 +12,14 @@ "allowUnsafe": true }, + "configurations": { + "Linux": { + "buildOptions": { + "define": [ "UNIX" ] + } + } + }, + "dependencies": { "System.Management.Automation": "1.0.0-*" }, diff --git a/src/System.Management.Automation/CoreCLR/CorePsPlatform.cs b/src/System.Management.Automation/CoreCLR/CorePsPlatform.cs index 34cb42a93c..3733458ebd 100644 --- a/src/System.Management.Automation/CoreCLR/CorePsPlatform.cs +++ b/src/System.Management.Automation/CoreCLR/CorePsPlatform.cs @@ -403,10 +403,10 @@ namespace System.Management.Automation return Unix.CreateHardLink(path, strTargetPath); } - internal static void NonWindowsSetDate(DateTime dateToUse) + internal static bool NonWindowsSetDate(DateTime dateToUse) { Unix.SetDateInfoInternal date = new Unix.SetDateInfoInternal(dateToUse); - Unix.SetDate(date); + return Unix.NativeMethods.SetDate(date) == 0; } internal static string NonWindowsGetDomainName() @@ -526,15 +526,6 @@ namespace System.Management.Automation } } - public static void SetDate(SetDateInfoInternal info) - { - int ret = NativeMethods.SetDate(info); - if (ret == -1) - { - throw new Win32Exception(Marshal.GetLastWin32Error()); - } - } - public static bool CreateHardLink(string path, string strTargetPath) { int ret = NativeMethods.CreateHardLink(path, strTargetPath); diff --git a/src/libpsl-native/src/setdate.cpp b/src/libpsl-native/src/setdate.cpp index 3a2c179d7e..3f350101ff 100644 --- a/src/libpsl-native/src/setdate.cpp +++ b/src/libpsl-native/src/setdate.cpp @@ -4,6 +4,7 @@ #include "setdate.h" +#include #include #include #include @@ -11,8 +12,8 @@ #include #include -//! @brief SetDate sets the date and time on local computer. You must -//! be super-user to set the time. +//! @brief SetDate sets the date and time on local computer. +//! You must be super-user to set the time. //! //! SetDate //! @@ -20,27 +21,17 @@ //! @parblock //! A struct that contains program to execute and its parameters //! -//! @exception errno Passes these errors via errno to GetLastError: -//! - ERROR_BAD_ENVIRONMENT: locale is not UTF-8 -//! - ERROR_INVALID_PARAMETER: time was not passed in correctly -//! - ERROR_ACCESS_DENIED: you must be super-user to set the date -//! //! @retval 0 successfully set date -//! @retval -1 if failure occurred. To get extended error information, call GetLastError. +//! @retval -1 if failure occurred. //! - -int32_t SetDate(const SetDateInfo &info) +int32_t SetDate(const SetDateInfo info) { errno = 0; // Select locale from environment setlocale(LC_ALL, ""); // Check that locale is UTF-8 - if (nl_langinfo(CODESET) != std::string("UTF-8")) - { - errno = ERROR_BAD_ENVIRONMENT; - return -1; - } + assert(nl_langinfo(CODESET) == std::string("UTF-8")); struct tm bdTime; struct timeval tv; @@ -56,19 +47,11 @@ int32_t SetDate(const SetDateInfo &info) time_t newTime = mktime(&bdTime); if (newTime == -1) { - errno = ERROR_INVALID_PARAMETER; return -1; } tv.tv_sec = newTime; tv.tv_usec = 0; - int result = settimeofday(&tv, NULL); - if (result == -1) - { - errno = ERROR_ACCESS_DENIED; - return -1; - } - - return 0; + return settimeofday(&tv, NULL); } diff --git a/src/libpsl-native/src/setdate.h b/src/libpsl-native/src/setdate.h index b55a7d1e7a..bf2bccaed1 100644 --- a/src/libpsl-native/src/setdate.h +++ b/src/libpsl-native/src/setdate.h @@ -17,6 +17,6 @@ typedef struct setDateInfo int32_t DST; } SetDateInfo; -int32_t SetDate(const SetDateInfo &info); +int32_t SetDate(const SetDateInfo info); PAL_END_EXTERNC From 82867a5c12e9b4c56ef65e3b2e9e0ce722882bcd Mon Sep 17 00:00:00 2001 From: Andrew Schwartzmeyer Date: Mon, 3 Oct 2016 17:24:28 -0700 Subject: [PATCH 06/20] Clean up FollowSymLink --- .../namespaces/FileSystemProvider.cs | 19 ++++--- src/libpsl-native/src/followsymlink.cpp | 57 +------------------ 2 files changed, 13 insertions(+), 63 deletions(-) diff --git a/src/System.Management.Automation/namespaces/FileSystemProvider.cs b/src/System.Management.Automation/namespaces/FileSystemProvider.cs index f04a76d5f7..015cd8bdac 100644 --- a/src/System.Management.Automation/namespaces/FileSystemProvider.cs +++ b/src/System.Management.Automation/namespaces/FileSystemProvider.cs @@ -8033,17 +8033,18 @@ namespace Microsoft.PowerShell.Commands private static List InternalGetTarget(string filePath) { var links = new List(); - if (!Platform.IsWindows) +#if UNIX + string link = Platform.NonWindowsInternalGetTarget(filePath); + if (!String.IsNullOrEmpty(link)) { - string link = Platform.NonWindowsInternalGetTarget(filePath); - if (!String.IsNullOrEmpty(link)) - { - links.Add(link); - } - return links; + links.Add(link); + } + else + { + throw new Win32Exception(Marshal.GetLastWin32Error()); } -#if !CORECLR //FindFirstFileName, FindNextFileName and FindClose are not available on Core Clr +#elif !CORECLR //FindFirstFileName, FindNextFileName and FindClose are not available on Core Clr UInt32 linkStringLength = 0; var linkName = new StringBuilder(); @@ -8101,7 +8102,7 @@ namespace Microsoft.PowerShell.Commands { InternalSymbolicLinkLinkCodeMethods.FindClose(fileHandle); } -#endif +#endif return links; } diff --git a/src/libpsl-native/src/followsymlink.cpp b/src/libpsl-native/src/followsymlink.cpp index 78b6831beb..6f32d697d7 100644 --- a/src/libpsl-native/src/followsymlink.cpp +++ b/src/libpsl-native/src/followsymlink.cpp @@ -5,14 +5,12 @@ #include "followsymlink.h" #include "issymlink.h" +#include #include #include #include -#include -//! @brief Followsymlink determines target path of a sym link -//! -//! Followsymlink +//! @brief FollowSymLink determines target path of a sym link //! //! @param[in] fileName //! @parblock @@ -21,31 +19,14 @@ //! char* is marshaled as an LPStr, which on Linux is UTF-8. //! @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 target path, or NULL if unsuccessful //! char* FollowSymLink(const char* fileName) { + assert(fileName); errno = 0; - if (!fileName) - { - errno = ERROR_INVALID_PARAMETER; - return NULL; - } - // return null for non symlinks if (!IsSymLink(fileName)) { @@ -65,38 +46,6 @@ char* FollowSymLink(const char* fileName) ssize_t sz = readlink(fileName, buffer, PATH_MAX); if (sz == -1) { - switch(errno) - { - case EACCES: - errno = ERROR_ACCESS_DENIED; - break; - case EFAULT: - errno = ERROR_INVALID_ADDRESS; - break; - case EINVAL: - errno = ERROR_INVALID_NAME; - case EIO: - errno = ERROR_GEN_FAILURE; - break; - case ELOOP: - errno = ERROR_STOPPED_ON_SYMLINK; - break; - case ENAMETOOLONG: - errno = ERROR_BAD_PATH_NAME; - break; - case ENOENT: - errno = ERROR_FILE_NOT_FOUND; - break; - case ENOMEM: - errno = ERROR_OUTOFMEMORY; - break; - case ENOTDIR: - errno = ERROR_BAD_PATH_NAME; - break; - default: - errno = ERROR_INVALID_FUNCTION; - } - return NULL; } From bdfe69355f4f8f977df6823646aaadc58421a349 Mon Sep 17 00:00:00 2001 From: Andrew Schwartzmeyer Date: Mon, 3 Oct 2016 19:06:42 -0700 Subject: [PATCH 07/20] Clean up GetComputerName --- src/libpsl-native/src/getcomputername.cpp | 22 +++------------------- 1 file changed, 3 insertions(+), 19 deletions(-) diff --git a/src/libpsl-native/src/getcomputername.cpp b/src/libpsl-native/src/getcomputername.cpp index 1c257e1fa7..606bdc60e1 100644 --- a/src/libpsl-native/src/getcomputername.cpp +++ b/src/libpsl-native/src/getcomputername.cpp @@ -11,36 +11,20 @@ //! @brief GetComputerName retrieves the name of the host associated with //! the current thread. //! -//! @exception errno Passes these errors via errno to GetLastError: -//! - ERROR_INVALID_FUNCTION: getlogin_r() returned an unrecognized error code -//! - ERROR_INVALID_ADDRESS: buffer is an invalid address -//! - ERROR_GEN_FAILURE: buffer not large enough -//! //! @retval username as UTF-8 string, or null if unsuccessful char* GetComputerName() { - errno = 0; + errno = 0; // Get computername from system, note that gethostname(2) gets the // nodename from uname std::string computername(_POSIX_HOST_NAME_MAX, 0); int err = gethostname(&computername[0], computername.length()); // Map errno to Win32 Error Codes - if (err != 0) + if (err != 0) { - switch (errno) - { - case EFAULT: - errno = ERROR_INVALID_ADDRESS; - break; - case ENAMETOOLONG: - errno = ERROR_GEN_FAILURE; - break; - default: - errno = ERROR_INVALID_FUNCTION; - } return NULL; } - + return strdup(computername.c_str()); } From 0ce5575f578a7b23edf4e09e5afa0550b8ffdbea Mon Sep 17 00:00:00 2001 From: Andrew Schwartzmeyer Date: Mon, 3 Oct 2016 15:28:58 -0700 Subject: [PATCH 08/20] Clean up CreateSymLink --- .../CoreCLR/CorePsPlatform.cs | 7 +- .../namespaces/FileSystemProvider.cs | 13 ++- src/libpsl-native/src/createsymlink.cpp | 80 ++----------------- src/libpsl-native/src/createsymlink.h | 2 +- src/libpsl-native/test/test-createsymlink.cpp | 33 +++----- src/libpsl-native/test/test-issymlink.cpp | 2 +- .../New-Item.Tests.ps1 | 10 +++ 7 files changed, 40 insertions(+), 107 deletions(-) diff --git a/src/System.Management.Automation/CoreCLR/CorePsPlatform.cs b/src/System.Management.Automation/CoreCLR/CorePsPlatform.cs index 3733458ebd..54b8bcaa56 100644 --- a/src/System.Management.Automation/CoreCLR/CorePsPlatform.cs +++ b/src/System.Management.Automation/CoreCLR/CorePsPlatform.cs @@ -395,7 +395,7 @@ namespace System.Management.Automation internal static bool NonWindowsCreateSymbolicLink(string path, string target) { // Linux doesn't care if target is a directory or not - return Unix.NativeMethods.CreateSymLink(path, target); + return Unix.NativeMethods.CreateSymLink(path, target) == 0; } internal static bool NonWindowsCreateHardLink(string path, string strTargetPath) @@ -597,9 +597,8 @@ namespace System.Management.Automation internal static extern int SetDate(SetDateInfoInternal info); [DllImport(psLib, CharSet = CharSet.Ansi, SetLastError = true)] - [return: MarshalAs(UnmanagedType.I1)] - internal static extern bool CreateSymLink([MarshalAs(UnmanagedType.LPStr)]string filePath, - [MarshalAs(UnmanagedType.LPStr)]string target); + internal static extern int CreateSymLink([MarshalAs(UnmanagedType.LPStr)]string filePath, + [MarshalAs(UnmanagedType.LPStr)]string target); [DllImport(psLib, CharSet = CharSet.Ansi, SetLastError = true)] internal static extern int CreateHardLink([MarshalAs(UnmanagedType.LPStr)]string filePath, diff --git a/src/System.Management.Automation/namespaces/FileSystemProvider.cs b/src/System.Management.Automation/namespaces/FileSystemProvider.cs index 015cd8bdac..1b7f76257c 100644 --- a/src/System.Management.Automation/namespaces/FileSystemProvider.cs +++ b/src/System.Management.Automation/namespaces/FileSystemProvider.cs @@ -2208,14 +2208,11 @@ namespace Microsoft.PowerShell.Commands if (itemType == ItemType.SymbolicLink) { - if (Platform.IsWindows) - { - success = WinCreateSymbolicLink(path, strTargetPath, isDirectory); - } - else - { - success = Platform.NonWindowsCreateSymbolicLink(path, strTargetPath); - } +#if UNIX + success = Platform.NonWindowsCreateSymbolicLink(path, strTargetPath); +#else + success = WinCreateSymbolicLink(path, strTargetPath, isDirectory); +#endif } else if (itemType == ItemType.HardLink) { diff --git a/src/libpsl-native/src/createsymlink.cpp b/src/libpsl-native/src/createsymlink.cpp index 6cd712781c..22ea389a30 100644 --- a/src/libpsl-native/src/createsymlink.cpp +++ b/src/libpsl-native/src/createsymlink.cpp @@ -4,6 +4,7 @@ #include "createsymlink.h" +#include #include #include #include @@ -26,82 +27,15 @@ //! char* is marshaled as an LPStr, which on Linux is UTF-8. //! @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_FILE_NOT_FOUND: the system cannot find the file specified -//! - ERROR_INVALID_ADDRESS: attempt to access invalid address -//! - ERROR_STOPPED_ON_SYMLINK: the operation stopped after reaching a symbolic link -//! - ERROR_GEN_FAILURE: device attached to the system is not functioning -//! - ERROR_NO_SUCH_USER: there was no corresponding entry in the utmp-file -//! - ERROR_INVALID_NAME: filename, directory name, or volume label syntax is incorrect -//! - ERROR_BUFFER_OVERFLOW: file name is too long -//! - ERROR_INVALID_FUNCTION: incorrect function -//! - ERROR_BAD_PATH_NAME: pathname is too long, or contains invalid characters -//! -//! @retval boolean successful +//! @retval 0 if successful, -1 otherwise //! -bool CreateSymLink(const char *link, const char *target) +int32_t CreateSymLink(const char *link, const char *target) { + assert(link); + assert(target); + errno = 0; - // Check parameters - if (!link || !target) - { - errno = ERROR_INVALID_PARAMETER; - return false; - } - - int ret = symlink(target, link); - - if (ret == 0) - { - return true; - } - - switch(errno) - { - case EACCES: - errno = ERROR_ACCESS_DENIED; - break; - case EDQUOT: - errno = ERROR_DISK_FULL; - break; - case EEXIST: - errno = ERROR_FILE_EXISTS; - break; - case EFAULT: - errno = ERROR_INVALID_ADDRESS; - break; - case EIO: - errno = ERROR_GEN_FAILURE; - break; - case ELOOP: - errno = ERROR_STOPPED_ON_SYMLINK; - break; - case ENAMETOOLONG: - errno = ERROR_BAD_PATH_NAME; - break; - case ENOENT: - errno = ERROR_FILE_NOT_FOUND; - break; - case ENOMEM: - errno = ERROR_OUTOFMEMORY; - break; - case ENOTDIR: - errno = ERROR_INVALID_NAME; - break; - case ENOSPC: - errno = ERROR_DISK_FULL; - break; - case EPERM: - errno = ERROR_GEN_FAILURE; - break; - default: - errno = ERROR_INVALID_FUNCTION; - } - - return false; + return symlink(target, link); } diff --git a/src/libpsl-native/src/createsymlink.h b/src/libpsl-native/src/createsymlink.h index e2f4bd3d18..d40821d837 100644 --- a/src/libpsl-native/src/createsymlink.h +++ b/src/libpsl-native/src/createsymlink.h @@ -6,6 +6,6 @@ PAL_BEGIN_EXTERNC -bool CreateSymLink(const char *link, const char *target); +int32_t 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 1aab3379a0..9bd96f346f 100644 --- a/src/libpsl-native/test/test-createsymlink.cpp +++ b/src/libpsl-native/test/test-createsymlink.cpp @@ -39,12 +39,12 @@ protected: EXPECT_TRUE(dir != NULL); // Create symbolic link to file - bool ret1 = CreateSymLink(fileSymLink.c_str(), file); - EXPECT_TRUE(ret1); + int ret = CreateSymLink(fileSymLink.c_str(), file); + EXPECT_EQ(0, ret); // Create symbolic link to directory - bool ret2 = CreateSymLink(dirSymLink.c_str(), dir); - EXPECT_TRUE(ret2); + ret = CreateSymLink(dirSymLink.c_str(), dir); + EXPECT_EQ(0, ret); } ~CreateSymLinkTest() @@ -65,13 +65,6 @@ protected: } }; -TEST_F(CreateSymLinkTest, FilePathNameIsNull) -{ - bool retVal = CreateSymLink(NULL, NULL); - EXPECT_FALSE(retVal); - EXPECT_EQ(ERROR_INVALID_PARAMETER, errno); -} - TEST_F(CreateSymLinkTest, FilePathNameDoesNotExist) { std::string invalidFile = "/tmp/symlinktest_invalidFile"; @@ -82,8 +75,8 @@ TEST_F(CreateSymLinkTest, FilePathNameDoesNotExist) unlink(invalidLink.c_str()); // Linux allows creation of symbolic link that points to an invalid file - bool retVal = CreateSymLink(invalidLink.c_str(), invalidFile.c_str()); - EXPECT_TRUE(retVal); + int ret = CreateSymLink(invalidLink.c_str(), invalidFile.c_str()); + EXPECT_EQ(0, ret); std::string target = FollowSymLink(invalidLink.c_str()); EXPECT_EQ(target, invalidFile); @@ -93,8 +86,8 @@ TEST_F(CreateSymLinkTest, FilePathNameDoesNotExist) TEST_F(CreateSymLinkTest, SymLinkToFile) { - bool retVal = IsSymLink(fileSymLink.c_str()); - EXPECT_TRUE(retVal); + bool ret = IsSymLink(fileSymLink.c_str()); + EXPECT_TRUE(ret); std::string target = FollowSymLink(fileSymLink.c_str()); char buffer[PATH_MAX]; @@ -104,8 +97,8 @@ TEST_F(CreateSymLinkTest, SymLinkToFile) TEST_F(CreateSymLinkTest, SymLinkToDirectory) { - bool retVal = IsSymLink(dirSymLink.c_str()); - EXPECT_TRUE(retVal); + bool ret = IsSymLink(dirSymLink.c_str()); + EXPECT_TRUE(ret); std::string target = FollowSymLink(dirSymLink.c_str()); char buffer[PATH_MAX]; @@ -115,7 +108,7 @@ TEST_F(CreateSymLinkTest, SymLinkToDirectory) TEST_F(CreateSymLinkTest, SymLinkAgain) { - bool retVal = CreateSymLink(fileSymLink.c_str(), file); - EXPECT_FALSE(retVal); - EXPECT_EQ(ERROR_FILE_EXISTS, errno); + int ret = CreateSymLink(fileSymLink.c_str(), file); + EXPECT_EQ(-1, ret); + EXPECT_EQ(EEXIST, errno); } diff --git a/src/libpsl-native/test/test-issymlink.cpp b/src/libpsl-native/test/test-issymlink.cpp index 512a4053a9..463c124c10 100644 --- a/src/libpsl-native/test/test-issymlink.cpp +++ b/src/libpsl-native/test/test-issymlink.cpp @@ -65,7 +65,7 @@ TEST_F(isSymLinkTest, FilePathNameDoesNotExist) { std::string invalidFile = "/tmp/symlinktest_invalidFile"; EXPECT_FALSE(IsSymLink(invalidFile.c_str())); - EXPECT_EQ(ERROR_FILE_NOT_FOUND, errno); + EXPECT_EQ(ENOENT, errno); } TEST_F(isSymLinkTest, NormalFileIsNotSymLink) 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 9197ad9d1c..8a1d87c200 100644 --- a/test/powershell/Modules/Microsoft.PowerShell.Management/New-Item.Tests.ps1 +++ b/test/powershell/Modules/Microsoft.PowerShell.Management/New-Item.Tests.ps1 @@ -171,4 +171,14 @@ Describe "New-Item with links" -Tags @('CI', 'RequireAdminOnWindows') { # Remove the link explicitly to avoid broken symlink issue Remove-Item $FullyQualifiedLink -Force } + + It "Should error correctly when failing to create a symbolic link" -Skip:($IsWindows -or $IsElevated) { + # This test expects that /sbin exists but is not writable by the user + try { + New-Item -ItemType SymbolicLink -Path "/sbin/powershell-test" -Target $FullyQualifiedFolder -ErrorAction Stop + throw "Execution OK" + } catch { + $_.FullyQualifiedErrorId | Should Be "NewItemSymbolicLinkElevationRequired,Microsoft.PowerShell.Commands.NewItemCommand" + } + } } From b4b22785713bd5d3a08766f64703f6806814439e Mon Sep 17 00:00:00 2001 From: Andrew Schwartzmeyer Date: Mon, 3 Oct 2016 13:50:57 -0700 Subject: [PATCH 09/20] Clean up CreateHardLink --- .../CoreCLR/CorePsPlatform.cs | 8 +- .../namespaces/FileSystemProvider.cs | 13 ++- src/libpsl-native/src/createhardlink.cpp | 88 ++----------------- .../test/test-createhardlink.cpp | 39 ++++---- 4 files changed, 26 insertions(+), 122 deletions(-) diff --git a/src/System.Management.Automation/CoreCLR/CorePsPlatform.cs b/src/System.Management.Automation/CoreCLR/CorePsPlatform.cs index 54b8bcaa56..16e5ea5d95 100644 --- a/src/System.Management.Automation/CoreCLR/CorePsPlatform.cs +++ b/src/System.Management.Automation/CoreCLR/CorePsPlatform.cs @@ -400,7 +400,7 @@ namespace System.Management.Automation internal static bool NonWindowsCreateHardLink(string path, string strTargetPath) { - return Unix.CreateHardLink(path, strTargetPath); + return Unix.NativeMethods.CreateHardLink(path, strTargetPath) == 0; } internal static bool NonWindowsSetDate(DateTime dateToUse) @@ -526,12 +526,6 @@ namespace System.Management.Automation } } - public static bool CreateHardLink(string path, string strTargetPath) - { - int ret = NativeMethods.CreateHardLink(path, strTargetPath); - return ret == 1 ? true : false; - } - [StructLayout(LayoutKind.Sequential)] internal class SetDateInfoInternal { diff --git a/src/System.Management.Automation/namespaces/FileSystemProvider.cs b/src/System.Management.Automation/namespaces/FileSystemProvider.cs index 1b7f76257c..8111a1a048 100644 --- a/src/System.Management.Automation/namespaces/FileSystemProvider.cs +++ b/src/System.Management.Automation/namespaces/FileSystemProvider.cs @@ -2216,14 +2216,11 @@ namespace Microsoft.PowerShell.Commands } else if (itemType == ItemType.HardLink) { - if (Platform.IsWindows) - { - success = WinCreateHardLink(path, strTargetPath); - } - else - { - success = Platform.NonWindowsCreateHardLink(path, strTargetPath); - } +#if UNIX + success = Platform.NonWindowsCreateHardLink(path, strTargetPath); +#else + success = WinCreateHardLink(path, strTargetPath); +#endif } if (!success) diff --git a/src/libpsl-native/src/createhardlink.cpp b/src/libpsl-native/src/createhardlink.cpp index 8cbc1d6663..d3bd84685e 100644 --- a/src/libpsl-native/src/createhardlink.cpp +++ b/src/libpsl-native/src/createhardlink.cpp @@ -4,7 +4,7 @@ #include "createhardlink.h" -#include +#include #include #include @@ -26,91 +26,13 @@ //! char* is marshaled as an LPStr, which on Linux is UTF-8. //! @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_FILE_NOT_FOUND: the system cannot find the file specified -//! - ERROR_INVALID_ADDRESS: attempt to access invalid address -//! - ERROR_TOO_MANY_LINK: max number of hard links has been exceeded -//! - ERROR_GEN_FAILURE: device attached to the system is not functioning -//! - ERROR_NO_SUCH_USER: there was no corresponding entry in the utmp-file -//! - ERROR_INVALID_NAME: filename, directory name, or volume label syntax is incorrect -//! - ERROR_BUFFER_OVERFLOW: file name is too long -//! - 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 creation failed +//! @retval 0 if successful, otherwise -1 //! int32_t CreateHardLink(const char *newlink, const char *target) { - errno = 0; + assert(newlink); + assert(target); - // Check parameters - if (!newlink || !target) - { - errno = ERROR_INVALID_PARAMETER; - return 0; - } - - int returnCode = link(target, newlink); - - if (returnCode == 0) - { - return 1; - } - - switch(errno) - { - case EACCES: - errno = ERROR_ACCESS_DENIED; - break; - case EDQUOT: - errno = ERROR_DISK_FULL; - break; - case EEXIST: - errno = ERROR_FILE_EXISTS; - break; - case EFAULT: - errno = ERROR_INVALID_ADDRESS; - break; - case EIO: - errno = ERROR_GEN_FAILURE; - break; - case ELOOP: - errno = ERROR_TOO_MANY_LINKS; - break; - case EMLINK: - errno = ERROR_TOO_MANY_LINKS; - break; - case ENAMETOOLONG: - errno = ERROR_BAD_PATH_NAME; - break; - case ENOENT: - errno = ERROR_FILE_NOT_FOUND; - break; - case ENOMEM: - errno = ERROR_OUTOFMEMORY; - break; - case ENOTDIR: - errno = ERROR_INVALID_NAME; - break; - case ENOSPC: - errno = ERROR_DISK_FULL; - break; - case EPERM: - errno = ERROR_ACCESS_DENIED; - break; - case EROFS: - errno = ERROR_ACCESS_DENIED; - break; - case EXDEV: - errno = ERROR_GEN_FAILURE; - break; - default: - errno = ERROR_INVALID_FUNCTION; - } - return 0; + return link(target, newlink); } diff --git a/src/libpsl-native/test/test-createhardlink.cpp b/src/libpsl-native/test/test-createhardlink.cpp index 090864b9f7..1c18de66b0 100644 --- a/src/libpsl-native/test/test-createhardlink.cpp +++ b/src/libpsl-native/test/test-createhardlink.cpp @@ -3,7 +3,6 @@ //! @brief Implements test for CreateHardLink() #include -#include #include #include "getlinkcount.h" #include "createhardlink.h" @@ -31,19 +30,19 @@ protected: // First create a temp 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 hard link to file - int ret1 = CreateHardLink(fileHardLink.c_str(), file); - EXPECT_EQ(ret1, 1); - + int ret = CreateHardLink(fileHardLink.c_str(), file); + EXPECT_EQ(ret, 0); + // Create hard link to directory - should fail - int ret2 = CreateHardLink(dirHardLink.c_str(), dir); - EXPECT_EQ(ret2, 0); + ret = CreateHardLink(dirHardLink.c_str(), dir); + EXPECT_EQ(ret, -1); } ~CreateHardLinkTest() @@ -51,34 +50,27 @@ protected: int ret; ret = unlink(fileHardLink.c_str()); - EXPECT_EQ(0, ret); + EXPECT_EQ(0, ret); ret = unlink(file); - EXPECT_EQ(0, ret); + EXPECT_EQ(0, ret); - ret = rmdir(dir); - EXPECT_EQ(0, ret); + ret = rmdir(dir); + EXPECT_EQ(0, ret); } }; -TEST_F(CreateHardLinkTest, FilePathNameIsNull) -{ - int retVal = CreateHardLink(NULL, NULL); - EXPECT_EQ(retVal, 0); - EXPECT_EQ(ERROR_INVALID_PARAMETER, errno); -} - TEST_F(CreateHardLinkTest, FilePathNameDoesNotExist) { std::string invalidFile = "/tmp/symlinktest_invalidFile"; std::string invalidLink = "/tmp/symlinktest_invalidLink"; - // make sure neither exists + // make sure neither exists unlink(invalidFile.c_str()); unlink(invalidLink.c_str()); - int retVal = CreateHardLink(invalidLink.c_str(), invalidFile.c_str()); - EXPECT_EQ(retVal, 0); + int ret = CreateHardLink(invalidLink.c_str(), invalidFile.c_str()); + EXPECT_EQ(-1, ret); } TEST_F(CreateHardLinkTest, VerifyLinkCount) @@ -88,4 +80,3 @@ TEST_F(CreateHardLinkTest, VerifyLinkCount) EXPECT_EQ(1, retVal); EXPECT_EQ(2, count); } - From 1d240ef3e472f05eff42d41b2b8134d9dea1d6d9 Mon Sep 17 00:00:00 2001 From: Andrew Schwartzmeyer Date: Wed, 5 Oct 2016 14:09:35 -0700 Subject: [PATCH 10/20] Remove GetLStat --- src/libpsl-native/src/CMakeLists.txt | 1 - src/libpsl-native/src/getlstat.cpp | 96 ----------------------- src/libpsl-native/src/getlstat.h | 11 --- src/libpsl-native/src/isfile.cpp | 16 +--- src/libpsl-native/src/issymlink.cpp | 28 +------ src/libpsl-native/test/test-isfile.cpp | 8 +- src/libpsl-native/test/test-issymlink.cpp | 6 -- 7 files changed, 7 insertions(+), 159 deletions(-) delete mode 100644 src/libpsl-native/src/getlstat.cpp delete 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 1552ce3eec..41a2268119 100644 --- a/src/libpsl-native/src/CMakeLists.txt +++ b/src/libpsl-native/src/CMakeLists.txt @@ -1,6 +1,5 @@ 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 deleted file mode 100644 index b8ba8a00c2..0000000000 --- a/src/libpsl-native/src/getlstat.cpp +++ /dev/null @@ -1,96 +0,0 @@ -//! @file getlstat.cpp -//! @author Andrew Schwartzmeyer -//! @brief returns the lstat of a file - -#include "getlstat.h" - -#include -#include -#include -#include -#include -#include - -//! @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 deleted file mode 100644 index 6cb4d47198..0000000000 --- a/src/libpsl-native/src/getlstat.h +++ /dev/null @@ -1,11 +0,0 @@ -#pragma once - -#include "pal.h" - -#include - -PAL_BEGIN_EXTERNC - -int32_t GetLStat(const char* path, struct stat* buf); - -PAL_END_EXTERNC diff --git a/src/libpsl-native/src/isfile.cpp b/src/libpsl-native/src/isfile.cpp index e348b105ee..0c3aecf46a 100644 --- a/src/libpsl-native/src/isfile.cpp +++ b/src/libpsl-native/src/isfile.cpp @@ -2,10 +2,9 @@ //! @author Andrew Schwartzmeyer //! @brief returns if the path exists -#include "getlstat.h" #include "isfile.h" -#include +#include #include #include #include @@ -24,21 +23,12 @@ //! 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; - } + assert(path); struct stat buf; - return GetLStat(path, &buf) == 0; + return lstat(path, &buf) == 0; } diff --git a/src/libpsl-native/src/issymlink.cpp b/src/libpsl-native/src/issymlink.cpp index 00a73f1ef2..cc6c126ea8 100644 --- a/src/libpsl-native/src/issymlink.cpp +++ b/src/libpsl-native/src/issymlink.cpp @@ -2,10 +2,9 @@ //! @author George FLeming //! @brief returns whether a path is a symbolic link -#include "getlstat.h" #include "issymlink.h" -#include +#include #include #include #include @@ -22,36 +21,15 @@ //! char* is marshaled as an LPStr, which on Linux is UTF-8. //! @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_FILE_NOT_FOUND: the system cannot find the file specified -//! - ERROR_INVALID_ADDRESS: attempt to access invalid address -//! - ERROR_STOPPED_ON_SYMLINK: the operation stopped after reaching a symbolic link -//! - ERROR_GEN_FAILURE: device attached to the system is not functioning -//! - ERROR_NO_SUCH_USER: there was no corresponding entry in the utmp-file -//! - ERROR_INVALID_NAME: filename, directory name, or volume label syntax is incorrect -//! - ERROR_BUFFER_OVERFLOW: file name is too long -//! - ERROR_INVALID_FUNCTION: incorrect function -//! - ERROR_BAD_PATH_NAME: pathname is too long, or contains invalid characters -//! //! @retval true if path is a symbolic link, false otherwise //! bool IsSymLink(const char* path) { - errno = 0; - - // Check parameters - if (!path) - { - errno = ERROR_INVALID_PARAMETER; - return false; - } + assert(path); struct stat buf; - int32_t ret = GetLStat(path, &buf); + int32_t ret = lstat(path, &buf); if (ret != 0) { return false; diff --git a/src/libpsl-native/test/test-isfile.cpp b/src/libpsl-native/test/test-isfile.cpp index 09d72f5bfa..3c87c09507 100644 --- a/src/libpsl-native/test/test-isfile.cpp +++ b/src/libpsl-native/test/test-isfile.cpp @@ -20,11 +20,5 @@ TEST(IsFileTest, BinLsIsFile) 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); + EXPECT_EQ(errno, ENOENT); } diff --git a/src/libpsl-native/test/test-issymlink.cpp b/src/libpsl-native/test/test-issymlink.cpp index 463c124c10..68055227a7 100644 --- a/src/libpsl-native/test/test-issymlink.cpp +++ b/src/libpsl-native/test/test-issymlink.cpp @@ -55,12 +55,6 @@ protected: } }; -TEST_F(isSymLinkTest, FilePathNameIsNull) -{ - EXPECT_FALSE(IsSymLink(NULL)); - EXPECT_EQ(ERROR_INVALID_PARAMETER, errno); -} - TEST_F(isSymLinkTest, FilePathNameDoesNotExist) { std::string invalidFile = "/tmp/symlinktest_invalidFile"; From 14e2389e71a9503cad0184b88515fa4d62290004 Mon Sep 17 00:00:00 2001 From: Andrew Schwartzmeyer Date: Wed, 5 Oct 2016 14:09:49 -0700 Subject: [PATCH 11/20] Clean up GetComputerName --- src/libpsl-native/src/getcomputername.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/libpsl-native/src/getcomputername.cpp b/src/libpsl-native/src/getcomputername.cpp index 606bdc60e1..b1fda7d9f0 100644 --- a/src/libpsl-native/src/getcomputername.cpp +++ b/src/libpsl-native/src/getcomputername.cpp @@ -19,9 +19,9 @@ char* GetComputerName() // Get computername from system, note that gethostname(2) gets the // nodename from uname std::string computername(_POSIX_HOST_NAME_MAX, 0); - int err = gethostname(&computername[0], computername.length()); + int32_t ret = gethostname(&computername[0], computername.length()); // Map errno to Win32 Error Codes - if (err != 0) + if (ret != 0) { return NULL; } From e343e8ec60791cd41349cd8de3511ba9abaef585 Mon Sep 17 00:00:00 2001 From: Andrew Schwartzmeyer Date: Wed, 5 Oct 2016 14:09:59 -0700 Subject: [PATCH 12/20] Clean up GetUserFromPid --- src/libpsl-native/src/getpwuid.cpp | 20 ++------------------ src/libpsl-native/src/getuserfrompid.cpp | 1 - 2 files changed, 2 insertions(+), 19 deletions(-) diff --git a/src/libpsl-native/src/getpwuid.cpp b/src/libpsl-native/src/getpwuid.cpp index d28a28de27..f147d7d801 100644 --- a/src/libpsl-native/src/getpwuid.cpp +++ b/src/libpsl-native/src/getpwuid.cpp @@ -20,11 +20,6 @@ //! The user identifier to lookup. //! @endparblock //! -//! @exception errno Passes these errors via errno to GetLastError: -//! - ERROR_NO_SUCH_USER: user lookup unsuccessful -//! - ERROR_OUTOFMEMORY insufficient kernel memory -//! - ERROR_GEN_FAILURE: anything else -//! //! @retval username as UTF-8 string, or NULL if unsuccessful //! char* GetPwUid(uid_t uid) @@ -43,27 +38,16 @@ char* GetPwUid(uid_t uid) allocate: buf = (char*)calloc(buflen, sizeof(char)); + errno = 0; ret = getpwuid_r(uid, &pwd, buf, buflen, &result); if (ret != 0) { - switch(errno) + if (errno == ERANGE) { - case ERANGE: free(buf); buflen *= 2; goto allocate; - case ENOENT: - case ESRCH: - case EBADF: - case EPERM: - errno = ERROR_NO_SUCH_USER; - break; - case ENOMEM: - errno = ERROR_OUTOFMEMORY; - break; - default: - errno = ERROR_GEN_FAILURE; } return NULL; } diff --git a/src/libpsl-native/src/getuserfrompid.cpp b/src/libpsl-native/src/getuserfrompid.cpp index 2211becf87..89b49ea5db 100644 --- a/src/libpsl-native/src/getuserfrompid.cpp +++ b/src/libpsl-native/src/getuserfrompid.cpp @@ -33,7 +33,6 @@ char* GetUserFromPid(pid_t pid) int ret = sysctl(name, namelen, &oldp, &oldlenp, NULL, 0); if (ret != 0 || oldlenp == 0) { - errno = ERROR_GEN_FAILURE; return NULL; } From 2a6b84ed1b373fa990b38dce3ab5eee574e485c6 Mon Sep 17 00:00:00 2001 From: Andrew Schwartzmeyer Date: Wed, 5 Oct 2016 16:34:48 -0700 Subject: [PATCH 13/20] Clean up IsHardLink --- .../CoreCLR/CorePsPlatform.cs | 2 +- .../namespaces/FileSystemProvider.cs | 18 ++--- src/libpsl-native/src/getlinkcount.cpp | 67 ++----------------- .../test/test-createhardlink.cpp | 4 +- src/libpsl-native/test/test-getlinkcount.cpp | 29 +++----- 5 files changed, 30 insertions(+), 90 deletions(-) diff --git a/src/System.Management.Automation/CoreCLR/CorePsPlatform.cs b/src/System.Management.Automation/CoreCLR/CorePsPlatform.cs index 16e5ea5d95..9b6672461f 100644 --- a/src/System.Management.Automation/CoreCLR/CorePsPlatform.cs +++ b/src/System.Management.Automation/CoreCLR/CorePsPlatform.cs @@ -516,7 +516,7 @@ namespace System.Management.Automation int count; string filePath = fs.FullName; int ret = NativeMethods.GetLinkCount(filePath, out count); - if (ret == 1) + if (ret == 0) { return count > 1; } diff --git a/src/System.Management.Automation/namespaces/FileSystemProvider.cs b/src/System.Management.Automation/namespaces/FileSystemProvider.cs index 8111a1a048..2b8647477c 100644 --- a/src/System.Management.Automation/namespaces/FileSystemProvider.cs +++ b/src/System.Management.Automation/namespaces/FileSystemProvider.cs @@ -8179,10 +8179,11 @@ namespace Microsoft.PowerShell.Commands internal static bool IsHardLink(FileSystemInfo fileInfo) { - if (Platform.IsWindows) - return WinIsHardLink(fileInfo); - else - return Platform.NonWindowsIsHardLink(fileInfo); +#if UNIX + return Platform.NonWindowsIsHardLink(fileInfo); +#else + return WinIsHardLink(fileInfo); +#endif } internal static bool IsReparsePoint(FileSystemInfo fileInfo) @@ -8238,10 +8239,11 @@ namespace Microsoft.PowerShell.Commands internal static bool IsHardLink(ref IntPtr handle) { - if (Platform.IsWindows) - return WinIsHardLink(ref handle); - else - return Platform.NonWindowsIsHardLink(ref handle); +#if UNIX + return Platform.NonWindowsIsHardLink(ref handle); +#else + return WinIsHardLink(ref handle); +#endif } [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Reliability", "CA2001:AvoidCallingProblematicMethods")] diff --git a/src/libpsl-native/src/getlinkcount.cpp b/src/libpsl-native/src/getlinkcount.cpp index 552b46ce50..8a04dec009 100644 --- a/src/libpsl-native/src/getlinkcount.cpp +++ b/src/libpsl-native/src/getlinkcount.cpp @@ -4,6 +4,7 @@ #include "getlinkcount.h" +#include #include #include #include @@ -28,21 +29,7 @@ //! This function returns the number of hard links associated with this file //! @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_FILE_NOT_FOUND: the system cannot find the file specified -//! - ERROR_INVALID_ADDRESS: attempt to access invalid address -//! - ERROR_STOPPED_ON_SYMLINK: the operation stopped after reaching a symbolic link -//! - ERROR_GEN_FAILURE: device attached to the system is not functioning -//! - ERROR_NO_SUCH_USER: there was no corresponding entry in the utmp-file -//! - ERROR_INVALID_NAME: filename, directory name, or volume label syntax is incorrect -//! - ERROR_BUFFER_OVERFLOW: file name is too long -//! - ERROR_INVALID_FUNCTION: incorrect function -//! - ERROR_BAD_PATH_NAME: pathname is too long, or contains invalid characters -//! -//! @retval 1 If the function succeeds, and the variable pointed to by buffer contains +//! @retval 1 If the function succeeds, and the variable pointed to by buffer contains //! information about the files //! @retval 0 If the function fails, the return value is zero. To get //! extended error information, call GetLastError. @@ -50,56 +37,14 @@ int32_t GetLinkCount(const char* fileName, int32_t *count) { + assert(fileName); + assert(count); errno = 0; - // Check parameters - if (!fileName) - { - errno = ERROR_INVALID_PARAMETER; - return 0; - } - struct stat statBuf; - int returnCode = lstat(fileName, &statBuf); - - if (returnCode != 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 0; - } + int32_t ret = lstat(fileName, &statBuf); *count = statBuf.st_nlink; - return 1; + return ret; } diff --git a/src/libpsl-native/test/test-createhardlink.cpp b/src/libpsl-native/test/test-createhardlink.cpp index 1c18de66b0..bb9a3fbe52 100644 --- a/src/libpsl-native/test/test-createhardlink.cpp +++ b/src/libpsl-native/test/test-createhardlink.cpp @@ -76,7 +76,7 @@ TEST_F(CreateHardLinkTest, FilePathNameDoesNotExist) TEST_F(CreateHardLinkTest, VerifyLinkCount) { int count = 0; - int retVal = GetLinkCount(fileHardLink.c_str(), &count); - EXPECT_EQ(1, retVal); + int ret = GetLinkCount(fileHardLink.c_str(), &count); + EXPECT_EQ(0, ret); EXPECT_EQ(2, count); } diff --git a/src/libpsl-native/test/test-getlinkcount.cpp b/src/libpsl-native/test/test-getlinkcount.cpp index 4d3d103360..d005e31488 100644 --- a/src/libpsl-native/test/test-getlinkcount.cpp +++ b/src/libpsl-native/test/test-getlinkcount.cpp @@ -29,7 +29,7 @@ protected: int fd = mkstemp(fileTemplateBuf); EXPECT_TRUE(fd != -1); - file = fileTemplateBuf; + file = fileTemplateBuf; } void createFileForTesting(const std::string &theFile) @@ -43,39 +43,32 @@ protected: std::string createHardLink(const std::string &origFile) { std::string newFile = origFile + "_link"; - int ret = link(origFile.c_str(), newFile.c_str()); + int ret = link(origFile.c_str(), newFile.c_str()); EXPECT_EQ(0, ret); - return newFile; + return newFile; } void removeFile(const std::string &fileName) { int ret = unlink(fileName.c_str()); - EXPECT_EQ(0, ret); + EXPECT_EQ(0, ret); } }; -TEST_F(getLinkCountTest, FilePathNameIsNull) -{ - int32_t retVal = GetLinkCount(NULL, &count ); - ASSERT_FALSE(retVal); - EXPECT_EQ(ERROR_INVALID_PARAMETER, errno); -} - TEST_F(getLinkCountTest, FilePathNameDoesNotExist) { std::string invalidFile = "/tmp/createFile"; - int32_t retVal = GetLinkCount(invalidFile.c_str(), &count); - ASSERT_FALSE(retVal); - EXPECT_EQ(ERROR_FILE_NOT_FOUND, errno); + int32_t ret = GetLinkCount(invalidFile.c_str(), &count); + ASSERT_EQ(-1, ret); + EXPECT_EQ(ENOENT, errno); } TEST_F(getLinkCountTest, LinkCountOfSinglyLinkedFile) { createFileForTesting(file); - int32_t retVal = GetLinkCount(file, &count); - ASSERT_TRUE(retVal); + int32_t ret = GetLinkCount(file, &count); + ASSERT_EQ(0, ret); EXPECT_EQ(1, count); removeFile(file); @@ -85,8 +78,8 @@ TEST_F(getLinkCountTest, LinkCountOfMultiplyLinkedFile) { createFileForTesting(file); std::string newFile = createHardLink(file); - int32_t retVal = GetLinkCount(file, &count); - ASSERT_TRUE(retVal); + int32_t ret = GetLinkCount(file, &count); + ASSERT_EQ(0, ret); EXPECT_EQ(2, count); removeFile(file); From 8b3e8be1bcc7de3d2c3d10e8baf209d0f079c18c Mon Sep 17 00:00:00 2001 From: Andrew Schwartzmeyer Date: Wed, 5 Oct 2016 16:35:44 -0700 Subject: [PATCH 14/20] Clean up IsDirectory --- src/libpsl-native/src/isdirectory.cpp | 13 ++----------- src/libpsl-native/test/test-isdirectory.cpp | 8 +------- 2 files changed, 3 insertions(+), 18 deletions(-) diff --git a/src/libpsl-native/src/isdirectory.cpp b/src/libpsl-native/src/isdirectory.cpp index 5e61311626..1cb75a72a4 100644 --- a/src/libpsl-native/src/isdirectory.cpp +++ b/src/libpsl-native/src/isdirectory.cpp @@ -7,7 +7,7 @@ #include "getfileowner.h" #include "isdirectory.h" -#include +#include #include #include #include @@ -25,20 +25,11 @@ //! 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) { - errno = 0; - - if (!path) - { - errno = ERROR_INVALID_PARAMETER; - return false; - } + assert(path); struct stat buf; int32_t ret = GetStat(path, &buf); diff --git a/src/libpsl-native/test/test-isdirectory.cpp b/src/libpsl-native/test/test-isdirectory.cpp index 27c840cba7..24ab647113 100644 --- a/src/libpsl-native/test/test-isdirectory.cpp +++ b/src/libpsl-native/test/test-isdirectory.cpp @@ -21,11 +21,5 @@ TEST(IsDirectoryTest, BinLsIsNotDirectory) 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); + EXPECT_EQ(ENOENT, errno); } From 4038cd61f2697b59805fed08b72aa37bf95e2178 Mon Sep 17 00:00:00 2001 From: Andrew Schwartzmeyer Date: Wed, 5 Oct 2016 16:35:53 -0700 Subject: [PATCH 15/20] Clean up IsExecutable --- src/libpsl-native/src/isexecutable.cpp | 14 ++------------ src/libpsl-native/test/test-isexecutable.cpp | 8 +------- 2 files changed, 3 insertions(+), 19 deletions(-) diff --git a/src/libpsl-native/src/isexecutable.cpp b/src/libpsl-native/src/isexecutable.cpp index c702ccf3ba..81e00fba23 100644 --- a/src/libpsl-native/src/isexecutable.cpp +++ b/src/libpsl-native/src/isexecutable.cpp @@ -4,7 +4,7 @@ #include "isexecutable.h" -#include +#include #include #include @@ -19,22 +19,12 @@ //! char* is marshaled as an LPStr, which on Linux is UTF-8. //! @endparblock //! -//! @exception errno Passes these errors via errno to GetLastError: -//! - ERROR_INVALID_ADDRESS: attempt to access invalid address -//! //! @retval true if path is an executable, false otherwise //! bool IsExecutable(const char* path) { - errno = 0; - - // Check parameters - if (!path) - { - errno = ERROR_INVALID_PARAMETER; - return false; - } + assert(path); return access(path, X_OK) != -1; } diff --git a/src/libpsl-native/test/test-isexecutable.cpp b/src/libpsl-native/test/test-isexecutable.cpp index d97d7d3159..0ccfd40317 100644 --- a/src/libpsl-native/test/test-isexecutable.cpp +++ b/src/libpsl-native/test/test-isexecutable.cpp @@ -47,17 +47,11 @@ protected: } }; -TEST_F(IsExecutableTest, FilePathNameIsNull) -{ - EXPECT_FALSE(IsExecutable(NULL)); - EXPECT_EQ(ERROR_INVALID_PARAMETER, errno); -} - TEST_F(IsExecutableTest, FilePathNameDoesNotExist) { std::string invalidFile = "/tmp/isexecutabletest_invalidFile"; EXPECT_FALSE(IsExecutable(invalidFile.c_str())); - EXPECT_EQ(ERROR_FILE_NOT_FOUND, errno); + EXPECT_EQ(ENOENT, errno); } TEST_F(IsExecutableTest, NormalFileIsNotIsexecutable) From 011d947fd539b05859dbbcf3be90669b8ebf0e49 Mon Sep 17 00:00:00 2001 From: Andrew Schwartzmeyer Date: Wed, 5 Oct 2016 16:41:59 -0700 Subject: [PATCH 16/20] Clean up GetFileOwner --- src/libpsl-native/src/getfileowner.cpp | 14 +---- src/libpsl-native/src/getstat.cpp | 60 +------------------- src/libpsl-native/test/test-getfileowner.cpp | 8 +-- 3 files changed, 7 insertions(+), 75 deletions(-) diff --git a/src/libpsl-native/src/getfileowner.cpp b/src/libpsl-native/src/getfileowner.cpp index de3deaee79..56de5d3f05 100644 --- a/src/libpsl-native/src/getfileowner.cpp +++ b/src/libpsl-native/src/getfileowner.cpp @@ -6,6 +6,7 @@ #include "getpwuid.h" #include "getfileowner.h" +#include #include #include #include @@ -24,24 +25,15 @@ //! 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 file owner, or NULL if unsuccessful //! char* GetFileOwner(const char* fileName) { - int32_t ret = 0; + assert(fileName); errno = 0; - if (!fileName) - { - errno = ERROR_INVALID_PARAMETER; - return NULL; - } - struct stat buf; - ret = GetStat(fileName, &buf); + int32_t ret = GetStat(fileName, &buf); if (ret != 0) { return NULL; diff --git a/src/libpsl-native/src/getstat.cpp b/src/libpsl-native/src/getstat.cpp index 05e9ea479e..56d3c6b1aa 100644 --- a/src/libpsl-native/src/getstat.cpp +++ b/src/libpsl-native/src/getstat.cpp @@ -5,6 +5,7 @@ #include "getstat.h" #include +#include #include #include #include @@ -28,69 +29,14 @@ //! A pointer to the buffer in which to place the stat 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 GetStat(const char* path, struct stat* buf) { + assert(path); errno = 0; - if (!path) - { - errno = ERROR_INVALID_PARAMETER; - return -1; - } - - int32_t ret = stat(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; + return stat(path, buf); } diff --git a/src/libpsl-native/test/test-getfileowner.cpp b/src/libpsl-native/test/test-getfileowner.cpp index 275c63ed11..c13675467f 100644 --- a/src/libpsl-native/test/test-getfileowner.cpp +++ b/src/libpsl-native/test/test-getfileowner.cpp @@ -15,11 +15,5 @@ TEST(GetFileOwnerTest, CanGetOwnerOfRoot) TEST(GetFileOwnerTest, CannotGetOwnerOfFakeFile) { EXPECT_STREQ(GetFileOwner("SomeMadeUpFileNameThatDoesNotExist"), NULL); - EXPECT_EQ(errno, ERROR_FILE_NOT_FOUND); -} - -TEST(GetFileOwnerTest, ReturnsNullForNullInput) -{ - EXPECT_STREQ(GetFileOwner(NULL), NULL); - EXPECT_EQ(errno, ERROR_INVALID_PARAMETER); + EXPECT_EQ(ENOENT, errno); } From cdcd2c25c87e57e1b7ddbd925677d3768753e3da Mon Sep 17 00:00:00 2001 From: Andrew Schwartzmeyer Date: Wed, 5 Oct 2016 16:45:53 -0700 Subject: [PATCH 17/20] Remove Windows ERROR codes from pal.h --- src/libpsl-native/src/pal.h | 21 --------------------- 1 file changed, 21 deletions(-) diff --git a/src/libpsl-native/src/pal.h b/src/libpsl-native/src/pal.h index 39fb6db82c..0770003569 100644 --- a/src/libpsl-native/src/pal.h +++ b/src/libpsl-native/src/pal.h @@ -5,27 +5,6 @@ #include #include -#define ERROR_INVALID_PARAMETER 87 -#define ERROR_OUTOFMEMORY 14 -#define ERROR_BAD_ENVIRONMENT 0x0000000A -#define ERROR_TOO_MANY_OPEN_FILES 0x00000004 -#define ERROR_INSUFFICIENT_BUFFER 0x0000007A -#define ERROR_NO_ASSOCIATION 0x00000483 -#define ERROR_NO_SUCH_USER 0x00000525 -#define ERROR_INVALID_FUNCTION 0x00000001 -#define ERROR_INVALID_ADDRESS 0x000001e7 -#define ERROR_GEN_FAILURE 0x0000001F -#define ERROR_ACCESS_DENIED 0x00000005 -#define ERROR_INVALID_NAME 0x0000007B -#define ERROR_STOPPED_ON_SYMLINK 0x000002A9 -#define ERROR_BUFFER_OVERFLOW 0x0000006F -#define ERROR_FILE_NOT_FOUND 0x00000002 -#define ERROR_BAD_PATH_NAME 0x000000A1 -#define ERROR_BAD_NET_NAME 0x00000043 -#define ERROR_DISK_FULL 0x00000070 -#define ERROR_FILE_EXISTS 0x00000050 -#define ERROR_TOO_MANY_LINKS 0x00000476 - /* **============================================================================== ** From 24d0ce36e668ce06936e8731aae26f223554917c Mon Sep 17 00:00:00 2001 From: Andrew Schwartzmeyer Date: Fri, 7 Oct 2016 16:33:16 -0700 Subject: [PATCH 18/20] Fix SetDate And use a bunch of unsafe code because of concerns about stack size. --- .../CoreCLR/CorePsPlatform.cs | 69 +++++++++---------- src/libpsl-native/src/setdate.cpp | 19 +---- src/libpsl-native/src/setdate.h | 17 +---- .../Set-Date.Tests.ps1 | 5 +- 4 files changed, 43 insertions(+), 67 deletions(-) diff --git a/src/System.Management.Automation/CoreCLR/CorePsPlatform.cs b/src/System.Management.Automation/CoreCLR/CorePsPlatform.cs index 9b6672461f..ee75313abb 100644 --- a/src/System.Management.Automation/CoreCLR/CorePsPlatform.cs +++ b/src/System.Management.Automation/CoreCLR/CorePsPlatform.cs @@ -403,10 +403,10 @@ namespace System.Management.Automation return Unix.NativeMethods.CreateHardLink(path, strTargetPath) == 0; } - internal static bool NonWindowsSetDate(DateTime dateToUse) + internal static unsafe bool NonWindowsSetDate(DateTime dateToUse) { - Unix.SetDateInfoInternal date = new Unix.SetDateInfoInternal(dateToUse); - return Unix.NativeMethods.SetDate(date) == 0; + Unix.NativeMethods.UnixTm tm = Unix.NativeMethods.DateTimeToUnixTm(dateToUse); + return Unix.NativeMethods.SetDate(&tm) == 0; } internal static string NonWindowsGetDomainName() @@ -526,37 +526,6 @@ namespace System.Management.Automation } } - [StructLayout(LayoutKind.Sequential)] - internal class SetDateInfoInternal - { - public int Year; - public int Month; - public int Day; - public int Hour; - public int Minute; - public int Second; - public int Millisecond; - public int DST; - - public SetDateInfoInternal(DateTime d) - { - Year = d.Year; - Month = d.Month; - Day = d.Day; - Hour = d.Hour; - Minute = d.Minute; - Second = d.Second; - Millisecond = d.Millisecond; - DST = d.IsDaylightSavingTime() ? 1 : 0; - } - - public override string ToString() - { - string ret = String.Format("Year = {0}; Month = {1}; Day = {2}; Hour = {3}; Minute = {4}; Second = {5}; Millisec = {6}; DST = {7}", Year, Month, Day, Hour, Minute, Second, Millisecond, DST); - return ret; - } - } - internal static class NativeMethods { private const string psLib = "libpsl-native"; @@ -587,8 +556,38 @@ namespace System.Management.Automation [return: MarshalAs(UnmanagedType.LPStr)] internal static extern string GetFullyQualifiedName(); + // This is a struct tm from + [StructLayout(LayoutKind.Sequential)] + internal unsafe struct UnixTm + { + public int tm_sec; /* Seconds (0-60) */ + public int tm_min; /* Minutes (0-59) */ + public int tm_hour; /* Hours (0-23) */ + public int tm_mday; /* Day of the month (1-31) */ + public int tm_mon; /* Month (0-11) */ + public int tm_year; /* Year - 1900 */ + public int tm_wday; /* Day of the week (0-6, Sunday = 0) */ + public int tm_yday; /* Day in the year (0-365, 1 Jan = 0) */ + public int tm_isdst; /* Daylight saving time */ + } + + internal static UnixTm DateTimeToUnixTm(DateTime date) + { + UnixTm tm; + tm.tm_sec = date.Second; + tm.tm_min = date.Minute; + tm.tm_hour = date.Hour; + tm.tm_mday = date.Day; + tm.tm_mon = date.Month - 1; // needs to be 0 indexed + tm.tm_year = date.Year - 1900; // years since 1900 + tm.tm_wday = 0; // this is ignored by mktime + tm.tm_yday = 0; // this is also ignored + tm.tm_isdst = date.IsDaylightSavingTime() ? 1 : 0; + return tm; + } + [DllImport(psLib, CharSet = CharSet.Ansi, SetLastError = true)] - internal static extern int SetDate(SetDateInfoInternal info); + internal static extern unsafe int SetDate(UnixTm* tm); [DllImport(psLib, CharSet = CharSet.Ansi, SetLastError = true)] internal static extern int CreateSymLink([MarshalAs(UnmanagedType.LPStr)]string filePath, diff --git a/src/libpsl-native/src/setdate.cpp b/src/libpsl-native/src/setdate.cpp index 3f350101ff..916795cb4d 100644 --- a/src/libpsl-native/src/setdate.cpp +++ b/src/libpsl-native/src/setdate.cpp @@ -17,34 +17,19 @@ //! //! SetDate //! -//! @param[in] info -//! @parblock -//! A struct that contains program to execute and its parameters -//! //! @retval 0 successfully set date //! @retval -1 if failure occurred. //! -int32_t SetDate(const SetDateInfo info) +int32_t SetDate(struct tm* time) { errno = 0; // Select locale from environment setlocale(LC_ALL, ""); - // Check that locale is UTF-8 - assert(nl_langinfo(CODESET) == std::string("UTF-8")); - struct tm bdTime; struct timeval tv; - bdTime.tm_year = info.Year - 1900; - bdTime.tm_mon = info.Month - 1; // This is zero-based - bdTime.tm_mday = info.Day; - bdTime.tm_hour = info.Hour; - bdTime.tm_min = info.Minute; - bdTime.tm_sec = info.Second; - bdTime.tm_isdst = info.DST; - - time_t newTime = mktime(&bdTime); + time_t newTime = mktime(time); if (newTime == -1) { return -1; diff --git a/src/libpsl-native/src/setdate.h b/src/libpsl-native/src/setdate.h index bf2bccaed1..ad0389a6a6 100644 --- a/src/libpsl-native/src/setdate.h +++ b/src/libpsl-native/src/setdate.h @@ -2,21 +2,10 @@ #include "pal.h" +#include + PAL_BEGIN_EXTERNC -typedef struct setDateInfo -{ - // the order of members does matter here - int32_t Year; - int32_t Month; - int32_t Day; - int32_t Hour; - int32_t Minute; - int32_t Second; - int32_t Millisecond; - int32_t DST; -} SetDateInfo; - -int32_t SetDate(const SetDateInfo info); +int32_t SetDate(struct tm* time); PAL_END_EXTERNC diff --git a/test/powershell/Modules/Microsoft.PowerShell.Utility/Set-Date.Tests.ps1 b/test/powershell/Modules/Microsoft.PowerShell.Utility/Set-Date.Tests.ps1 index d523146dda..ce723a1ba6 100644 --- a/test/powershell/Modules/Microsoft.PowerShell.Utility/Set-Date.Tests.ps1 +++ b/test/powershell/Modules/Microsoft.PowerShell.Utility/Set-Date.Tests.ps1 @@ -6,10 +6,13 @@ Describe "Set-Date" -Tag "CI" { Import-Module (join-path $psscriptroot "../../Common/Test.Helpers.psm1") $IsElevated = Test-IsElevated } + It "Set-Date should be able to set the date in an elevated context" -Skip:(! $IsElevated) { { get-date | set-date } | Should not throw } + It "Set-Date should produce an error in a non-elevated context" -Skip:($IsElevated) { - { get-date |set-date} | should throw + { get-date | set-date} | should throw + $Error[0].FullyQualifiedErrorId | should be "System.ComponentModel.Win32Exception,Microsoft.PowerShell.Commands.SetDateCommand" } } From e630c6f79c2b67a69ef69367a1545ba6c6f679c2 Mon Sep 17 00:00:00 2001 From: Andrew Schwartzmeyer Date: Mon, 10 Oct 2016 14:06:06 -0700 Subject: [PATCH 19/20] Fix GetCurrentThreadId --- .../CoreCLR/CorePsPlatform.cs | 6 ++++-- .../utils/PsUtils.cs | 16 ++++------------ src/libpsl-native/src/CMakeLists.txt | 1 + src/libpsl-native/src/getcurrentthreadid.cpp | 11 +++++++++-- src/libpsl-native/src/getcurrentthreadid.h | 1 - .../Write-Stream.Tests.ps1 | 1 + 6 files changed, 19 insertions(+), 17 deletions(-) diff --git a/src/System.Management.Automation/CoreCLR/CorePsPlatform.cs b/src/System.Management.Automation/CoreCLR/CorePsPlatform.cs index ee75313abb..99019fa3f6 100644 --- a/src/System.Management.Automation/CoreCLR/CorePsPlatform.cs +++ b/src/System.Management.Automation/CoreCLR/CorePsPlatform.cs @@ -448,8 +448,7 @@ namespace System.Management.Automation internal static uint NonWindowsGetThreadId() { - // TODO:PSL clean this up - return 0; + return Unix.NativeMethods.GetCurrentThreadId(); } // Unix specific implementations of required functionality @@ -552,6 +551,9 @@ namespace System.Management.Automation [return: MarshalAs(UnmanagedType.I1)] internal static extern bool IsExecutable([MarshalAs(UnmanagedType.LPStr)]string filePath); + [DllImport(psLib, CharSet = CharSet.Ansi)] + internal static extern uint GetCurrentThreadId(); + [DllImport(psLib, CharSet = CharSet.Ansi, SetLastError = true)] [return: MarshalAs(UnmanagedType.LPStr)] internal static extern string GetFullyQualifiedName(); diff --git a/src/System.Management.Automation/utils/PsUtils.cs b/src/System.Management.Automation/utils/PsUtils.cs index 6ace95e152..33bfeaa722 100644 --- a/src/System.Management.Automation/utils/PsUtils.cs +++ b/src/System.Management.Automation/utils/PsUtils.cs @@ -624,19 +624,11 @@ namespace System.Management.Automation internal static uint GetNativeThreadId() { - if (Platform.IsWindows) - { - return WinGetNativeThreadId(); - } - else - { - return Platform.NonWindowsGetThreadId(); - } - } - - internal static uint WinGetNativeThreadId() - { +#if UNIX + return Platform.NonWindowsGetThreadId(); +#else return NativeMethods.GetCurrentThreadId(); +#endif } private static class NativeMethods diff --git a/src/libpsl-native/src/CMakeLists.txt b/src/libpsl-native/src/CMakeLists.txt index 41a2268119..9a3be5701d 100644 --- a/src/libpsl-native/src/CMakeLists.txt +++ b/src/libpsl-native/src/CMakeLists.txt @@ -3,6 +3,7 @@ add_library(psl-native SHARED getpwuid.cpp getuserfrompid.cpp getfileowner.cpp + getcurrentthreadid.cpp getcurrentprocessorid.cpp getusername.cpp getcomputername.cpp diff --git a/src/libpsl-native/src/getcurrentthreadid.cpp b/src/libpsl-native/src/getcurrentthreadid.cpp index 7422d57af2..e836685ccd 100644 --- a/src/libpsl-native/src/getcurrentthreadid.cpp +++ b/src/libpsl-native/src/getcurrentthreadid.cpp @@ -1,9 +1,16 @@ #include "getcurrentthreadid.h" #include -#include +#include +#include pid_t GetCurrentThreadId() { - return pthread_self(); + pid_t tid = 0; +#if defined(__linux__) + tid = syscall(SYS_gettid); +#elif defined(__APPLE__) && defined(__MACH__) + tid = syscall(SYS_thread_selfid); +#endif + return tid; } diff --git a/src/libpsl-native/src/getcurrentthreadid.h b/src/libpsl-native/src/getcurrentthreadid.h index cc388ec411..9a6c94e9e3 100644 --- a/src/libpsl-native/src/getcurrentthreadid.h +++ b/src/libpsl-native/src/getcurrentthreadid.h @@ -9,4 +9,3 @@ PAL_BEGIN_EXTERNC pid_t GetCurrentThreadId(); PAL_END_EXTERNC - diff --git a/test/powershell/Modules/Microsoft.PowerShell.Utility/Write-Stream.Tests.ps1 b/test/powershell/Modules/Microsoft.PowerShell.Utility/Write-Stream.Tests.ps1 index 4107fda298..e47bc19a3b 100644 --- a/test/powershell/Modules/Microsoft.PowerShell.Utility/Write-Stream.Tests.ps1 +++ b/test/powershell/Modules/Microsoft.PowerShell.Utility/Write-Stream.Tests.ps1 @@ -74,6 +74,7 @@ Describe "Stream writer tests" -Tags "CI" { # redirect the streams is sufficient $result = Write-Information "Test Message" *>&1 $result.GetType().Fullname | Should be "System.Management.Automation.InformationRecord" + $result.NativeThreadId | Should Not Be 0 "$result" | Should be "Test Message" } } From 07a1841eb6c17c0771ba6accc98193dd3bc3eebf Mon Sep 17 00:00:00 2001 From: Andrew Schwartzmeyer Date: Mon, 10 Oct 2016 14:12:23 -0700 Subject: [PATCH 20/20] Set libpsl-native configuration to release This disables asserts. --- src/libpsl-native/CMakeLists.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/src/libpsl-native/CMakeLists.txt b/src/libpsl-native/CMakeLists.txt index fc26a5b91c..0889042ae1 100644 --- a/src/libpsl-native/CMakeLists.txt +++ b/src/libpsl-native/CMakeLists.txt @@ -2,6 +2,7 @@ cmake_minimum_required(VERSION 2.8.11) project(PSL-NATIVE) # Can't use add_compile_options with 2.8.11 +set(CMAKE_BUILD_TYPE "Release") set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11 -Wall -Werror") set(LIBRARY_OUTPUT_PATH "${PROJECT_SOURCE_DIR}/../powershell-unix")