- Fix formatting and a bug in NtSetSystemTime.
[reactos.git] / reactos / ntoskrnl / ex / time.c
index 353f791..5671b7e 100644 (file)
-/* $Id: time.c,v 1.12 2001/09/06 20:26:36 dwelch Exp $
- *
+/*
  * COPYRIGHT:       See COPYING in the top level directory
- * PROJECT:         ReactOS kernel
+ * PROJECT:         ReactOS Kernel
  * FILE:            ntoskrnl/ex/time.c
- * PURPOSE:         Time
- * PROGRAMMER:      David Welch (welch@mcmail.com)
- * UPDATE HISTORY:
- *                  Created 22/05/98
+ * PURPOSE:         Time and Timezone Management
+ * PROGRAMMERS:     Eric Kohl
+ *                  Thomas Weidenmueller
  */
 
 /* INCLUDES *****************************************************************/
 
-#include <ddk/ntddk.h>
-#include <internal/ex.h>
-#include <internal/safe.h>
-#include <ddk/halfuncs.h>
-#include <ddk/kefuncs.h>
-
+#include <ntoskrnl.h>
+#define NDEBUG
 #include <internal/debug.h>
 
-
 #define TICKSPERMINUTE  600000000
 
+#if defined (ALLOC_PRAGMA)
+#pragma alloc_text(INIT, ExpInitTimeZoneInfo)
+#endif
+
 /* GLOBALS ******************************************************************/
 
 /* Note: Bias[minutes] = UTC - local time */
-TIME_ZONE_INFORMATION _SystemTimeZoneInfo;
-
+TIME_ZONE_INFORMATION ExpTimeZoneInfo;
+LARGE_INTEGER ExpTimeZoneBias;
+ULONG ExpTimeZoneId;
 
 /* FUNCTIONS ****************************************************************/
 
 VOID
-ExInitTimeZoneInfo (VOID)
+INIT_FUNCTION
+NTAPI
+ExpInitTimeZoneInfo(VOID)
 {
-  /* Initialize system time zone information */
-  memset (& _SystemTimeZoneInfo, 0, sizeof(TIME_ZONE_INFORMATION));
+    LARGE_INTEGER CurrentTime;
+    NTSTATUS Status;
+
+     /* Read time zone information from the registry */
+    Status = RtlQueryTimeZoneInformation(&ExpTimeZoneInfo);
+    if (!NT_SUCCESS(Status))
+    {
+        /* Failed, clear all data */
+        RtlZeroMemory(&ExpTimeZoneInfo, sizeof(TIME_ZONE_INFORMATION));
+        ExpTimeZoneBias.QuadPart = (LONGLONG)0;
+        ExpTimeZoneId = TIME_ZONE_ID_UNKNOWN;
+    }
+    else
+    {
+        /* FIXME: Calculate transition dates */
+
+        /* Set bias and ID */
+        ExpTimeZoneBias.QuadPart = ((LONGLONG)(ExpTimeZoneInfo.Bias +
+                                               ExpTimeZoneInfo.StandardBias)) *
+                                               TICKSPERMINUTE;
+        ExpTimeZoneId = TIME_ZONE_ID_STANDARD;
+    }
+
+    /* Change it for user-mode applications */
+    SharedUserData->TimeZoneBias.High1Time = ExpTimeZoneBias.u.HighPart;
+    SharedUserData->TimeZoneBias.High2Time = ExpTimeZoneBias.u.HighPart;
+    SharedUserData->TimeZoneBias.LowPart = ExpTimeZoneBias.u.LowPart;
+    SharedUserData->TimeZoneId = ExpTimeZoneId;
 
-  /* FIXME: Read time zone information from the registry */
+    /* Convert boot time from local time to UTC */
+    SystemBootTime.QuadPart += ExpTimeZoneBias.QuadPart;
 
+    /* Convert system time from local time to UTC */
+    do
+    {
+        CurrentTime.u.HighPart = SharedUserData->SystemTime.High1Time;
+        CurrentTime.u.LowPart = SharedUserData->SystemTime.LowPart;
+    } while (CurrentTime.u.HighPart != SharedUserData->SystemTime.High2Time);
+
+    /* Change it for user-mode applications */
+    CurrentTime.QuadPart += ExpTimeZoneBias.QuadPart;
+    SharedUserData->SystemTime.LowPart = CurrentTime.u.LowPart;
+    SharedUserData->SystemTime.High1Time = CurrentTime.u.HighPart;
+    SharedUserData->SystemTime.High2Time = CurrentTime.u.HighPart;
 }
 
+NTSTATUS
+ExpSetTimeZoneInformation(PTIME_ZONE_INFORMATION TimeZoneInformation)
+{
+    LARGE_INTEGER LocalTime, SystemTime;
+    TIME_FIELDS TimeFields;
+    DPRINT("ExpSetTimeZoneInformation() called\n");
+
+    DPRINT("Old time zone bias: %d minutes\n", ExpTimeZoneInfo.Bias);
+    DPRINT("Old time zone standard bias: %d minutes\n",
+            ExpTimeZoneInfo.StandardBias);
+    DPRINT("New time zone bias: %d minutes\n", TimeZoneInformation->Bias);
+    DPRINT("New time zone standard bias: %d minutes\n",
+            TimeZoneInformation->StandardBias);
+
+    /* Get the local time */
+    HalQueryRealTimeClock(&TimeFields);
+    RtlTimeFieldsToTime(&TimeFields, &LocalTime);
+
+    /* FIXME: Calculate transition dates */
+
+    /* Calculate the bias and set the ID */
+    ExpTimeZoneBias.QuadPart = ((LONGLONG)(TimeZoneInformation->Bias +
+                                           TimeZoneInformation->StandardBias)) *
+                                           TICKSPERMINUTE;
+    ExpTimeZoneId = TIME_ZONE_ID_STANDARD;
+
+    /* Copy the timezone information */
+    RtlMoveMemory(&ExpTimeZoneInfo,
+                  TimeZoneInformation,
+                  sizeof(TIME_ZONE_INFORMATION));
+
+    /* Set the new time zone information */
+    SharedUserData->TimeZoneBias.High1Time = ExpTimeZoneBias.u.HighPart;
+    SharedUserData->TimeZoneBias.High2Time = ExpTimeZoneBias.u.HighPart;
+    SharedUserData->TimeZoneBias.LowPart = ExpTimeZoneBias.u.LowPart;
+    SharedUserData->TimeZoneId = ExpTimeZoneId;
+
+    DPRINT("New time zone bias: %I64d minutes\n",
+            ExpTimeZoneBias.QuadPart / TICKSPERMINUTE);
+
+    /* Calculate the new system time */
+    ExLocalTimeToSystemTime(&LocalTime, &SystemTime);
+
+    /* Set the new system time */
+    KiSetSystemTime(&SystemTime);
 
-NTSTATUS STDCALL
-NtSetSystemTime (IN    PLARGE_INTEGER  UnsafeNewSystemTime,
-                OUT    PLARGE_INTEGER  UnsafeOldSystemTime     OPTIONAL)
-     /*
-      * FUNCTION: Sets the system time.
-      * PARAMETERS:
-      *        NewTime - Points to a variable that specified the new time
-      *        of day in the standard time format.
-      *        OldTime - Optionally points to a variable that receives the
-      *        old time of day in the standard time format.
-      * RETURNS: Status
-      */
+    /* Return success */
+    DPRINT("ExpSetTimeZoneInformation() done\n");
+    return STATUS_SUCCESS;
+}
+
+/*
+ * FUNCTION: Sets the system time.
+ * PARAMETERS:
+ *        NewTime - Points to a variable that specified the new time
+ *        of day in the standard time format.
+ *        OldTime - Optionally points to a variable that receives the
+ *        old time of day in the standard time format.
+ * RETURNS: Status
+ */
+NTSTATUS
+NTAPI
+NtSetSystemTime(IN PLARGE_INTEGER SystemTime,
+                OUT PLARGE_INTEGER PreviousTime OPTIONAL)
 {
-  NTSTATUS Status;
-  LARGE_INTEGER OldSystemTime;
-  LARGE_INTEGER NewSystemTime;
+    LARGE_INTEGER OldSystemTime;
+    LARGE_INTEGER NewSystemTime;
+    LARGE_INTEGER LocalTime;
+    TIME_FIELDS TimeFields;
+    KPROCESSOR_MODE PreviousMode = ExGetPreviousMode();
+    NTSTATUS Status = STATUS_SUCCESS;
+    PAGED_CODE();
 
-  /* FIXME: Check for SeSystemTimePrivilege */
+    /* Check if we were called from user-mode */
+    if(PreviousMode != KernelMode)
+    {
+        _SEH_TRY
+        {
+            /* Verify the time pointers */
+            NewSystemTime = ProbeForReadLargeInteger(SystemTime);
+            if(PreviousTime) ProbeForWriteLargeInteger(PreviousTime);
+        }
+        _SEH_EXCEPT(_SEH_ExSystemExceptionFilter)
+        {
+            Status = _SEH_GetExceptionCode();
+        }
+        _SEH_END;
 
-  Status = MmCopyFromCaller(&NewSystemTime, UnsafeNewSystemTime,
-                           sizeof(NewSystemTime));
-  if (!NT_SUCCESS(Status))
+        /* If the pointers were invalid, bail out */
+        if(!NT_SUCCESS(Status)) return Status;
+    }
+    else
     {
-      return(Status);
+        /* Reuse the pointer */
+        NewSystemTime = *SystemTime;
     }
-  
-  if (UnsafeOldSystemTime != NULL)
+
+    /* Make sure we have permission to change the time */
+    if(!SeSinglePrivilegeCheck(SeSystemtimePrivilege, PreviousMode))
     {
-      KeQuerySystemTime(&OldSystemTime);
+        DPRINT1("NtSetSystemTime: Caller requires the "
+                "SeSystemtimePrivilege privilege!\n");
+        return STATUS_PRIVILEGE_NOT_HELD;
     }
-  HalSetRealTimeClock ((PTIME_FIELDS)&NewSystemTime);
 
-  if (UnsafeOldSystemTime != NULL)
+    /* Check if caller wants the old time */
+    if(PreviousTime) KeQuerySystemTime(&OldSystemTime);
+
+    /* Convert the time and set it in HAL */
+    ExSystemTimeToLocalTime(&NewSystemTime, &LocalTime);
+    RtlTimeToTimeFields(&LocalTime, &TimeFields);
+    HalSetRealTimeClock(&TimeFields);
+
+    /* Now set system time */
+    KiSetSystemTime(&NewSystemTime);
+
+    /* Check if caller wanted previous time */
+    if(PreviousTime)
     {
-      Status = MmCopyToCaller(UnsafeOldSystemTime, &OldSystemTime,
-                             sizeof(OldSystemTime));
-      if (!NT_SUCCESS(Status))
-       {
-         return(Status);
-       }
+        /* Enter SEH Block for return */
+        _SEH_TRY
+        {
+            /* Return the previous time */
+            *PreviousTime = OldSystemTime;
+        }
+        _SEH_EXCEPT(_SEH_ExSystemExceptionFilter)
+        {
+            Status = _SEH_GetExceptionCode();
+        }
+        _SEH_END;
     }
-  return(STATUS_SUCCESS);
-}
 
+    /* Return status */
+    return Status;
+}
 
-NTSTATUS STDCALL
-NtQuerySystemTime (OUT TIME* UnsafeCurrentTime)
-     /*
-      * FUNCTION: Retrieves the system time.
-      * PARAMETERS:
-      *          CurrentTime - Points to a variable that receives the current
-      *          time of day in the standard time format.
-      */
+/*
+ * FUNCTION: Retrieves the system time.
+ * PARAMETERS:
+ *          CurrentTime - Points to a variable that receives the current
+ *          time of day in the standard time format.
+ */
+NTSTATUS
+NTAPI
+NtQuerySystemTime(OUT PLARGE_INTEGER SystemTime)
 {
-  LARGE_INTEGER CurrentTime;
-  NTSTATUS Status;
+    KPROCESSOR_MODE PreviousMode = ExGetPreviousMode();
+    NTSTATUS Status = STATUS_SUCCESS;
+    PAGED_CODE();
 
-  KeQuerySystemTime(&CurrentTime);
-  Status = MmCopyToCaller(UnsafeCurrentTime, &CurrentTime,
-                         sizeof(CurrentTime));
-  if (!NT_SUCCESS(Status))
+    /* Check if we were called from user-mode */
+    if(PreviousMode != KernelMode)
     {
-      return(Status);
+        _SEH_TRY
+        {
+            /* Verify the time pointer */
+            ProbeForWriteLargeInteger(SystemTime);
+
+            /*
+             * It's safe to pass the pointer directly to KeQuerySystemTime as
+             * it's just a basic copy to this pointer. If it raises an
+             * exception nothing dangerous can happen!
+             */
+            KeQuerySystemTime(SystemTime);
+        }
+        _SEH_EXCEPT(_SEH_ExSystemExceptionFilter)
+        {
+        Status = _SEH_GetExceptionCode();
+        }
+        _SEH_END;
+    }
+    else
+    {
+        /* Query the time directly */
+        KeQuerySystemTime(SystemTime);
     }
-  return STATUS_SUCCESS;
-}
 
+    /* Return status to caller */
+    return Status;
+}
 
+/*
+ * @implemented
+ */
 VOID
-STDCALL
-ExLocalTimeToSystemTime (
-       PLARGE_INTEGER  LocalTime, 
-       PLARGE_INTEGER  SystemTime
-       )
+NTAPI
+ExLocalTimeToSystemTime(PLARGE_INTEGER LocalTime,
+                        PLARGE_INTEGER SystemTime)
 {
-   SystemTime->QuadPart = LocalTime->QuadPart +
-                          _SystemTimeZoneInfo.Bias * TICKSPERMINUTE;
+    SystemTime->QuadPart = LocalTime->QuadPart + ExpTimeZoneBias.QuadPart;
 }
 
+/*
+ * @unimplemented
+ */
+ULONG
+NTAPI
+ExSetTimerResolution(IN ULONG DesiredTime,
+                     IN BOOLEAN SetResolution)
+{
+    UNIMPLEMENTED;
+    return 0;
+}
 
+/*
+ * @implemented
+ */
 VOID
-STDCALL
-ExSystemTimeToLocalTime (
-       PLARGE_INTEGER  SystemTime,
-       PLARGE_INTEGER  LocalTime
-       )
+NTAPI
+ExSystemTimeToLocalTime(PLARGE_INTEGER SystemTime,
+                        PLARGE_INTEGER LocalTime)
 {
-   LocalTime->QuadPart = SystemTime->QuadPart -
-                         _SystemTimeZoneInfo.Bias * TICKSPERMINUTE;
+    LocalTime->QuadPart = SystemTime->QuadPart - ExpTimeZoneBias.QuadPart;
 }
 
 /* EOF */