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 29a4f189f5..99019fa3f6 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; @@ -394,18 +395,18 @@ 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) { - return Unix.CreateHardLink(path, strTargetPath); + return Unix.NativeMethods.CreateHardLink(path, strTargetPath) == 0; } - internal static void NonWindowsSetDate(DateTime dateToUse) + internal static unsafe bool NonWindowsSetDate(DateTime dateToUse) { - Unix.SetDateInfoInternal date = new Unix.SetDateInfoInternal(dateToUse); - Unix.SetDate(date); + Unix.NativeMethods.UnixTm tm = Unix.NativeMethods.DateTimeToUnixTm(dateToUse); + return Unix.NativeMethods.SetDate(&tm) == 0; } internal static string NonWindowsGetDomainName() @@ -447,12 +448,24 @@ 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 + // + // 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 { + // 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 { @@ -502,61 +515,13 @@ 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; } else { - int lastError = Marshal.GetLastWin32Error(); - throw new InvalidOperationException("Unix.IsHardLink error: " + lastError); - } - } - - public static void SetDate(SetDateInfoInternal info) - { - int ret = NativeMethods.SetDate(info); - if (ret == -1) - { - int lastError = Marshal.GetLastWin32Error(); - throw new InvalidOperationException("Unix.NonWindowsSetDate error: " + lastError); - } - } - - public static bool CreateHardLink(string path, string strTargetPath) - { - int ret = NativeMethods.CreateHardLink(path, strTargetPath); - return ret == 1 ? true : false; - } - - [StructLayout(LayoutKind.Sequential)] - internal class SetDateInfoInternal - { - public int Year; - public int Month; - public int Day; - public int Hour; - public int Minute; - public int Second; - public int Millisecond; - public int DST; - - public SetDateInfoInternal(DateTime d) - { - Year = d.Year; - Month = d.Month; - Day = d.Day; - Hour = d.Hour; - Minute = d.Minute; - Second = d.Second; - Millisecond = d.Millisecond; - DST = d.IsDaylightSavingTime() ? 1 : 0; - } - - 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; + throw new Win32Exception(Marshal.GetLastWin32Error()); } } @@ -568,6 +533,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(); @@ -583,17 +551,49 @@ 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(); - [DllImport(psLib, CharSet = CharSet.Ansi, SetLastError = true)] - internal static extern int SetDate(SetDateInfoInternal info); + // 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)] - [return: MarshalAs(UnmanagedType.I1)] - internal static extern bool CreateSymLink([MarshalAs(UnmanagedType.LPStr)]string filePath, - [MarshalAs(UnmanagedType.LPStr)]string target); + 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, + [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 3d8452367f..2b8647477c 100644 --- a/src/System.Management.Automation/namespaces/FileSystemProvider.cs +++ b/src/System.Management.Automation/namespaces/FileSystemProvider.cs @@ -2208,34 +2208,33 @@ 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) { - 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) { + // Porting note: The Win32Exception will report the correct error on Linux int errorCode = Marshal.GetLastWin32Error(); 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())); @@ -8028,17 +8027,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(); @@ -8096,7 +8096,7 @@ namespace Microsoft.PowerShell.Commands { InternalSymbolicLinkLinkCodeMethods.FindClose(fileHandle); } -#endif +#endif return links; } @@ -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/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/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") diff --git a/src/libpsl-native/src/CMakeLists.txt b/src/libpsl-native/src/CMakeLists.txt index 5d4c432b40..9a3be5701d 100644 --- a/src/libpsl-native/src/CMakeLists.txt +++ b/src/libpsl-native/src/CMakeLists.txt @@ -1,14 +1,15 @@ add_library(psl-native SHARED getstat.cpp - getlstat.cpp getpwuid.cpp getuserfrompid.cpp getfileowner.cpp + getcurrentthreadid.cpp getcurrentprocessorid.cpp getusername.cpp getcomputername.cpp getlinkcount.cpp getfullyqualifiedname.cpp + geterrorcategory.cpp isfile.cpp isdirectory.cpp issymlink.cpp diff --git a/src/libpsl-native/src/createhardlink.cpp b/src/libpsl-native/src/createhardlink.cpp index 29727c2cf6..d3bd84685e 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 +#include "createhardlink.h" + +#include #include #include -#include "createhardlink.h" //! @brief Createhardlink create new symbolic link //! @@ -25,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/src/createsymlink.cpp b/src/libpsl-native/src/createsymlink.cpp index b9ce2b18d1..22ea389a30 100644 --- a/src/libpsl-native/src/createsymlink.cpp +++ b/src/libpsl-native/src/createsymlink.cpp @@ -2,10 +2,12 @@ //! @author George FLeming //! @brief create new symbolic link +#include "createsymlink.h" + +#include #include #include #include -#include "createsymlink.h" //! @brief Createsymlink create new symbolic link //! @@ -25,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 45da928902..d40821d837 100644 --- a/src/libpsl-native/src/createsymlink.h +++ b/src/libpsl-native/src/createsymlink.h @@ -1,10 +1,11 @@ #pragma once #include "pal.h" + #include 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/src/followsymlink.cpp b/src/libpsl-native/src/followsymlink.cpp index 47d0883958..6f32d697d7 100644 --- a/src/libpsl-native/src/followsymlink.cpp +++ b/src/libpsl-native/src/followsymlink.cpp @@ -2,16 +2,15 @@ //! @author George FLeming //! @brief returns whether a path is a symbolic link -#include -#include -#include -#include #include "followsymlink.h" #include "issymlink.h" -//! @brief Followsymlink determines target path of a sym link -//! -//! Followsymlink +#include +#include +#include +#include + +//! @brief FollowSymLink determines target path of a sym link //! //! @param[in] fileName //! @parblock @@ -20,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)) { @@ -64,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; } diff --git a/src/libpsl-native/src/getcomputername.cpp b/src/libpsl-native/src/getcomputername.cpp index 3e480b9ad4..b1fda7d9f0 100644 --- a/src/libpsl-native/src/getcomputername.cpp +++ b/src/libpsl-native/src/getcomputername.cpp @@ -2,44 +2,29 @@ //! @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. //! -//! @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()); + int32_t ret = gethostname(&computername[0], computername.length()); // Map errno to Win32 Error Codes - if (err != 0) + if (ret != 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()); } 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..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 -HANDLE GetCurrentThreadId() +#include +#include +#include + +pid_t GetCurrentThreadId() { - pid_t tid = pthread_self(); - return reinterpret_cast(tid); + 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 258c3c397f..9a6c94e9e3 100644 --- a/src/libpsl-native/src/getcurrentthreadid.h +++ b/src/libpsl-native/src/getcurrentthreadid.h @@ -2,9 +2,10 @@ #include "pal.h" +#include + PAL_BEGIN_EXTERNC -HANDLE GetCurrentThreadId(); +pid_t GetCurrentThreadId(); PAL_END_EXTERNC - 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 diff --git a/src/libpsl-native/src/getfileowner.cpp b/src/libpsl-native/src/getfileowner.cpp index c1bd5b69f6..56de5d3f05 100644 --- a/src/libpsl-native/src/getfileowner.cpp +++ b/src/libpsl-native/src/getfileowner.cpp @@ -2,15 +2,17 @@ //! @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 -#include "getstat.h" -#include "getpwuid.h" -#include "getfileowner.h" //! @brief GetFileOwner returns the owner of a file //! @@ -23,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/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..8a04dec009 100644 --- a/src/libpsl-native/src/getlinkcount.cpp +++ b/src/libpsl-native/src/getlinkcount.cpp @@ -2,13 +2,15 @@ //! @author George FLeming //! @brief Retrieve link count of a file +#include "getlinkcount.h" + +#include #include #include #include #include #include #include -#include "getlinkcount.h" //! @brief GetLinkCount retrieves the file link count (number of hard links) //! for the given file @@ -27,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. @@ -49,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/src/getlstat.cpp b/src/libpsl-native/src/getlstat.cpp deleted file mode 100644 index d2fcb69697..0000000000 --- a/src/libpsl-native/src/getlstat.cpp +++ /dev/null @@ -1,95 +0,0 @@ -//! @file getlstat.cpp -//! @author Andrew Schwartzmeyer -//! @brief returns the lstat of a file - -#include -#include -#include -#include -#include -#include -#include "getlstat.h" - -//! @brief GetLStat returns the lstat of a file. This simply delegates to the -//! lstat() system call and maps errno to the expected values for GetLastError. -//! -//! GetLstat -//! -//! @param[in] path -//! @parblock -//! A pointer to the buffer that contains the file name -//! -//! char* is marshaled as an LPStr, which on Linux is UTF-8. -//! @endparblock -//! -//! @param[in] lstat -//! @parblock -//! A pointer to the buffer in which to place the lstat information -//! @endparblock -//! -//! @exception errno Passes these errors via errno to GetLastError: -//! - ERROR_INVALID_PARAMETER: parameter is not valid -//! - ERROR_FILE_NOT_FOUND: file does not exist -//! - ERROR_ACCESS_DENIED: access is denied -//! - ERROR_INVALID_ADDRESS: attempt to access invalid address -//! - ERROR_STOPPED_ON_SYMLINK: too many symbolic links -//! - ERROR_GEN_FAILURE: I/O error occurred -//! - ERROR_INVALID_NAME: file provided is not a symbolic link -//! - ERROR_INVALID_FUNCTION: incorrect function -//! - ERROR_BAD_PATH_NAME: pathname is too long -//! - ERROR_OUTOFMEMORY insufficient kernel memory -//! -//! @retval 0 if successful -//! @retval -1 if failed -//! - -int32_t GetLStat(const char* path, struct stat* buf) -{ - errno = 0; - - if (!path) - { - errno = ERROR_INVALID_PARAMETER; - return -1; - } - - int32_t ret = lstat(path, buf); - - if (ret != 0) - { - switch(errno) - { - case EACCES: - errno = ERROR_ACCESS_DENIED; - break; - case EBADF: - errno = ERROR_FILE_NOT_FOUND; - break; - case EFAULT: - errno = ERROR_INVALID_ADDRESS; - break; - case ELOOP: - errno = ERROR_STOPPED_ON_SYMLINK; - break; - case ENAMETOOLONG: - errno = ERROR_GEN_FAILURE; - break; - case ENOENT: - errno = ERROR_FILE_NOT_FOUND; - break; - case ENOMEM: - errno = ERROR_NO_SUCH_USER; - break; - case ENOTDIR: - errno = ERROR_INVALID_NAME; - break; - case EOVERFLOW: - errno = ERROR_BUFFER_OVERFLOW; - break; - default: - errno = ERROR_INVALID_FUNCTION; - } - } - - return ret; -} diff --git a/src/libpsl-native/src/getlstat.h b/src/libpsl-native/src/getlstat.h deleted file mode 100644 index ba746dd35a..0000000000 --- a/src/libpsl-native/src/getlstat.h +++ /dev/null @@ -1,10 +0,0 @@ -#pragma once - -#include -#include "pal.h" - -PAL_BEGIN_EXTERNC - -int32_t GetLStat(const char* path, struct stat* buf); - -PAL_END_EXTERNC diff --git a/src/libpsl-native/src/getpwuid.cpp b/src/libpsl-native/src/getpwuid.cpp index 62263067e2..f147d7d801 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 //! @@ -19,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) @@ -42,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/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..56d3c6b1aa 100644 --- a/src/libpsl-native/src/getstat.cpp +++ b/src/libpsl-native/src/getstat.cpp @@ -2,13 +2,15 @@ //! @author Andrew Schwartzmeyer //! @brief returns the stat of a file +#include "getstat.h" + #include +#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. @@ -27,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/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..89b49ea5db 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) { @@ -32,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; } 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..1cb75a72a4 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 +#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 //! @@ -24,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/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..81e00fba23 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 +#include "isexecutable.h" + +#include #include #include -#include "isexecutable.h" //! @brief IsExecutable determines if path is executable //! @@ -18,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/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..0c3aecf46a 100644 --- a/src/libpsl-native/src/isfile.cpp +++ b/src/libpsl-native/src/isfile.cpp @@ -2,15 +2,15 @@ //! @author Andrew Schwartzmeyer //! @brief returns if the path exists -#include +#include "isfile.h" + +#include #include #include #include #include #include #include -#include "getlstat.h" -#include "isfile.h" //! @brief returns if the path is a file or directory //! @@ -23,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/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..cc6c126ea8 100644 --- a/src/libpsl-native/src/issymlink.cpp +++ b/src/libpsl-native/src/issymlink.cpp @@ -2,13 +2,13 @@ //! @author George FLeming //! @brief returns whether a path is a symbolic link -#include +#include "issymlink.h" + +#include #include #include #include #include -#include "getlstat.h" -#include "issymlink.h" //! @brief IsSymlink determines if path is a symbolic link //! @@ -21,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/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/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 - /* **============================================================================== ** diff --git a/src/libpsl-native/src/setdate.cpp b/src/libpsl-native/src/setdate.cpp index 81bfa3417e..916795cb4d 100644 --- a/src/libpsl-native/src/setdate.cpp +++ b/src/libpsl-native/src/setdate.cpp @@ -2,72 +2,41 @@ //! @author George FLeming //! @brief set local/system date and time +#include "setdate.h" + +#include #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. +//! @brief SetDate sets the date and time on local computer. +//! You must be super-user to set the time. //! //! SetDate //! -//! @param[in] info -//! @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(struct tm* time) { 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; - } - 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) { - 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..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/src/libpsl-native/test/test-createhardlink.cpp b/src/libpsl-native/test/test-createhardlink.cpp index 090864b9f7..bb9a3fbe52 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,41 +50,33 @@ 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) { 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-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-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); } 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); 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); } 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) 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 512a4053a9..68055227a7 100644 --- a/src/libpsl-native/test/test-issymlink.cpp +++ b/src/libpsl-native/test/test-issymlink.cpp @@ -55,17 +55,11 @@ 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"; 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" + } + } } 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" } } 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" } }