windows-nt/Source/XPSP1/NT/base/ntsetup/win95upg/w95upg/sysmig/timezone.c
2020-09-26 16:20:57 +08:00

780 lines
17 KiB
C

/*++
Copyright (c) 1997 Microsoft Corporation
Module Name:
timezone.c
Abstract:
This module is responsible for managing the mapping of timezones from windows 9x to
windows Nt. Because of the fact that the timezone strings are different between the
several different platforms (Win9x Win98 WinNt) and because it is important to end
users that there timezone setting accurately reflect there geographic location, a
somewhat complex method of mapping timezones is needed.
Author:
Marc R. Whitten (marcw) 09-Jul-1998
Revision History:
marcw 18-Aug-1998 Added timezone enum, support for retaining
fixed matches.
--*/
#include "pch.h"
#define DBG_TIMEZONE "TimeZone"
#define S_FIRSTBOOT TEXT("!!!First Boot!!!")
TCHAR g_TimeZoneMap[20] = TEXT("");
TCHAR g_CurrentTimeZone[MAX_TIMEZONE] = TEXT("");
BOOL g_TimeZoneMapped = FALSE;
//
// Variable used by tztest tool.
//
HANDLE g_TzTestHiveSftInf = NULL;
BOOL
pBuildNtTimeZoneData (
VOID
)
/*++
Routine Description:
pBuildNtTimeZone data reads the timezone information that is stored in
hivesft.inf and organizes it into memdb. This data is used to look up
display names of timezone indices.
Arguments:
None.
Return Value:
TRUE if the function completes successfully, FALSE
otherwise.
--*/
{
HINF inf = INVALID_HANDLE_VALUE;
INFSTRUCT is = INITINFSTRUCT_POOLHANDLE;
BOOL rSuccess = FALSE;
PTSTR key = NULL;
PTSTR value = NULL;
PTSTR desc = NULL;
PTSTR index = NULL;
BOOL timeZonesFound = FALSE;
TCHAR paddedIndex[20];
PTSTR p = NULL;
UINT i = 0;
UINT count = 0;
if (!g_TzTestHiveSftInf) {
//
// First, Read data from hivesft.inf.
//
inf = InfOpenInfInAllSources (S_HIVESFT_INF);
}
else {
inf = g_TzTestHiveSftInf;
}
if (inf == INVALID_HANDLE_VALUE) {
LOG ((LOG_ERROR, "Cannot load hivesoft.inf. Unable to build timezone information." ));
return FALSE;
}
if (InfFindFirstLine (inf, S_ADDREG, NULL, &is)) {
do {
//
// Cycle through all of the lines looking for timezone information.
//
key = InfGetStringField (&is, 2);
if (key && IsPatternMatch (TEXT("*Time Zones*"), key)) {
//
// Remember that we have found the first timezone entry.
//
timeZonesFound = TRUE;
//
// Now, get value. We care about "display" and "index"
//
value = InfGetStringField (&is, 3);
if (!value) {
continue;
}
if (StringIMatch (value, S_DISPLAY)) {
//
// display string found.
//
desc = InfGetStringField (&is, 5);
} else if (StringIMatch (value, S_INDEX)) {
//
// index value found.
//
index = InfGetStringField (&is, 5);
}
if (index && desc) {
//
// Make sure the index is 0 padded.
//
count = 3 - TcharCount (index);
p = paddedIndex;
for (i=0; i<count; i++) {
*p = TEXT('0');
p = _tcsinc (p);
}
StringCopy (p, index);
//
// we have all the information we need. Save this entry into memdb.
//
MemDbSetValueEx (MEMDB_CATEGORY_NT_TIMEZONES, paddedIndex, desc, NULL, 0, NULL);
index = NULL;
desc = NULL;
}
} else {
//
// Keep memory usage low.
//
InfResetInfStruct (&is);
if (key) {
if (timeZonesFound) {
//
// We have gathered all of the timezone information from hivesft.inf
// we can abort our loop at this point.
//
break;
}
}
}
} while (InfFindNextLine(&is));
} ELSE_DEBUGMSG ((DBG_ERROR, "[%s] not found in hivesft.inf!",S_ADDREG));
//
// Clean up resources
//
InfCleanUpInfStruct (&is);
InfCloseInfFile (inf);
return TRUE;
}
BOOL
pBuild9xTimeZoneData (
VOID
)
/*++
Routine Description:
pBuild9xTimeZone Data is responsible for reading the time zone information
that is stored in win95upg.inf and organizing it into memdb. The timezone
enumeration routines then use this data in order to find all Nt timezones
that can map to a particular 9x timezone.
Arguments:
None.
Return Value:
TRUE if the data is successfully stored in memdb, FALSE
otherwise.
--*/
{
INFSTRUCT is = INITINFSTRUCT_POOLHANDLE;
PTSTR desc = NULL;
PTSTR index = NULL;
UINT count = 0;
PTSTR p = NULL;
//
// Now, read in information about win9x registry mappings.
//
if (InfFindFirstLine (g_Win95UpgInf, S_TIMEZONEMAPPINGS, NULL, &is)) {
do {
//
// Get the display name and matching index(es) for this timezone.
//
desc = InfGetStringField (&is,0);
index = InfGetStringField (&is,1);
//
// Enumerate the indices and save them into memdb.
//
count = 0;
while (index) {
p = _tcschr (index, TEXT(','));
if (p) {
*p = 0;
}
MemDbSetValueEx (
MEMDB_CATEGORY_9X_TIMEZONES,
desc,
MEMDB_FIELD_INDEX,
index,
0,
NULL
);
count++;
if (p) {
index = _tcsinc(p);
}
else {
//
// Save away the count of possible nt timezones for this 9x timezone.
//
MemDbSetValueEx (
MEMDB_CATEGORY_9X_TIMEZONES,
desc,
MEMDB_FIELD_COUNT,
NULL,
count,
NULL
);
index = NULL;
}
}
} while (InfFindNextLine (&is));
}
//
// Clean up resources.
//
InfCleanUpInfStruct (&is);
return TRUE;
}
BOOL
pGetCurrentTimeZone (
VOID
)
/*++
Routine Description:
pGetCurrentTimeZone retrieves the user's timezone from the windows 9x
registry. The enumeration routines use this timezone in order to enumerate
the possible matching timezones in the INF.
Arguments:
None.
Return Value:
TRUE if the function successfully retrieves the user's password, FALSE
otherwise.
--*/
{
BOOL rSuccess = TRUE;
PCTSTR displayName = NULL;
REGTREE_ENUM eTree;
PCTSTR valueName = NULL;
PCTSTR value = NULL;
PCTSTR curTimeZone = NULL;
HKEY hKey = NULL;
//
// Get the current timezone name, and set the valuename to the correct string.
//
hKey = OpenRegKeyStr (S_TIMEZONEINFORMATION);
if (!hKey) {
LOG ((LOG_ERROR, "Unable to open %s key.", S_TIMEZONEINFORMATION));
return FALSE;
}
if ((curTimeZone = GetRegValueString (hKey, S_STANDARDNAME)) && !StringIMatch (curTimeZone, S_FIRSTBOOT)) {
//
// standard time. We need to look under the "STD" value to match this.
//
valueName = S_STD;
} else if ((curTimeZone = GetRegValueString (hKey, S_DAYLIGHTNAME)) && !StringIMatch (curTimeZone, S_FIRSTBOOT)) {
//
// Daylight Savings Time. We need to look under the "DLT" value to match this.
//
valueName = S_DLT;
} else {
CloseRegKey (hKey);
hKey = OpenRegKeyStr (TEXT("HKLM\\Software\\Microsoft\\Windows\\CurrentVersion\\Time Zones"));
if (hKey) {
if (curTimeZone = GetRegValueString (hKey, TEXT(""))) {
valueName = S_STD;
}
}
if (!valueName) {
//
// No timezone found!
//
DEBUGMSG((DBG_WHOOPS,"Unable to get Timezone name..User will have to enter timezone in GUI mode."));
return FALSE;
}
}
__try {
//
// Now we have to search through the timezones key and find the key that has a value equal to
// the current timezone name. A big pain.
//
if (EnumFirstRegKeyInTree (&eTree, S_TIMEZONES)) {
do {
//
// For each subkey, we must look for the string in valueName and
// see if it matches.
//
value = GetRegValueString (eTree.CurrentKey->KeyHandle, valueName);
if (value) {
if (StringIMatch (value, curTimeZone)) {
//
// We found the key we were looking for and we can finally
// gather the data we need.
//
displayName = GetRegValueString (eTree.CurrentKey->KeyHandle, S_DISPLAY);
if (!displayName) {
DEBUGMSG((DBG_WHOOPS,"Error! Timezone key found, but no Display value!"));
AbortRegKeyTreeEnum (&eTree);
rSuccess = FALSE;
__leave;
}
//
// Save away the current Timezone and leave the loop. We are done.
//
StringCopy (g_CurrentTimeZone, displayName);
AbortRegKeyTreeEnum (&eTree);
break;
}
MemFree (g_hHeap, 0, value);
value = NULL;
}
} while (EnumNextRegKeyInTree (&eTree));
}
} __finally {
if (curTimeZone) {
MemFree (g_hHeap, 0, curTimeZone);
}
if (value) {
MemFree (g_hHeap, 0, value);
}
if (displayName) {
MemFree (g_hHeap, 0, displayName);
}
CloseRegKey (hKey);
}
return rSuccess;
}
BOOL
pInitTimeZoneData (
VOID
)
/*++
Routine Description:
pInitTimeZoneData is responsible for performing all of the initialization
necessary to use the time zone enumeration routines.
Arguments:
None.
Return Value:
TRUE if initialization completes successfully, FALSE otherwise.
--*/
{
BOOL rSuccess = TRUE;
//
// First, fill memdb with timezone
// information regarding winnt and win9x
// (from hivesft.inf and win95upg.inf)
//
if (!pBuildNtTimeZoneData ()) {
LOG ((LOG_ERROR, "Unable to gather nt timezone information."));
rSuccess = FALSE;
}
if (!pBuild9xTimeZoneData ()) {
LOG ((LOG_ERROR, "Unable to gather 9x timezone information."));
rSuccess = FALSE;
}
//
// Next, get the user's timezone.
//
if (!pGetCurrentTimeZone ()) {
LOG ((LOG_ERROR, "Failure trying to retrieve timezone information."));
rSuccess = FALSE;
}
return rSuccess;
}
BOOL
pEnumFirstNtTimeZone (
OUT PTIMEZONE_ENUM EnumPtr
)
{
BOOL rSuccess = FALSE;
PTSTR p;
EnumPtr -> MapCount = 0;
if (MemDbEnumFirstValue (&(EnumPtr -> Enum), MEMDB_CATEGORY_NT_TIMEZONES"\\*", MEMDB_ALL_SUBLEVELS, MEMDB_ENDPOINTS_ONLY)) {
do {
EnumPtr -> MapCount++;
} while (MemDbEnumNextValue (&(EnumPtr -> Enum)));
}
else {
return FALSE;
}
MemDbEnumFirstValue (&(EnumPtr -> Enum), MEMDB_CATEGORY_NT_TIMEZONES"\\*", MEMDB_ALL_SUBLEVELS, MEMDB_ENDPOINTS_ONLY);
p = _tcschr (EnumPtr->Enum.szName,TEXT('\\'));
if (!p) {
return FALSE;
}
*p = 0;
EnumPtr -> MapIndex = EnumPtr -> Enum.szName;
StringCopy (EnumPtr -> NtTimeZone, _tcsinc(p));
return TRUE;
}
BOOL
pEnumNextNtTimeZone (
OUT PTIMEZONE_ENUM EnumPtr
)
{
PTSTR p;
if (!MemDbEnumNextValue(&EnumPtr -> Enum)) {
return FALSE;
}
p = _tcschr (EnumPtr->Enum.szName,TEXT('\\'));
if (!p) {
return FALSE;
}
*p = 0;
EnumPtr -> MapIndex = EnumPtr -> Enum.szName;
StringCopy (EnumPtr -> NtTimeZone, _tcsinc(p));
return TRUE;
}
BOOL
EnumFirstTimeZone (
OUT PTIMEZONE_ENUM EnumPtr,
IN DWORD Flags
)
/*++
Routine Description:
EnumFirstTimeZone/EnumNextTimeZone enumerate the Nt timezones that can match the
user's current Windows 9x time zone. In most cases, there will be only one,
but, in some cases, there can be several.
Arguments:
EnumPtr - A pointer to a valid timezone enumeration structure. This
variable holds the necessary state between timezone enumeration
calls.
Return Value:
TRUE if there are any timezones to enumerate, FALSE otherwise.
--*/
{
BOOL rSuccess = FALSE;
TCHAR key[MEMDB_MAX];
static BOOL firstTime = TRUE;
if (firstTime) {
if (!pInitTimeZoneData ()) {
LOG ((LOG_ERROR, "Error initializing timezone data."));
return FALSE;
}
firstTime = FALSE;
}
MYASSERT (EnumPtr);
EnumPtr -> CurTimeZone = g_CurrentTimeZone;
EnumPtr -> Flags = Flags;
if (Flags & TZFLAG_ENUM_ALL) {
return pEnumFirstNtTimeZone (EnumPtr);
}
if ((Flags & TZFLAG_USE_FORCED_MAPPINGS) && g_TimeZoneMapped) {
//
// We have a force mapping, so mapcount is 1.
//
EnumPtr -> MapCount = 1;
}
else {
//
// Get count of matches.
//
MemDbBuildKey (key, MEMDB_CATEGORY_9X_TIMEZONES, EnumPtr -> CurTimeZone, MEMDB_FIELD_COUNT, NULL);
if (!MemDbGetValue (key, &(EnumPtr -> MapCount))) {
DEBUGMSG ((
DBG_WARNING,
"EnumFirstTimeZone: Could not retrieve count of nt timezone matches from memdb for %s.",
EnumPtr -> CurTimeZone
));
return FALSE;
}
}
DEBUGMSG ((DBG_TIMEZONE, "%d Nt time zones match the win9x timezone %s.", EnumPtr -> MapCount, EnumPtr -> CurTimeZone));
if ((Flags & TZFLAG_USE_FORCED_MAPPINGS) && g_TimeZoneMapped) {
//
// Use the previously forced mapping.
//
EnumPtr -> MapIndex = g_TimeZoneMap;
} else {
//
// Now, enumerate the matching map indexes in memdb.
//
rSuccess = MemDbGetValueEx (
&(EnumPtr -> Enum),
MEMDB_CATEGORY_9X_TIMEZONES,
EnumPtr -> CurTimeZone,
MEMDB_FIELD_INDEX
);
if (!rSuccess) {
return FALSE;
}
EnumPtr -> MapIndex = EnumPtr -> Enum.szName;
}
//
// Get the NT display string for this map index.
//
rSuccess = MemDbGetEndpointValueEx (MEMDB_CATEGORY_NT_TIMEZONES, EnumPtr->MapIndex, NULL, EnumPtr->NtTimeZone);
return rSuccess;
}
BOOL
EnumNextTimeZone (
IN OUT PTIMEZONE_ENUM EnumPtr
)
{
if (EnumPtr -> Flags & TZFLAG_ENUM_ALL) {
return pEnumNextNtTimeZone (EnumPtr);
}
if ((EnumPtr -> Flags & TZFLAG_USE_FORCED_MAPPINGS) && g_TimeZoneMapped) {
return FALSE;
}
if (!MemDbEnumNextValue (&(EnumPtr->Enum))) {
return FALSE;
}
EnumPtr->MapIndex = EnumPtr->Enum.szName;
return MemDbGetEndpointValueEx (MEMDB_CATEGORY_NT_TIMEZONES, EnumPtr->MapIndex, NULL, EnumPtr->NtTimeZone);
}
BOOL
ForceTimeZoneMap (
IN PCTSTR NtTimeZone
)
/*++
Routine Description:
ForceTimeZoneMap forces the mapping of a particular 9x timezone to a
particular Nt timezone. This function is used in cases where there are
multiple nt timezones that could map to a particular 9x timezone.
Arguments:
NtTimeZone - String containing the timezone to force mapping to.
Return Value:
TRUE if the function successfully updated the timezone mapping, FALSE
otherwise.
--*/
{
TIMEZONE_ENUM e;
//
// Find index that matches this timezone.
//
if (EnumFirstTimeZone (&e, TZFLAG_ENUM_ALL)) {
do {
if (StringIMatch (NtTimeZone, e.NtTimeZone)) {
//
// this is the index we need.
//
StringCopy (g_TimeZoneMap, e.MapIndex);
g_TimeZoneMapped = TRUE;
break;
}
} while (EnumNextTimeZone (&e));
}
return TRUE;
}