diff --git a/ntoskrnl/ex/time.c b/ntoskrnl/ex/time.c index 44ce39d9ad..0902b2cb46 100644 --- a/ntoskrnl/ex/time.c +++ b/ntoskrnl/ex/time.c @@ -28,6 +28,336 @@ ERESOURCE ExpTimeRefreshLock; ULONG ExpKernelResolutionCount = 0; ULONG ExpTimerResolutionCount = 0; +/* Beginning of Additions for Daylight Time Testing */ + +typedef struct _FILETIME { + ULONG dwLowDateTime; + ULONG dwHighDateTime; +} FILETIME, *PFILETIME; + +typedef struct _SYSTEMTIME { + WCHAR wYear; + WCHAR wMonth; + WCHAR wDayOfWeek; + WCHAR wDay; + WCHAR wHour; + WCHAR wMinute; + WCHAR wSecond; + WCHAR wMilliseconds; +} SYSTEMTIME,*LPSYSTEMTIME,*PSYSTEMTIME; + +typedef struct _TIME_ZONE_INFORMATION { + LONG Bias; + WCHAR StandardName[32]; + SYSTEMTIME StandardDate; + LONG StandardBias; + WCHAR DaylightName[32]; + SYSTEMTIME DaylightDate; + LONG DaylightBias; +} TIME_ZONE_INFORMATION; + +static const int MonthLengths[2][12] = +{ + { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }, + { 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 } +}; + +/* STATIC FUNCTIONS **********************************************************/ + +static inline int IsLeapYear(int Year) +{ + return Year % 4 == 0 && (Year % 100 != 0 || Year % 400 == 0) ? 1 : 0; +} + +VOID +GetSystemTimeAsFileTime1(OUT PFILETIME lpFileTime) +{ + LARGE_INTEGER SystemTime; + + do + { + SystemTime.HighPart = SharedUserData->SystemTime.High1Time; + SystemTime.LowPart = SharedUserData->SystemTime.LowPart; + } + while (SystemTime.HighPart != SharedUserData->SystemTime.High2Time); + + lpFileTime->dwLowDateTime = SystemTime.LowPart; + lpFileTime->dwHighDateTime = SystemTime.HighPart; +} + +/*********************************************************************** + * TIME1_DayLightCompareDate + * + * Compares two dates without looking at the year. + * + * PARAMS + * date [in] The local time to compare. + * compareDate [in] The daylight savings begin or end date. + * + * RETURNS + * + * -1 if date < compareDate + * 0 if date == compareDate + * 1 if date > compareDate + * -2 if an error occurs + */ +static int +TIME1_DayLightCompareDate(const SYSTEMTIME *date, const TIME_FIELDS *compareDate) +{ + int limit_day, dayinsecs; + + if (date->wMonth < compareDate->Month) + return -1; /* We are in a month before the date limit. */ + + if (date->wMonth > compareDate->Month) + return 1; /* We are in a month after the date limit. */ + + /* if year is 0 then date is in day-of-week format, otherwise + * it's absolute date. + */ + if (compareDate->Year == 0) + { + ULONG First; + /* compareDate->Day is interpreted as number of the week in the month + * 5 means: the last week in the month */ + int weekofmonth = compareDate->Day; + /* calculate the day of the first DayOfWeek in the month */ + First = ( 6 + compareDate->Weekday - date->wDayOfWeek + date->wDay + ) % 7 + 1; + limit_day = First + 7 * (weekofmonth - 1); + /* check needed for the 5th weekday of the month */ + if(limit_day > MonthLengths[date->wMonth==2 && IsLeapYear(date->wYear)] + [date->wMonth - 1]) + limit_day -= 7; + } + else + { + limit_day = compareDate->Day; + } + + /* convert to seconds */ + limit_day = ((limit_day * 24 + compareDate->Hour) * 60 + + compareDate->Minute ) * 60; + dayinsecs = ((date->wDay * 24 + date->wHour) * 60 + + date->wMinute ) * 60 + date->wSecond; + /* and compare */ + return dayinsecs < limit_day ? -1 : + dayinsecs > limit_day ? 1 : + 0; /* date is equal to the date limit. */ +} + + +BOOLEAN +FileTimeToSystemTime1(IN CONST FILETIME *lpFileTime, + OUT LPSYSTEMTIME lpSystemTime) +{ + TIME_FIELDS TimeFields; + LARGE_INTEGER liTime; + + liTime.u.LowPart = lpFileTime->dwLowDateTime; + liTime.u.HighPart = lpFileTime->dwHighDateTime; + if (liTime.QuadPart < 0) + { +// SetLastError(ERROR_INVALID_PARAMETER); + return FALSE; + } + + RtlTimeToTimeFields(&liTime, &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; + + return TRUE; +} + + +#define TIME_ZONE_ID_UNKNOWN 0 +#define TIME_ZONE_ID_STANDARD 1 +#define TIME_ZONE_ID_DAYLIGHT 2 +#define TIME_ZONE_ID_INVALID 0xFFFFFFFF + + +#define TICKSPERMIN 600000000 + +#define LL2FILETIME( ll, pft )\ + (pft)->dwLowDateTime = (INT)(ll); \ + (pft)->dwHighDateTime = (INT)((ll) >> 32); +#define FILETIME2LL( pft, ll) \ + ll = (((LONGLONG)((pft)->dwHighDateTime))<<32) + (pft)-> dwLowDateTime ; + + +/*********************************************************************** + * TIME1_CompTimeZoneID + * + * Computes the local time bias for a given time and time zone. + * + * PARAMS + * pTZinfo [in] The time zone data. + * lpFileTime [in] The system or local time. + * islocal [in] it is local time. + * + * RETURNS + * TIME_ZONE_ID_INVALID An error occurred (-1) + * TIME_ZONE_ID_UNKNOWN There are no transition time known (0) + * TIME_ZONE_ID_STANDARD Current time is standard time (1) + * TIME_ZONE_ID_DAYLIGHT Current time is daylight savings time (2) + */ +static +ULONG +TIME1_CompTimeZoneID( const RTL_TIME_ZONE_INFORMATION *pTZinfo, FILETIME *lpFileTime, BOOLEAN islocal ) +{ + int ret, year; + BOOLEAN beforeStandardDate, afterDaylightDate; + ULONG retval = TIME_ZONE_ID_INVALID; + long long int llTime = 0; /* initialized to prevent gcc complaining */ + long long int TTime = 0; /* Test Time */ + SYSTEMTIME SysTime; + FILETIME ftTemp; + +DPRINT("Entering TIME1_CompTimeZoneID().\n"); + + + if (pTZinfo->DaylightDate.Month != 0) + { + /* if year is 0 then date is in day-of-week format, otherwise + * it's absolute date. + */ + if (pTZinfo->StandardDate.Month == 0 || + (pTZinfo->StandardDate.Year == 0 && + (pTZinfo->StandardDate.Day<1 || + pTZinfo->StandardDate.Day>5 || + pTZinfo->DaylightDate.Day<1 || + pTZinfo->DaylightDate.Day>5))) + { + DPRINT("Error Invalid Parameter.\n"); + return TIME_ZONE_ID_INVALID; + } + + if (!islocal) { + + FILETIME2LL( lpFileTime, llTime ); + + DPRINT("llTime is '%I64d'.\n", llTime); + + llTime -= pTZinfo->Bias * (LONGLONG)TICKSPERMIN; + LL2FILETIME( llTime, &ftTemp) + lpFileTime = &ftTemp; + FILETIME2LL( lpFileTime, TTime); + + DPRINT("lpFileTime after subtracting TZ bias is '%I64d'.\n", TTime); + } + + FileTimeToSystemTime1(lpFileTime, &SysTime); + year = SysTime.wYear; + + DPRINT("SysTime.wYear is '%d'.\n", SysTime.wYear); + + TTime = (LONGLONG)pTZinfo->DaylightBias * (LONGLONG)TICKSPERMIN * (LONGLONG)-1; + DPRINT1("pTZinfo->DaylightBias is '%I64d'.\n", TTime); + + if (!islocal) { + llTime = llTime + TTime; + + DPRINT("llTime after subtracting Daylight bias is '%I64d'.\n", llTime); + + LL2FILETIME( llTime, &ftTemp) + lpFileTime = &ftTemp; // Added + FILETIME2LL( lpFileTime, TTime); + DPRINT("lpFileTime after subtracting Daylight bias is '%I64d'.\n", TTime); + FileTimeToSystemTime1(lpFileTime, &SysTime); + } + + /* check for daylight savings */ + DPRINT("SysTime.wYear is '%d' and year is '%d'.\n", SysTime.wYear, year); + if(year == SysTime.wYear) + { + ret = TIME1_DayLightCompareDate( &SysTime, &pTZinfo->StandardDate); + DPRINT("Return from TIME1_DayLightCompareDate is %d.\n", ret); + + if (ret == -2) + return TIME_ZONE_ID_INVALID; + + beforeStandardDate = ret < 0; + } + else + beforeStandardDate = SysTime.wYear < year; + + if (!islocal) + { + llTime -= ( pTZinfo->StandardBias - pTZinfo->DaylightBias ) + * (LONGLONG)TICKSPERMIN; + LL2FILETIME( llTime, &ftTemp) + FileTimeToSystemTime1(lpFileTime, &SysTime); + } + + if(year == SysTime.wYear) + { + ret = TIME1_DayLightCompareDate( &SysTime, &pTZinfo->DaylightDate); + if (ret == -2) + return TIME_ZONE_ID_INVALID; + + afterDaylightDate = ret >= 0; + } + else + afterDaylightDate = SysTime.wYear > year; + + DPRINT("beforeStandardDate is %d and afterDaylightDate is %d.\n", beforeStandardDate, afterDaylightDate); + + retval = TIME_ZONE_ID_STANDARD; + if( pTZinfo->DaylightDate.Month < pTZinfo->StandardDate.Month ) + { + /* Northern hemisphere */ + if( beforeStandardDate && afterDaylightDate ) + retval = TIME_ZONE_ID_DAYLIGHT; + } + else /* Down south */ + if( beforeStandardDate || afterDaylightDate ) + retval = TIME_ZONE_ID_DAYLIGHT; + } + else + /* No transition date */ + retval = TIME_ZONE_ID_UNKNOWN; + DPRINT("Time Zone (-1=BAD, 0=UNK, 1=STD, 2=DLT) is %d.\n", retval); + + return retval; +} + +/*********************************************************************** + * TIME1_TimeZoneID + * + * Calculates whether daylight savings is on now. + * + * PARAMS + * pTzi [in] Timezone info. + * + * RETURNS + * TIME_ZONE_ID_INVALID An error occurred + * TIME_ZONE_ID_UNKNOWN There are no transition time known + * TIME_ZONE_ID_STANDARD Current time is standard time + * TIME_ZONE_ID_DAYLIGHT Current time is daylight savings time + */ +static ULONG TIME1_ZoneID( const RTL_TIME_ZONE_INFORMATION *pTzi ) +{ + FILETIME ftTime; + + DPRINT("TIME1_ZoneID()\n"); + + GetSystemTimeAsFileTime1( &ftTime); + + DPRINT("File Time High is %d and File Time Low is %d.\n", ftTime.dwHighDateTime, ftTime.dwLowDateTime); + + return TIME1_CompTimeZoneID( pTzi, &ftTime, FALSE); +} + +/* End of Additions for Daylight Time Testing */ + + /* FUNCTIONS ****************************************************************/ /*++ @@ -227,6 +557,7 @@ ExRefreshTimeZoneInformation(IN PLARGE_INTEGER CurrentBootTime) { LARGE_INTEGER CurrentTime; NTSTATUS Status; + CHAR tzid; // Time Zone ID /* Read time zone information from the registry */ Status = RtlQueryTimeZoneInformation(&ExpTimeZoneInfo); @@ -239,12 +570,20 @@ ExRefreshTimeZoneInformation(IN PLARGE_INTEGER CurrentBootTime) } else { - /* FIXME: Calculate transition dates */ + /* Calculate transition dates */ /* Set bias and ID */ ExpTimeZoneBias.QuadPart = ((LONGLONG)(ExpTimeZoneInfo.Bias + ExpTimeZoneInfo.StandardBias)) * TICKSPERMINUTE; + + tzid =(TIME1_ZoneID(&ExpTimeZoneInfo)); + DPRINT1("tzid is %d.\n", tzid); + + /* If Daylight Savings Time this subtracts an hour from the Time Zone Bias making it an hour later. */ + if (tzid == 2) + ExpTimeZoneBias.QuadPart += (LONGLONG)ExpTimeZoneInfo.DaylightBias * TICKSPERMINUTE; + ExpTimeZoneId = TIME_ZONE_ID_STANDARD; } @@ -279,6 +618,8 @@ ExpSetTimeZoneInformation(PRTL_TIME_ZONE_INFORMATION TimeZoneInformation) { LARGE_INTEGER LocalTime, SystemTime, OldTime; TIME_FIELDS TimeFields; + CHAR tzid; // Time Zone ID + DPRINT("ExpSetTimeZoneInformation() called\n"); DPRINT("Old time zone bias: %d minutes\n", ExpTimeZoneInfo.Bias); @@ -292,12 +633,20 @@ ExpSetTimeZoneInformation(PRTL_TIME_ZONE_INFORMATION TimeZoneInformation) HalQueryRealTimeClock(&TimeFields); RtlTimeFieldsToTime(&TimeFields, &LocalTime); - /* FIXME: Calculate transition dates */ + /* Calculate transition dates */ /* Calculate the bias and set the ID */ ExpTimeZoneBias.QuadPart = ((LONGLONG)(TimeZoneInformation->Bias + TimeZoneInformation->StandardBias)) * TICKSPERMINUTE; + + tzid =(TIME1_ZoneID(&ExpTimeZoneInfo)); + DPRINT1("tzid is %d.\n", tzid); + + // If Daylight Savings Time this subtracts an hour from the Time Zone Bias making it an hour later. + if (tzid == 2) + ExpTimeZoneBias.QuadPart += (LONGLONG)ExpTimeZoneInfo.DaylightBias * TICKSPERMINUTE; + ExpTimeZoneId = TIME_ZONE_ID_STANDARD; /* Copy the timezone information */