From 24d0ce36e668ce06936e8731aae26f223554917c Mon Sep 17 00:00:00 2001 From: Andrew Schwartzmeyer Date: Fri, 7 Oct 2016 16:33:16 -0700 Subject: [PATCH] Fix SetDate And use a bunch of unsafe code because of concerns about stack size. --- .../CoreCLR/CorePsPlatform.cs | 69 +++++++++---------- src/libpsl-native/src/setdate.cpp | 19 +---- src/libpsl-native/src/setdate.h | 17 +---- .../Set-Date.Tests.ps1 | 5 +- 4 files changed, 43 insertions(+), 67 deletions(-) diff --git a/src/System.Management.Automation/CoreCLR/CorePsPlatform.cs b/src/System.Management.Automation/CoreCLR/CorePsPlatform.cs index 9b6672461f..ee75313abb 100644 --- a/src/System.Management.Automation/CoreCLR/CorePsPlatform.cs +++ b/src/System.Management.Automation/CoreCLR/CorePsPlatform.cs @@ -403,10 +403,10 @@ namespace System.Management.Automation return Unix.NativeMethods.CreateHardLink(path, strTargetPath) == 0; } - internal static bool NonWindowsSetDate(DateTime dateToUse) + internal static unsafe bool NonWindowsSetDate(DateTime dateToUse) { - Unix.SetDateInfoInternal date = new Unix.SetDateInfoInternal(dateToUse); - return Unix.NativeMethods.SetDate(date) == 0; + Unix.NativeMethods.UnixTm tm = Unix.NativeMethods.DateTimeToUnixTm(dateToUse); + return Unix.NativeMethods.SetDate(&tm) == 0; } internal static string NonWindowsGetDomainName() @@ -526,37 +526,6 @@ namespace System.Management.Automation } } - [StructLayout(LayoutKind.Sequential)] - internal class SetDateInfoInternal - { - public int Year; - public int Month; - public int Day; - public int Hour; - public int Minute; - public int Second; - public int Millisecond; - public int DST; - - public SetDateInfoInternal(DateTime d) - { - Year = d.Year; - Month = d.Month; - Day = d.Day; - Hour = d.Hour; - Minute = d.Minute; - Second = d.Second; - Millisecond = d.Millisecond; - DST = d.IsDaylightSavingTime() ? 1 : 0; - } - - public override string ToString() - { - string ret = String.Format("Year = {0}; Month = {1}; Day = {2}; Hour = {3}; Minute = {4}; Second = {5}; Millisec = {6}; DST = {7}", Year, Month, Day, Hour, Minute, Second, Millisecond, DST); - return ret; - } - } - internal static class NativeMethods { private const string psLib = "libpsl-native"; @@ -587,8 +556,38 @@ namespace System.Management.Automation [return: MarshalAs(UnmanagedType.LPStr)] internal static extern string GetFullyQualifiedName(); + // This is a struct tm from + [StructLayout(LayoutKind.Sequential)] + internal unsafe struct UnixTm + { + public int tm_sec; /* Seconds (0-60) */ + public int tm_min; /* Minutes (0-59) */ + public int tm_hour; /* Hours (0-23) */ + public int tm_mday; /* Day of the month (1-31) */ + public int tm_mon; /* Month (0-11) */ + public int tm_year; /* Year - 1900 */ + public int tm_wday; /* Day of the week (0-6, Sunday = 0) */ + public int tm_yday; /* Day in the year (0-365, 1 Jan = 0) */ + public int tm_isdst; /* Daylight saving time */ + } + + internal static UnixTm DateTimeToUnixTm(DateTime date) + { + UnixTm tm; + tm.tm_sec = date.Second; + tm.tm_min = date.Minute; + tm.tm_hour = date.Hour; + tm.tm_mday = date.Day; + tm.tm_mon = date.Month - 1; // needs to be 0 indexed + tm.tm_year = date.Year - 1900; // years since 1900 + tm.tm_wday = 0; // this is ignored by mktime + tm.tm_yday = 0; // this is also ignored + tm.tm_isdst = date.IsDaylightSavingTime() ? 1 : 0; + return tm; + } + [DllImport(psLib, CharSet = CharSet.Ansi, SetLastError = true)] - internal static extern int SetDate(SetDateInfoInternal info); + internal static extern unsafe int SetDate(UnixTm* tm); [DllImport(psLib, CharSet = CharSet.Ansi, SetLastError = true)] internal static extern int CreateSymLink([MarshalAs(UnmanagedType.LPStr)]string filePath, diff --git a/src/libpsl-native/src/setdate.cpp b/src/libpsl-native/src/setdate.cpp index 3f350101ff..916795cb4d 100644 --- a/src/libpsl-native/src/setdate.cpp +++ b/src/libpsl-native/src/setdate.cpp @@ -17,34 +17,19 @@ //! //! SetDate //! -//! @param[in] info -//! @parblock -//! A struct that contains program to execute and its parameters -//! //! @retval 0 successfully set date //! @retval -1 if failure occurred. //! -int32_t SetDate(const SetDateInfo info) +int32_t SetDate(struct tm* time) { errno = 0; // Select locale from environment setlocale(LC_ALL, ""); - // Check that locale is UTF-8 - assert(nl_langinfo(CODESET) == std::string("UTF-8")); - struct tm bdTime; struct timeval tv; - bdTime.tm_year = info.Year - 1900; - bdTime.tm_mon = info.Month - 1; // This is zero-based - bdTime.tm_mday = info.Day; - bdTime.tm_hour = info.Hour; - bdTime.tm_min = info.Minute; - bdTime.tm_sec = info.Second; - bdTime.tm_isdst = info.DST; - - time_t newTime = mktime(&bdTime); + time_t newTime = mktime(time); if (newTime == -1) { return -1; diff --git a/src/libpsl-native/src/setdate.h b/src/libpsl-native/src/setdate.h index bf2bccaed1..ad0389a6a6 100644 --- a/src/libpsl-native/src/setdate.h +++ b/src/libpsl-native/src/setdate.h @@ -2,21 +2,10 @@ #include "pal.h" +#include + PAL_BEGIN_EXTERNC -typedef struct setDateInfo -{ - // the order of members does matter here - int32_t Year; - int32_t Month; - int32_t Day; - int32_t Hour; - int32_t Minute; - int32_t Second; - int32_t Millisecond; - int32_t DST; -} SetDateInfo; - -int32_t SetDate(const SetDateInfo info); +int32_t SetDate(struct tm* time); PAL_END_EXTERNC diff --git a/test/powershell/Modules/Microsoft.PowerShell.Utility/Set-Date.Tests.ps1 b/test/powershell/Modules/Microsoft.PowerShell.Utility/Set-Date.Tests.ps1 index d523146dda..ce723a1ba6 100644 --- a/test/powershell/Modules/Microsoft.PowerShell.Utility/Set-Date.Tests.ps1 +++ b/test/powershell/Modules/Microsoft.PowerShell.Utility/Set-Date.Tests.ps1 @@ -6,10 +6,13 @@ Describe "Set-Date" -Tag "CI" { Import-Module (join-path $psscriptroot "../../Common/Test.Helpers.psm1") $IsElevated = Test-IsElevated } + It "Set-Date should be able to set the date in an elevated context" -Skip:(! $IsElevated) { { get-date | set-date } | Should not throw } + It "Set-Date should produce an error in a non-elevated context" -Skip:($IsElevated) { - { get-date |set-date} | should throw + { get-date | set-date} | should throw + $Error[0].FullyQualifiedErrorId | should be "System.ComponentModel.Win32Exception,Microsoft.PowerShell.Commands.SetDateCommand" } }