Merge pull request #2441 from andschwa/native-perror

Fix error handling of libpsl-native
This commit is contained in:
Andrew Schwartzmeyer 2016-10-17 11:13:31 -07:00 committed by GitHub
commit 8e3861a64b
52 changed files with 400 additions and 899 deletions

View file

@ -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;

View file

@ -12,6 +12,14 @@
"allowUnsafe": true
},
"configurations": {
"Linux": {
"buildOptions": {
"define": [ "UNIX" ]
}
}
},
"dependencies": {
"System.Management.Automation": "1.0.0-*"
},

View file

@ -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 <time.h>
[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,

View file

@ -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<string> InternalGetTarget(string filePath)
{
var links = new List<string>();
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")]

View file

@ -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

View file

@ -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")

View file

@ -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

View file

@ -2,10 +2,11 @@
//! @author George FLeming <v-geflem@microsoft.com>
//! @brief create new hard link
#include <errno.h>
#include "createhardlink.h"
#include <assert.h>
#include <unistd.h>
#include <string>
#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);
}

View file

@ -2,10 +2,12 @@
//! @author George FLeming <v-geflem@microsoft.com>
//! @brief create new symbolic link
#include "createsymlink.h"
#include <assert.h>
#include <errno.h>
#include <unistd.h>
#include <string>
#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);
}

View file

@ -1,10 +1,11 @@
#pragma once
#include "pal.h"
#include <stdbool.h>
PAL_BEGIN_EXTERNC
bool CreateSymLink(const char *link, const char *target);
int32_t CreateSymLink(const char *link, const char *target);
PAL_END_EXTERNC

View file

@ -2,16 +2,15 @@
//! @author George FLeming <v-geflem@microsoft.com>
//! @brief returns whether a path is a symbolic link
#include <errno.h>
#include <unistd.h>
#include <string>
#include <iostream>
#include "followsymlink.h"
#include "issymlink.h"
//! @brief Followsymlink determines target path of a sym link
//!
//! Followsymlink
#include <assert.h>
#include <errno.h>
#include <unistd.h>
#include <string>
//! @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;
}

View file

@ -2,44 +2,29 @@
//! @author George Fleming <v-geflem@microsoft>
//! @brief Implements GetComputerName Win32 API
#include "getcomputername.h"
#include <errno.h>
#include <unistd.h>
#include <string>
#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());
}

View file

@ -1,9 +1,8 @@
#include "getcurrentprocessorid.h"
#include <unistd.h>
int32_t GetCurrentProcessId()
pid_t GetCurrentProcessId()
{
pid_t pid = getpid();
return static_cast<int32_t>(pid);
return getpid();
}

View file

@ -1,10 +1,11 @@
#pragma once
#include "pal.h"
#include <sys/types.h>
PAL_BEGIN_EXTERNC
int32_t GetCurrentProcessId();
pid_t GetCurrentProcessId();
PAL_END_EXTERNC

View file

@ -1,9 +1,16 @@
#include "getcurrentthreadid.h"
#include <unistd.h>
#include <pthread.h>
HANDLE GetCurrentThreadId()
#include <unistd.h>
#include <sys/types.h>
#include <sys/syscall.h>
pid_t GetCurrentThreadId()
{
pid_t tid = pthread_self();
return reinterpret_cast<HANDLE>(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;
}

View file

@ -2,9 +2,10 @@
#include "pal.h"
#include <sys/types.h>
PAL_BEGIN_EXTERNC
HANDLE GetCurrentThreadId();
pid_t GetCurrentThreadId();
PAL_END_EXTERNC

View file

@ -0,0 +1,63 @@
#include "geterrorcategory.h"
#include <assert.h>
#include <sys/types.h>
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
// 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;
}
}

View file

@ -0,0 +1,9 @@
#pragma once
#include "pal.h"
PAL_BEGIN_EXTERNC
int32_t GetErrorCategory(int32_t);
PAL_END_EXTERNC

View file

@ -2,15 +2,17 @@
//! @author Andrew Schwartzmeyer <andschwa@microsoft.com>
//! @brief returns the owner of a file
#include "getstat.h"
#include "getpwuid.h"
#include "getfileowner.h"
#include <assert.h>
#include <errno.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <pwd.h>
#include <string.h>
#include <unistd.h>
#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;

View file

@ -2,12 +2,13 @@
//! @author George Fleming <v-geflem@microsoft.com>
//! @brief Implements GetFullyQualifiedName on Linux
#include "getcomputername.h"
#include "getfullyqualifiedname.h"
#include <errno.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netdb.h>
#include "getcomputername.h"
#include "getfullyqualifiedname.h"
//! @brief GetFullyQualifiedName retrieves the fully qualified dns name of the host
//!

View file

@ -2,13 +2,15 @@
//! @author George FLeming <v-geflem@microsoft.com>
//! @brief Retrieve link count of a file
#include "getlinkcount.h"
#include <assert.h>
#include <errno.h>
#include <locale.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <string>
#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;
}

View file

@ -1,95 +0,0 @@
//! @file getlstat.cpp
//! @author Andrew Schwartzmeyer <andschwa@microsoft.com>
//! @brief returns the lstat of a file
#include <errno.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <pwd.h>
#include <string.h>
#include <unistd.h>
#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;
}

View file

@ -1,10 +0,0 @@
#pragma once
#include <sys/stat.h>
#include "pal.h"
PAL_BEGIN_EXTERNC
int32_t GetLStat(const char* path, struct stat* buf);
PAL_END_EXTERNC

View file

@ -2,13 +2,14 @@
//! @author Andrew Schwartzmeyer <andschwa@microsoft.com>
//! @brief returns the username for a uid
#include "getpwuid.h"
#include <errno.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <pwd.h>
#include <string.h>
#include <unistd.h>
#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;
}

View file

@ -1,8 +1,9 @@
#pragma once
#include <sys/types.h>
#include "pal.h"
#include <sys/types.h>
PAL_BEGIN_EXTERNC
char* GetPwUid(uid_t uid);

View file

@ -2,13 +2,15 @@
//! @author Andrew Schwartzmeyer <andschwa@microsoft.com>
//! @brief returns the stat of a file
#include "getstat.h"
#include <errno.h>
#include <assert.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <pwd.h>
#include <string.h>
#include <unistd.h>
#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);
}

View file

@ -1,8 +1,9 @@
#pragma once
#include <sys/stat.h>
#include "pal.h"
#include <sys/stat.h>
PAL_BEGIN_EXTERNC
int32_t GetStat(const char* path, struct stat* buf);

View file

@ -1,12 +1,13 @@
#include <string>
#include <sstream>
#include <errno.h>
#include <sys/sysctl.h>
#include "pal.h"
#include "getfileowner.h"
#include "getpwuid.h"
#include "getuserfrompid.h"
#include <string>
#include <sstream>
#include <errno.h>
#include <sys/sysctl.h>
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;
}

View file

@ -2,6 +2,8 @@
#include "pal.h"
#include <sys/types.h>
PAL_BEGIN_EXTERNC
char* GetUserFromPid(pid_t pid);

View file

@ -2,10 +2,11 @@
//! @author Andrew Schwartzmeyer <andschwa@microsoft.com>
//! @brief Implements GetUserName for Linux
#include <unistd.h>
#include "getpwuid.h"
#include "getusername.h"
#include <unistd.h>
//! @brief GetUserName retrieves the name of the user associated with
//! the current thread.
//!

View file

@ -2,16 +2,17 @@
//! @author Andrew Schwartzmeyer <andschwa@microsoft.com>
//! @brief returns if the path is a directory
#include <errno.h>
#include "getstat.h"
#include "getpwuid.h"
#include "getfileowner.h"
#include "isdirectory.h"
#include <assert.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <pwd.h>
#include <string.h>
#include <unistd.h>
#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);

View file

@ -1,6 +1,7 @@
#pragma once
#include "pal.h"
#include <stdbool.h>
PAL_BEGIN_EXTERNC

View file

@ -2,10 +2,11 @@
//! @author George Fleming <v-geflem@microsoft.com>
//! @brief returns whether a file is executable
#include <errno.h>
#include "isexecutable.h"
#include <assert.h>
#include <unistd.h>
#include <string>
#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;
}

View file

@ -1,6 +1,7 @@
#pragma once
#include "pal.h"
#include <stdbool.h>
PAL_BEGIN_EXTERNC

View file

@ -2,15 +2,15 @@
//! @author Andrew Schwartzmeyer <andschwa@microsoft.com>
//! @brief returns if the path exists
#include <errno.h>
#include "isfile.h"
#include <assert.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <pwd.h>
#include <string.h>
#include <fcntl.h>
#include <unistd.h>
#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;
}

View file

@ -1,6 +1,7 @@
#pragma once
#include "pal.h"
#include <stdbool.h>
PAL_BEGIN_EXTERNC

View file

@ -2,13 +2,13 @@
//! @author George FLeming <v-geflem@microsoft.com>
//! @brief returns whether a path is a symbolic link
#include <errno.h>
#include "issymlink.h"
#include <assert.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <string>
#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;

View file

@ -1,6 +1,7 @@
#pragma once
#include "pal.h"
#include <stdbool.h>
PAL_BEGIN_EXTERNC

View file

@ -5,27 +5,6 @@
#include <inttypes.h>
#include <limits.h>
#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
/*
**==============================================================================
**

View file

@ -2,72 +2,41 @@
//! @author George FLeming <v-geflem@microsoft.com>
//! @brief set local/system date and time
#include "setdate.h"
#include <assert.h>
#include <errno.h>
#include <langinfo.h>
#include <locale.h>
#include <string>
#include <time.h>
#include <sys/time.h>
#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);
}

View file

@ -2,21 +2,10 @@
#include "pal.h"
#include <time.h>
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

View file

@ -3,7 +3,6 @@
//! @brief Implements test for CreateHardLink()
#include <gtest/gtest.h>
#include <errno.h>
#include <unistd.h>
#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);
}

View file

@ -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);
}

View file

@ -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);
}

View file

@ -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);

View file

@ -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);
}

View file

@ -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)

View file

@ -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);
}

View file

@ -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)

View file

@ -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"
}
}
}

View file

@ -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"
}
}

View file

@ -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"
}
}