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