[KERNEL32]: Rewrite almost all the time APIs to do their own conversions instead...
authorAlex Ionescu <aionescu@gmail.com>
Tue, 26 Jul 2011 14:05:30 +0000 (14:05 +0000)
committerAlex Ionescu <aionescu@gmail.com>
Tue, 26 Jul 2011 14:05:30 +0000 (14:05 +0000)
[KERNEL32]: Add support for terminal services timezone redirection (one more for GedMurphy's pipe dream) in all the time functions.
[KERNEL32]: Make the time functions acquire SE_SYSTEMTIME_PRIVILEGE when needed (and release it).
[KERNEL32]: Fix the DOS time conversion routines.
[KERNEL32]: Add missing validations to some time functions.
[KERNEL32]: Implement IsTimeZoneRedirectionEnabled.
[KERNEL32]: Reimplement GetSystemTimes to support MP, and treat parameters as optional.

svn path=/trunk/; revision=52898

reactos/dll/win32/kernel32/client/time.c

index 50aa8f0..e7fe8f1 100644 (file)
  *                  Created 19/01/99
  */
 
-/* INCLUDES ******************************************************************/
+/* INCLUDES *******************************************************************/
 
 #include <k32.h>
 
 #define NDEBUG
 #include <debug.h>
 
-/* TYPES *********************************************************************/
-
-typedef struct __DOSTIME
-{
-    WORD Second:5;
-    WORD Minute:6;
-    WORD Hour:5;
-} DOSTIME, *PDOSTIME;
+/* FUNCTIONS ******************************************************************/
 
-typedef struct __DOSDATE
+/*
+ * @implemented
+ */
+BOOL
+WINAPI
+IsTimeZoneRedirectionEnabled(VOID)
 {
-    WORD Day:5;
-    WORD Month:4;
-    WORD Year:5;
-} DOSDATE, *PDOSDATE;
-
-/* FUNCTIONS ******************************************************************/
+    /* Return if a TS Timezone ID is active */
+    return (BaseStaticServerData->TermsrvClientTimeZoneId != TIME_ZONE_ID_INVALID);
+}
 
 /*
  * @implemented
  */
 BOOL
 WINAPI
-FileTimeToDosDateTime(CONST FILETIME *lpFileTime,
-                      LPWORD lpFatDate,
-                      LPWORD lpFatTime)
+FileTimeToDosDateTime(IN CONST FILETIME *lpFileTime,
+                      OUT LPWORD lpFatDate,
+                      OUT LPWORD lpFatTime)
 {
-    PDOSTIME  pdtime=(PDOSTIME) lpFatTime;
-    PDOSDATE  pddate=(PDOSDATE) lpFatDate;
-    SYSTEMTIME SystemTime = { 0, 0, 0, 0, 0, 0, 0, 0 };
+    LARGE_INTEGER FileTime;
+    TIME_FIELDS TimeFields;
 
-    if (lpFileTime == NULL)
-        return FALSE;
+    FileTime.HighPart = lpFileTime->dwHighDateTime;
+    FileTime.LowPart = lpFileTime->dwLowDateTime;
 
-    if (lpFatDate == NULL)
+    if (FileTime.QuadPart < 0)
+    {
+        SetLastError(ERROR_INVALID_PARAMETER);
         return FALSE;
+    }
 
-    if (lpFatTime == NULL)
+    RtlTimeToTimeFields(&FileTime, &TimeFields);
+    if ((TimeFields.Year < 1980) || (TimeFields.Year > 2107))
+    {
+        BaseSetLastNTError(STATUS_INVALID_PARAMETER);
         return FALSE;
+    }
 
-    FileTimeToSystemTime(lpFileTime, &SystemTime);
-
-    pdtime->Second = SystemTime.wSecond / 2;
-    pdtime->Minute = SystemTime.wMinute;
-    pdtime->Hour = SystemTime.wHour;
-
-    pddate->Day = SystemTime.wDay;
-    pddate->Month = SystemTime.wMonth;
-    pddate->Year = SystemTime.wYear - 1980;
+    *lpFatDate = (TimeFields.Day) |
+                 (TimeFields.Month << 5) |
+                 ((TimeFields.Year - 1980) << 9);
+    *lpFatTime = (TimeFields.Second >> 1) |
+                 (TimeFields.Minute << 5) |
+                 (TimeFields.Hour << 16);
 
     return TRUE;
 }
 
-
 /*
  * @implemented
  */
 BOOL
 WINAPI
-DosDateTimeToFileTime(WORD wFatDate,
-                      WORD wFatTime,
-                      LPFILETIME lpFileTime)
+DosDateTimeToFileTime(IN WORD wFatDate,
+                      IN WORD wFatTime,
+                      OUT LPFILETIME lpFileTime)
 {
-    PDOSTIME  pdtime = (PDOSTIME) &wFatTime;
-    PDOSDATE  pddate = (PDOSDATE) &wFatDate;
-    SYSTEMTIME SystemTime;
-
-    if (lpFileTime == NULL)
-        return FALSE;
-
-    SystemTime.wMilliseconds = 0;
-    SystemTime.wSecond = pdtime->Second * 2;
-    SystemTime.wMinute = pdtime->Minute;
-    SystemTime.wHour = pdtime->Hour;
+    TIME_FIELDS TimeFields;
+    LARGE_INTEGER SystemTime;
 
-    SystemTime.wDay = pddate->Day;
-    SystemTime.wMonth = pddate->Month;
-    SystemTime.wYear = 1980 + pddate->Year;
+    TimeFields.Year = (wFatDate >> 9) + 1980;
+    TimeFields.Month = (wFatDate >> 5) & 0xF;
+    TimeFields.Day = (wFatDate & 0x1F);
+    TimeFields.Hour = (wFatTime >> 11);
+    TimeFields.Minute = (wFatTime >> 5) & 0x3F;
+    TimeFields.Second = (wFatTime & 0x1F) << 1;
+    TimeFields.Milliseconds = 0;
 
-    if (SystemTimeToFileTime(&SystemTime, lpFileTime) == FALSE)
+    if (RtlTimeFieldsToTime(&TimeFields, &SystemTime))
     {
-        return FALSE;
+        lpFileTime->dwLowDateTime = SystemTime.LowPart;
+        lpFileTime->dwHighDateTime = SystemTime.HighPart;
+        return TRUE;
     }
 
-    return TRUE;
+    BaseSetLastNTError(STATUS_INVALID_PARAMETER);
+    return FALSE;
 }
 
-
 /*
  * @implemented
  */
 LONG
 WINAPI
-CompareFileTime(CONST FILETIME *lpFileTime1, CONST FILETIME *lpFileTime2)
+CompareFileTime(IN CONST FILETIME *lpFileTime1,
+                IN CONST FILETIME *lpFileTime2)
 {
-    if (lpFileTime1 == NULL)
-        return 0;
-    if (lpFileTime2 == NULL)
-        return 0;
+    LARGE_INTEGER Time1, Time2, Diff;
 
-    if (*((PLONGLONG)lpFileTime1) > *((PLONGLONG)lpFileTime2))
-        return 1;
-    else if (*((PLONGLONG)lpFileTime1) < *((PLONGLONG)lpFileTime2))
-        return -1;
+    Time1.LowPart = lpFileTime1->dwLowDateTime;
+    Time2.LowPart = lpFileTime2->dwLowDateTime;
+    Time1.HighPart = lpFileTime1->dwHighDateTime;
+    Time2.HighPart = lpFileTime2->dwHighDateTime;
 
-    return 0;
-}
+    Diff.QuadPart = Time1.QuadPart - Time2.QuadPart;
 
+    if (Diff.HighPart < 0) return -1;
+    if (Diff.QuadPart == 0) return 0;
+    return 1;
+}
 
 /*
  * @implemented
  */
 VOID
 WINAPI
-GetSystemTimeAsFileTime(PFILETIME lpFileTime)
+GetSystemTimeAsFileTime(OUT PFILETIME lpFileTime)
 {
+    LARGE_INTEGER SystemTime;
+
     do
     {
-        lpFileTime->dwHighDateTime = SharedUserData->SystemTime.High1Time;
-        lpFileTime->dwLowDateTime = SharedUserData->SystemTime.LowPart;
+        SystemTime.HighPart = SharedUserData->SystemTime.High1Time;
+        SystemTime.LowPart = SharedUserData->SystemTime.LowPart;
     }
-    while (lpFileTime->dwHighDateTime != (DWORD)SharedUserData->SystemTime.High2Time);
-}
+    while (SystemTime.HighPart != SharedUserData->SystemTime.High2Time);
 
+    lpFileTime->dwLowDateTime = SystemTime.LowPart;
+    lpFileTime->dwHighDateTime = SystemTime.HighPart;
+}
 
 /*
  * @implemented
  */
 BOOL
 WINAPI
-SystemTimeToFileTime(CONST SYSTEMTIME *lpSystemTime, LPFILETIME lpFileTime)
+SystemTimeToFileTime(IN CONST SYSTEMTIME *lpSystemTime,
+                     OUT LPFILETIME lpFileTime)
 {
     TIME_FIELDS TimeFields;
     LARGE_INTEGER liTime;
@@ -160,33 +160,35 @@ SystemTimeToFileTime(CONST SYSTEMTIME *lpSystemTime, LPFILETIME lpFileTime)
     TimeFields.Second = lpSystemTime->wSecond;
     TimeFields.Milliseconds = lpSystemTime->wMilliseconds;
 
-    if (RtlTimeFieldsToTime (&TimeFields, &liTime))
+    if (RtlTimeFieldsToTime(&TimeFields, &liTime))
     {
         lpFileTime->dwLowDateTime = liTime.u.LowPart;
         lpFileTime->dwHighDateTime = liTime.u.HighPart;
         return TRUE;
     }
 
-    SetLastError(ERROR_INVALID_PARAMETER);
+    BaseSetLastNTError(STATUS_INVALID_PARAMETER);
     return FALSE;
 }
 
-
 /*
  * @implemented
  */
 BOOL
 WINAPI
-FileTimeToSystemTime(CONST FILETIME *lpFileTime, LPSYSTEMTIME lpSystemTime)
+FileTimeToSystemTime(IN CONST FILETIME *lpFileTime,
+                     OUT LPSYSTEMTIME lpSystemTime)
 {
     TIME_FIELDS TimeFields;
     LARGE_INTEGER liTime;
 
-    if (lpFileTime->dwHighDateTime & 0x80000000)
-        return FALSE;
-
     liTime.u.LowPart = lpFileTime->dwLowDateTime;
     liTime.u.HighPart = lpFileTime->dwHighDateTime;
+    if (liTime.QuadPart < 0)
+    {
+        SetLastError(ERROR_INVALID_PARAMETER);
+        return FALSE;
+    }
 
     RtlTimeToTimeFields(&liTime, &TimeFields);
 
@@ -202,115 +204,237 @@ FileTimeToSystemTime(CONST FILETIME *lpFileTime, LPSYSTEMTIME lpSystemTime)
     return TRUE;
 }
 
-
 /*
  * @implemented
  */
 BOOL
 WINAPI
-FileTimeToLocalFileTime(CONST FILETIME *lpFileTime, LPFILETIME lpLocalFileTime)
+FileTimeToLocalFileTime(IN CONST FILETIME *lpFileTime,
+                        OUT LPFILETIME lpLocalFileTime)
 {
-    LARGE_INTEGER TimeZoneBias;
+    LARGE_INTEGER TimeZoneBias, FileTime;
+    volatile KSYSTEM_TIME *TimePtr;
 
+    TimePtr = IsTimeZoneRedirectionEnabled() ?
+              &BaseStaticServerData->ktTermsrvClientBias :
+              &SharedUserData->TimeZoneBias;
     do
     {
-        TimeZoneBias.HighPart = SharedUserData->TimeZoneBias.High1Time;
-        TimeZoneBias.LowPart = SharedUserData->TimeZoneBias.LowPart;
+        TimeZoneBias.HighPart = TimePtr->High1Time;
+        TimeZoneBias.LowPart = TimePtr->LowPart;
     }
-    while (TimeZoneBias.HighPart != SharedUserData->TimeZoneBias.High2Time);
+    while (TimeZoneBias.HighPart != TimePtr->High2Time);
+
+    FileTime.LowPart = lpFileTime->dwLowDateTime;
+    FileTime.HighPart = lpFileTime->dwHighDateTime;
 
-    *((PLONGLONG)lpLocalFileTime) = *((PLONGLONG)lpFileTime) - TimeZoneBias.QuadPart;
+    FileTime.QuadPart -= TimeZoneBias.QuadPart;
+
+    lpLocalFileTime->dwLowDateTime = FileTime.LowPart;
+    lpLocalFileTime->dwHighDateTime = FileTime.HighPart;
 
     return TRUE;
 }
 
-
 /*
  * @implemented
  */
 BOOL
 WINAPI
-LocalFileTimeToFileTime(CONST FILETIME *lpLocalFileTime, LPFILETIME lpFileTime)
+LocalFileTimeToFileTime(IN CONST FILETIME *lpLocalFileTime,
+                        OUT LPFILETIME lpFileTime)
 {
-    LARGE_INTEGER TimeZoneBias;
+    LARGE_INTEGER TimeZoneBias, FileTime;
+    volatile KSYSTEM_TIME *TimePtr;
+
+    TimePtr = IsTimeZoneRedirectionEnabled() ?
+              &BaseStaticServerData->ktTermsrvClientBias :
+              &SharedUserData->TimeZoneBias;
 
     do
     {
-        TimeZoneBias.HighPart = SharedUserData->TimeZoneBias.High1Time;
-        TimeZoneBias.LowPart = SharedUserData->TimeZoneBias.LowPart;
+        TimeZoneBias.HighPart = TimePtr->High1Time;
+        TimeZoneBias.LowPart = TimePtr->LowPart;
     }
-    while (TimeZoneBias.HighPart != SharedUserData->TimeZoneBias.High2Time);
+    while (TimeZoneBias.HighPart != TimePtr->High2Time);
 
-    *((PLONGLONG)lpFileTime) = *((PLONGLONG)lpLocalFileTime) + TimeZoneBias.QuadPart;
+    FileTime.LowPart = lpLocalFileTime->dwLowDateTime;
+    FileTime.HighPart = lpLocalFileTime->dwHighDateTime;
+
+    FileTime.QuadPart += TimeZoneBias.QuadPart;
+
+    lpFileTime->dwLowDateTime = FileTime.LowPart;
+    lpFileTime->dwHighDateTime = FileTime.HighPart;
 
     return TRUE;
 }
 
-
 /*
  * @implemented
  */
 VOID
 WINAPI
-GetLocalTime(LPSYSTEMTIME lpSystemTime)
+GetLocalTime(OUT LPSYSTEMTIME lpSystemTime)
 {
-    FILETIME FileTime;
-    FILETIME LocalFileTime;
+    LARGE_INTEGER SystemTime, TimeZoneBias;
+    TIME_FIELDS TimeFields;
+    volatile KSYSTEM_TIME *TimePtr;
 
-    GetSystemTimeAsFileTime(&FileTime);
-    FileTimeToLocalFileTime(&FileTime, &LocalFileTime);
-    FileTimeToSystemTime(&LocalFileTime, lpSystemTime);
-}
+    do
+    {
+        SystemTime.HighPart = SharedUserData->SystemTime.High1Time;
+        SystemTime.LowPart = SharedUserData->SystemTime.LowPart;
+    }
+    while (SystemTime.HighPart != SharedUserData->SystemTime.High2Time);
+
+    TimePtr = IsTimeZoneRedirectionEnabled() ?
+              &BaseStaticServerData->ktTermsrvClientBias :
+              &SharedUserData->TimeZoneBias;
+    do
+    {
+        TimeZoneBias.HighPart = TimePtr->High1Time;
+        TimeZoneBias.LowPart = TimePtr->LowPart;
+    }
+    while (TimeZoneBias.HighPart != TimePtr->High2Time);
 
+    SystemTime.QuadPart -= TimeZoneBias.QuadPart;
+    RtlTimeToTimeFields(&SystemTime, &TimeFields);
+
+    lpSystemTime->wYear = TimeFields.Year;
+    lpSystemTime->wMonth = TimeFields.Month;
+    lpSystemTime->wDay = TimeFields.Day;
+    lpSystemTime->wHour = TimeFields.Hour;
+    lpSystemTime->wMinute = TimeFields.Minute;
+    lpSystemTime->wSecond = TimeFields.Second;
+    lpSystemTime->wMilliseconds = TimeFields.Milliseconds;
+    lpSystemTime->wDayOfWeek = TimeFields.Weekday;
+}
 
 /*
  * @implemented
  */
 VOID
 WINAPI
-GetSystemTime(LPSYSTEMTIME lpSystemTime)
+GetSystemTime(OUT LPSYSTEMTIME lpSystemTime)
 {
-    FILETIME FileTime;
+    LARGE_INTEGER SystemTime;
+    TIME_FIELDS TimeFields;
 
-    GetSystemTimeAsFileTime(&FileTime);
-    FileTimeToSystemTime(&FileTime, lpSystemTime);
-}
+    do
+    {
+        SystemTime.HighPart = SharedUserData->SystemTime.High1Time;
+        SystemTime.LowPart = SharedUserData->SystemTime.LowPart;
+    }
+    while (SystemTime.HighPart != SharedUserData->SystemTime.High2Time);
+
+    RtlTimeToTimeFields(&SystemTime, &TimeFields);
 
+    lpSystemTime->wYear = TimeFields.Year;
+    lpSystemTime->wMonth = TimeFields.Month;
+    lpSystemTime->wDay = TimeFields.Day;
+    lpSystemTime->wHour = TimeFields.Hour;
+    lpSystemTime->wMinute = TimeFields.Minute;
+    lpSystemTime->wSecond = TimeFields.Second;
+    lpSystemTime->wMilliseconds = TimeFields.Milliseconds;
+    lpSystemTime->wDayOfWeek = TimeFields.Weekday;
+}
 
 /*
  * @implemented
  */
 BOOL
 WINAPI
-SetLocalTime(CONST SYSTEMTIME *lpSystemTime)
+SetLocalTime(IN CONST SYSTEMTIME *lpSystemTime)
 {
-    FILETIME LocalFileTime;
-    LARGE_INTEGER FileTime;
+    LARGE_INTEGER NewSystemTime, TimeZoneBias;
     NTSTATUS Status;
+    ULONG Privilege = SE_SYSTEMTIME_PRIVILEGE;
+    TIME_FIELDS TimeFields;
+    PVOID State;
+    volatile KSYSTEM_TIME *TimePtr;
+
+    TimePtr = IsTimeZoneRedirectionEnabled() ?
+              &BaseStaticServerData->ktTermsrvClientBias :
+              &SharedUserData->TimeZoneBias;
+    do
+    {
+        TimeZoneBias.HighPart = TimePtr->High1Time;
+        TimeZoneBias.LowPart = TimePtr->LowPart;
+    }
+    while (TimeZoneBias.HighPart != TimePtr->High2Time);
+
+    TimeFields.Year = lpSystemTime->wYear;
+    TimeFields.Month = lpSystemTime->wMonth;
+    TimeFields.Day = lpSystemTime->wDay;
+    TimeFields.Hour = lpSystemTime->wHour;
+    TimeFields.Minute = lpSystemTime->wMinute;
+    TimeFields.Second = lpSystemTime->wSecond;
+    TimeFields.Milliseconds = lpSystemTime->wMilliseconds;
+
+    if (!RtlTimeFieldsToTime(&TimeFields, &NewSystemTime))
+    {
+        BaseSetLastNTError(STATUS_INVALID_PARAMETER);
+        return FALSE;
+    }
+
+    NewSystemTime.QuadPart += TimeZoneBias.QuadPart;
+
+    Status = RtlAcquirePrivilege(&Privilege, 1, 0, &State);
+    if (NT_SUCCESS(Status))
+    {
+        Status = NtSetSystemTime(&NewSystemTime, NULL);
+        RtlReleasePrivilege(State);
+    }
 
-    SystemTimeToFileTime(lpSystemTime, &LocalFileTime);
-    LocalFileTimeToFileTime(&LocalFileTime, (FILETIME *)&FileTime);
-    Status = NtSetSystemTime(&FileTime, &FileTime);
     if (!NT_SUCCESS(Status))
+    {
+        BaseSetLastNTError(Status);
         return FALSE;
+    }
+
     return TRUE;
 }
 
-
 /*
  * @implemented
  */
 BOOL
 WINAPI
-SetSystemTime(CONST SYSTEMTIME *lpSystemTime)
+SetSystemTime(IN CONST SYSTEMTIME *lpSystemTime)
 {
     LARGE_INTEGER NewSystemTime;
     NTSTATUS Status;
+    ULONG Privilege = SE_SYSTEMTIME_PRIVILEGE;
+    TIME_FIELDS TimeFields;
+    PVOID State;
+
+    TimeFields.Year = lpSystemTime->wYear;
+    TimeFields.Month = lpSystemTime->wMonth;
+    TimeFields.Day = lpSystemTime->wDay;
+    TimeFields.Hour = lpSystemTime->wHour;
+    TimeFields.Minute = lpSystemTime->wMinute;
+    TimeFields.Second = lpSystemTime->wSecond;
+    TimeFields.Milliseconds = lpSystemTime->wMilliseconds;
+
+    if (!RtlTimeFieldsToTime(&TimeFields, &NewSystemTime))
+    {
+        BaseSetLastNTError(STATUS_INVALID_PARAMETER);
+        return FALSE;
+    }
+
+    Status = RtlAcquirePrivilege(&Privilege, 1, 0, &State);
+    if (NT_SUCCESS(Status))
+    {
+        Status = NtSetSystemTime(&NewSystemTime, NULL);
+        RtlReleasePrivilege(State);
+    }
 
-    SystemTimeToFileTime(lpSystemTime, (PFILETIME)&NewSystemTime);
-    Status = NtSetSystemTime(&NewSystemTime, &NewSystemTime);
     if (!NT_SUCCESS(Status))
+    {
+        BaseSetLastNTError(Status);
         return FALSE;
+    }
+
     return TRUE;
 }
 
@@ -334,38 +458,28 @@ GetTickCount(VOID)
         YieldProcessor();
     }
 
-    return (ULONG)((UInt32x32To64(TickCount.LowPart, SharedUserData->TickCountMultiplier) >> 24) +
-                    UInt32x32To64((TickCount.HighPart << 8) & 0xFFFFFFFF, SharedUserData->TickCountMultiplier));
+    return (ULONG)((UInt32x32To64(TickCount.LowPart,
+                                  SharedUserData->TickCountMultiplier) >> 24) +
+                    UInt32x32To64((TickCount.HighPart << 8) & 0xFFFFFFFF,
+                                  SharedUserData->TickCountMultiplier));
 
 }
 
-/*
- * @unimplemented
- */
-BOOL
-WINAPI
-SetClientTimeZoneInformation(
-    CONST TIME_ZONE_INFORMATION *lpTimeZoneInformation)
-{
-    STUB;
-    return 0;
-}
-
 /*
  * @implemented
  */
 BOOL
 WINAPI
-GetSystemTimeAdjustment(PDWORD lpTimeAdjustment,
-                        PDWORD lpTimeIncrement,
-                        PBOOL lpTimeAdjustmentDisabled)
+GetSystemTimeAdjustment(OUT PDWORD lpTimeAdjustment,
+                        OUT PDWORD lpTimeIncrement,
+                        OUT PBOOL lpTimeAdjustmentDisabled)
 {
-    SYSTEM_QUERY_TIME_ADJUST_INFORMATION Buffer;
+    SYSTEM_QUERY_TIME_ADJUST_INFORMATION TimeInfo;
     NTSTATUS Status;
 
     Status = NtQuerySystemInformation(SystemTimeAdjustmentInformation,
-                                      &Buffer,
-                                      sizeof(SYSTEM_QUERY_TIME_ADJUST_INFORMATION),
+                                      &TimeInfo,
+                                      sizeof(TimeInfo),
                                       NULL);
     if (!NT_SUCCESS(Status))
     {
@@ -373,31 +487,30 @@ GetSystemTimeAdjustment(PDWORD lpTimeAdjustment,
         return FALSE;
     }
 
-    *lpTimeAdjustment = (DWORD)Buffer.TimeAdjustment;
-    *lpTimeIncrement = (DWORD)Buffer.TimeIncrement;
-    *lpTimeAdjustmentDisabled = (BOOL)Buffer.Enable;
+    *lpTimeAdjustment = (DWORD)TimeInfo.TimeAdjustment;
+    *lpTimeIncrement = (DWORD)TimeInfo.TimeIncrement;
+    *lpTimeAdjustmentDisabled = (BOOL)TimeInfo.Enable;
 
     return TRUE;
 }
 
-
 /*
  * @implemented
  */
 BOOL
 WINAPI
-SetSystemTimeAdjustment(DWORD dwTimeAdjustment,
-                        BOOL bTimeAdjustmentDisabled)
+SetSystemTimeAdjustment(IN DWORD dwTimeAdjustment,
+                        IN BOOL bTimeAdjustmentDisabled)
 {
     NTSTATUS Status;
-    SYSTEM_SET_TIME_ADJUST_INFORMATION Buffer;
+    SYSTEM_SET_TIME_ADJUST_INFORMATION TimeInfo;
 
-    Buffer.TimeAdjustment = (ULONG)dwTimeAdjustment;
-    Buffer.Enable = (BOOLEAN)bTimeAdjustmentDisabled;
+    TimeInfo.TimeAdjustment = (ULONG)dwTimeAdjustment;
+    TimeInfo.Enable = (BOOLEAN)bTimeAdjustmentDisabled;
 
     Status = NtSetSystemInformation(SystemTimeAdjustmentInformation,
-                                    &Buffer,
-                                    sizeof(SYSTEM_SET_TIME_ADJUST_INFORMATION));
+                                    &TimeInfo,
+                                    sizeof(TimeInfo));
     if (!NT_SUCCESS(Status))
     {
         BaseSetLastNTError(Status);
@@ -407,55 +520,96 @@ SetSystemTimeAdjustment(DWORD dwTimeAdjustment,
     return TRUE;
 }
 
-
 /*
  * @implemented
  */
 BOOL
 WINAPI
-GetSystemTimes(LPFILETIME lpIdleTime,
-               LPFILETIME lpKernelTime,
-               LPFILETIME lpUserTime)
+GetSystemTimes(OUT LPFILETIME lpIdleTime OPTIONAL,
+               OUT LPFILETIME lpKernelTime OPTIONAL,
+               OUT LPFILETIME lpUserTime OPTIONAL)
 {
-    SYSTEM_PROCESSOR_PERFORMANCE_INFORMATION SysProcPerfInfo;
+    PSYSTEM_PROCESSOR_PERFORMANCE_INFORMATION ProcPerfInfo;
+    LARGE_INTEGER TotalUserTime, TotalKernTime, TotalIdleTime;
+    SIZE_T BufferSize, ReturnLength;
+    ULONG i;
     NTSTATUS Status;
 
+    TotalUserTime.QuadPart = TotalKernTime.QuadPart = TotalIdleTime.QuadPart = 0;
+
+    BufferSize = sizeof(SYSTEM_PROCESSOR_PERFORMANCE_INFORMATION) *
+                 BaseStaticServerData->SysInfo.NumberOfProcessors;
+
+    ProcPerfInfo = RtlAllocateHeap(RtlGetProcessHeap(), 0, BufferSize);
+    if (!ProcPerfInfo)
+    {
+        BaseSetLastNTError(STATUS_NO_MEMORY);
+        return FALSE;
+    }
+
     Status = ZwQuerySystemInformation(SystemProcessorPerformanceInformation,
-                                      &SysProcPerfInfo,
-                                      sizeof(SysProcPerfInfo),
-                                      NULL);
+                                      ProcPerfInfo,
+                                      BufferSize,
+                                      &ReturnLength);
+    if ((NT_SUCCESS(Status)) && (ReturnLength == BufferSize))
+    {
+        if (lpIdleTime)
+        {
+            for (i = 0; i < BaseStaticServerData->SysInfo.NumberOfProcessors; i++)
+            {
+                TotalIdleTime.QuadPart += ProcPerfInfo[i].IdleTime.QuadPart;
+            }
+
+            lpIdleTime->dwLowDateTime = TotalIdleTime.LowPart;
+            lpIdleTime->dwHighDateTime = TotalIdleTime.HighPart;
+        }
+
+        if (lpKernelTime)
+        {
+            for (i = 0; i < BaseStaticServerData->SysInfo.NumberOfProcessors; i++)
+            {
+                TotalKernTime.QuadPart += ProcPerfInfo[i].KernelTime.QuadPart;
+            }
+
+            lpKernelTime->dwLowDateTime = TotalKernTime.LowPart;
+            lpKernelTime->dwHighDateTime = TotalKernTime.HighPart;
+        }
+
+        if (lpUserTime)
+        {
+            for (i = 0; i < BaseStaticServerData->SysInfo.NumberOfProcessors; i++)
+            {
+                TotalUserTime.QuadPart += ProcPerfInfo[i].UserTime.QuadPart;
+            }
+
+            lpUserTime->dwLowDateTime = TotalUserTime.LowPart;
+            lpUserTime->dwHighDateTime = TotalUserTime.HighPart;
+        }
+    }
+    else if (NT_SUCCESS(Status))
+    {
+         Status = STATUS_INTERNAL_ERROR;
+    }
 
+    RtlFreeHeap(RtlGetProcessHeap(), 0, ProcPerfInfo);
     if (!NT_SUCCESS(Status))
     {
         BaseSetLastNTError(Status);
         return FALSE;
     }
-/*
-    Good only for one processor system.
- */
-
-    lpIdleTime->dwLowDateTime = SysProcPerfInfo.IdleTime.LowPart;
-    lpIdleTime->dwHighDateTime = SysProcPerfInfo.IdleTime.HighPart;
-
-    lpKernelTime->dwLowDateTime = SysProcPerfInfo.KernelTime.LowPart;
-    lpKernelTime->dwHighDateTime = SysProcPerfInfo.KernelTime.HighPart;
-
-    lpUserTime->dwLowDateTime = SysProcPerfInfo.UserTime.LowPart;
-    lpUserTime->dwHighDateTime = SysProcPerfInfo.UserTime.HighPart;
 
     return TRUE;
 }
 
 /*
- * @implemented
+ * @unimplemented
  */
 BOOL
 WINAPI
-IsTimeZoneRedirectionEnabled(VOID)
+SetClientTimeZoneInformation(IN CONST TIME_ZONE_INFORMATION *lpTimeZoneInformation)
 {
-    /* To be implemented soon */
-    //return (BaseStaticServerData->TermsrvClientTimeZoneId != TIME_ZONE_ID_INVALID);
-    return FALSE;
+    STUB;
+    return 0;
 }
 
 /* EOF */