-/* $Id: time.c,v 1.18 2003/07/11 01:23:14 royce 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;
- TIME_FIELDS TimeFields;
+ 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;
}
- RtlTimeToTimeFields (&NewSystemTime, &TimeFields);
- HalSetRealTimeClock (&TimeFields);
- 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 PLARGE_INTEGER 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();
+
+ /* Check if we were called from user-mode */
+ if(PreviousMode != KernelMode)
+ {
+ _SEH_TRY
+ {
+ /* Verify the time pointer */
+ ProbeForWriteLargeInteger(SystemTime);
- KeQuerySystemTime(&CurrentTime);
- Status = MmCopyToCaller(UnsafeCurrentTime, &CurrentTime,
- sizeof(CurrentTime));
- if (!NT_SUCCESS(Status))
+ /*
+ * 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
{
- return(Status);
+ /* 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 */