Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

779 lines
17 KiB

  1. /*++
  2. Copyright (c) 1997 Microsoft Corporation
  3. Module Name:
  4. timezone.c
  5. Abstract:
  6. This module is responsible for managing the mapping of timezones from windows 9x to
  7. windows Nt. Because of the fact that the timezone strings are different between the
  8. several different platforms (Win9x Win98 WinNt) and because it is important to end
  9. users that there timezone setting accurately reflect there geographic location, a
  10. somewhat complex method of mapping timezones is needed.
  11. Author:
  12. Marc R. Whitten (marcw) 09-Jul-1998
  13. Revision History:
  14. marcw 18-Aug-1998 Added timezone enum, support for retaining
  15. fixed matches.
  16. --*/
  17. #include "pch.h"
  18. #define DBG_TIMEZONE "TimeZone"
  19. #define S_FIRSTBOOT TEXT("!!!First Boot!!!")
  20. TCHAR g_TimeZoneMap[20] = TEXT("");
  21. TCHAR g_CurrentTimeZone[MAX_TIMEZONE] = TEXT("");
  22. BOOL g_TimeZoneMapped = FALSE;
  23. //
  24. // Variable used by tztest tool.
  25. //
  26. HANDLE g_TzTestHiveSftInf = NULL;
  27. BOOL
  28. pBuildNtTimeZoneData (
  29. VOID
  30. )
  31. /*++
  32. Routine Description:
  33. pBuildNtTimeZone data reads the timezone information that is stored in
  34. hivesft.inf and organizes it into memdb. This data is used to look up
  35. display names of timezone indices.
  36. Arguments:
  37. None.
  38. Return Value:
  39. TRUE if the function completes successfully, FALSE
  40. otherwise.
  41. --*/
  42. {
  43. HINF inf = INVALID_HANDLE_VALUE;
  44. INFSTRUCT is = INITINFSTRUCT_POOLHANDLE;
  45. BOOL rSuccess = FALSE;
  46. PTSTR key = NULL;
  47. PTSTR value = NULL;
  48. PTSTR desc = NULL;
  49. PTSTR index = NULL;
  50. BOOL timeZonesFound = FALSE;
  51. TCHAR paddedIndex[20];
  52. PTSTR p = NULL;
  53. UINT i = 0;
  54. UINT count = 0;
  55. if (!g_TzTestHiveSftInf) {
  56. //
  57. // First, Read data from hivesft.inf.
  58. //
  59. inf = InfOpenInfInAllSources (S_HIVESFT_INF);
  60. }
  61. else {
  62. inf = g_TzTestHiveSftInf;
  63. }
  64. if (inf == INVALID_HANDLE_VALUE) {
  65. LOG ((LOG_ERROR, "Cannot load hivesoft.inf. Unable to build timezone information." ));
  66. return FALSE;
  67. }
  68. if (InfFindFirstLine (inf, S_ADDREG, NULL, &is)) {
  69. do {
  70. //
  71. // Cycle through all of the lines looking for timezone information.
  72. //
  73. key = InfGetStringField (&is, 2);
  74. if (key && IsPatternMatch (TEXT("*Time Zones*"), key)) {
  75. //
  76. // Remember that we have found the first timezone entry.
  77. //
  78. timeZonesFound = TRUE;
  79. //
  80. // Now, get value. We care about "display" and "index"
  81. //
  82. value = InfGetStringField (&is, 3);
  83. if (!value) {
  84. continue;
  85. }
  86. if (StringIMatch (value, S_DISPLAY)) {
  87. //
  88. // display string found.
  89. //
  90. desc = InfGetStringField (&is, 5);
  91. } else if (StringIMatch (value, S_INDEX)) {
  92. //
  93. // index value found.
  94. //
  95. index = InfGetStringField (&is, 5);
  96. }
  97. if (index && desc) {
  98. //
  99. // Make sure the index is 0 padded.
  100. //
  101. count = 3 - TcharCount (index);
  102. p = paddedIndex;
  103. for (i=0; i<count; i++) {
  104. *p = TEXT('0');
  105. p = _tcsinc (p);
  106. }
  107. StringCopy (p, index);
  108. //
  109. // we have all the information we need. Save this entry into memdb.
  110. //
  111. MemDbSetValueEx (MEMDB_CATEGORY_NT_TIMEZONES, paddedIndex, desc, NULL, 0, NULL);
  112. index = NULL;
  113. desc = NULL;
  114. }
  115. } else {
  116. //
  117. // Keep memory usage low.
  118. //
  119. InfResetInfStruct (&is);
  120. if (key) {
  121. if (timeZonesFound) {
  122. //
  123. // We have gathered all of the timezone information from hivesft.inf
  124. // we can abort our loop at this point.
  125. //
  126. break;
  127. }
  128. }
  129. }
  130. } while (InfFindNextLine(&is));
  131. } ELSE_DEBUGMSG ((DBG_ERROR, "[%s] not found in hivesft.inf!",S_ADDREG));
  132. //
  133. // Clean up resources
  134. //
  135. InfCleanUpInfStruct (&is);
  136. InfCloseInfFile (inf);
  137. return TRUE;
  138. }
  139. BOOL
  140. pBuild9xTimeZoneData (
  141. VOID
  142. )
  143. /*++
  144. Routine Description:
  145. pBuild9xTimeZone Data is responsible for reading the time zone information
  146. that is stored in win95upg.inf and organizing it into memdb. The timezone
  147. enumeration routines then use this data in order to find all Nt timezones
  148. that can map to a particular 9x timezone.
  149. Arguments:
  150. None.
  151. Return Value:
  152. TRUE if the data is successfully stored in memdb, FALSE
  153. otherwise.
  154. --*/
  155. {
  156. INFSTRUCT is = INITINFSTRUCT_POOLHANDLE;
  157. PTSTR desc = NULL;
  158. PTSTR index = NULL;
  159. UINT count = 0;
  160. PTSTR p = NULL;
  161. //
  162. // Now, read in information about win9x registry mappings.
  163. //
  164. if (InfFindFirstLine (g_Win95UpgInf, S_TIMEZONEMAPPINGS, NULL, &is)) {
  165. do {
  166. //
  167. // Get the display name and matching index(es) for this timezone.
  168. //
  169. desc = InfGetStringField (&is,0);
  170. index = InfGetStringField (&is,1);
  171. //
  172. // Enumerate the indices and save them into memdb.
  173. //
  174. count = 0;
  175. while (index) {
  176. p = _tcschr (index, TEXT(','));
  177. if (p) {
  178. *p = 0;
  179. }
  180. MemDbSetValueEx (
  181. MEMDB_CATEGORY_9X_TIMEZONES,
  182. desc,
  183. MEMDB_FIELD_INDEX,
  184. index,
  185. 0,
  186. NULL
  187. );
  188. count++;
  189. if (p) {
  190. index = _tcsinc(p);
  191. }
  192. else {
  193. //
  194. // Save away the count of possible nt timezones for this 9x timezone.
  195. //
  196. MemDbSetValueEx (
  197. MEMDB_CATEGORY_9X_TIMEZONES,
  198. desc,
  199. MEMDB_FIELD_COUNT,
  200. NULL,
  201. count,
  202. NULL
  203. );
  204. index = NULL;
  205. }
  206. }
  207. } while (InfFindNextLine (&is));
  208. }
  209. //
  210. // Clean up resources.
  211. //
  212. InfCleanUpInfStruct (&is);
  213. return TRUE;
  214. }
  215. BOOL
  216. pGetCurrentTimeZone (
  217. VOID
  218. )
  219. /*++
  220. Routine Description:
  221. pGetCurrentTimeZone retrieves the user's timezone from the windows 9x
  222. registry. The enumeration routines use this timezone in order to enumerate
  223. the possible matching timezones in the INF.
  224. Arguments:
  225. None.
  226. Return Value:
  227. TRUE if the function successfully retrieves the user's password, FALSE
  228. otherwise.
  229. --*/
  230. {
  231. BOOL rSuccess = TRUE;
  232. PCTSTR displayName = NULL;
  233. REGTREE_ENUM eTree;
  234. PCTSTR valueName = NULL;
  235. PCTSTR value = NULL;
  236. PCTSTR curTimeZone = NULL;
  237. HKEY hKey = NULL;
  238. //
  239. // Get the current timezone name, and set the valuename to the correct string.
  240. //
  241. hKey = OpenRegKeyStr (S_TIMEZONEINFORMATION);
  242. if (!hKey) {
  243. LOG ((LOG_ERROR, "Unable to open %s key.", S_TIMEZONEINFORMATION));
  244. return FALSE;
  245. }
  246. if ((curTimeZone = GetRegValueString (hKey, S_STANDARDNAME)) && !StringIMatch (curTimeZone, S_FIRSTBOOT)) {
  247. //
  248. // standard time. We need to look under the "STD" value to match this.
  249. //
  250. valueName = S_STD;
  251. } else if ((curTimeZone = GetRegValueString (hKey, S_DAYLIGHTNAME)) && !StringIMatch (curTimeZone, S_FIRSTBOOT)) {
  252. //
  253. // Daylight Savings Time. We need to look under the "DLT" value to match this.
  254. //
  255. valueName = S_DLT;
  256. } else {
  257. CloseRegKey (hKey);
  258. hKey = OpenRegKeyStr (TEXT("HKLM\\Software\\Microsoft\\Windows\\CurrentVersion\\Time Zones"));
  259. if (hKey) {
  260. if (curTimeZone = GetRegValueString (hKey, TEXT(""))) {
  261. valueName = S_STD;
  262. }
  263. }
  264. if (!valueName) {
  265. //
  266. // No timezone found!
  267. //
  268. DEBUGMSG((DBG_WHOOPS,"Unable to get Timezone name..User will have to enter timezone in GUI mode."));
  269. return FALSE;
  270. }
  271. }
  272. __try {
  273. //
  274. // Now we have to search through the timezones key and find the key that has a value equal to
  275. // the current timezone name. A big pain.
  276. //
  277. if (EnumFirstRegKeyInTree (&eTree, S_TIMEZONES)) {
  278. do {
  279. //
  280. // For each subkey, we must look for the string in valueName and
  281. // see if it matches.
  282. //
  283. value = GetRegValueString (eTree.CurrentKey->KeyHandle, valueName);
  284. if (value) {
  285. if (StringIMatch (value, curTimeZone)) {
  286. //
  287. // We found the key we were looking for and we can finally
  288. // gather the data we need.
  289. //
  290. displayName = GetRegValueString (eTree.CurrentKey->KeyHandle, S_DISPLAY);
  291. if (!displayName) {
  292. DEBUGMSG((DBG_WHOOPS,"Error! Timezone key found, but no Display value!"));
  293. AbortRegKeyTreeEnum (&eTree);
  294. rSuccess = FALSE;
  295. __leave;
  296. }
  297. //
  298. // Save away the current Timezone and leave the loop. We are done.
  299. //
  300. StringCopy (g_CurrentTimeZone, displayName);
  301. AbortRegKeyTreeEnum (&eTree);
  302. break;
  303. }
  304. MemFree (g_hHeap, 0, value);
  305. value = NULL;
  306. }
  307. } while (EnumNextRegKeyInTree (&eTree));
  308. }
  309. } __finally {
  310. if (curTimeZone) {
  311. MemFree (g_hHeap, 0, curTimeZone);
  312. }
  313. if (value) {
  314. MemFree (g_hHeap, 0, value);
  315. }
  316. if (displayName) {
  317. MemFree (g_hHeap, 0, displayName);
  318. }
  319. CloseRegKey (hKey);
  320. }
  321. return rSuccess;
  322. }
  323. BOOL
  324. pInitTimeZoneData (
  325. VOID
  326. )
  327. /*++
  328. Routine Description:
  329. pInitTimeZoneData is responsible for performing all of the initialization
  330. necessary to use the time zone enumeration routines.
  331. Arguments:
  332. None.
  333. Return Value:
  334. TRUE if initialization completes successfully, FALSE otherwise.
  335. --*/
  336. {
  337. BOOL rSuccess = TRUE;
  338. //
  339. // First, fill memdb with timezone
  340. // information regarding winnt and win9x
  341. // (from hivesft.inf and win95upg.inf)
  342. //
  343. if (!pBuildNtTimeZoneData ()) {
  344. LOG ((LOG_ERROR, "Unable to gather nt timezone information."));
  345. rSuccess = FALSE;
  346. }
  347. if (!pBuild9xTimeZoneData ()) {
  348. LOG ((LOG_ERROR, "Unable to gather 9x timezone information."));
  349. rSuccess = FALSE;
  350. }
  351. //
  352. // Next, get the user's timezone.
  353. //
  354. if (!pGetCurrentTimeZone ()) {
  355. LOG ((LOG_ERROR, "Failure trying to retrieve timezone information."));
  356. rSuccess = FALSE;
  357. }
  358. return rSuccess;
  359. }
  360. BOOL
  361. pEnumFirstNtTimeZone (
  362. OUT PTIMEZONE_ENUM EnumPtr
  363. )
  364. {
  365. BOOL rSuccess = FALSE;
  366. PTSTR p;
  367. EnumPtr -> MapCount = 0;
  368. if (MemDbEnumFirstValue (&(EnumPtr -> Enum), MEMDB_CATEGORY_NT_TIMEZONES"\\*", MEMDB_ALL_SUBLEVELS, MEMDB_ENDPOINTS_ONLY)) {
  369. do {
  370. EnumPtr -> MapCount++;
  371. } while (MemDbEnumNextValue (&(EnumPtr -> Enum)));
  372. }
  373. else {
  374. return FALSE;
  375. }
  376. MemDbEnumFirstValue (&(EnumPtr -> Enum), MEMDB_CATEGORY_NT_TIMEZONES"\\*", MEMDB_ALL_SUBLEVELS, MEMDB_ENDPOINTS_ONLY);
  377. p = _tcschr (EnumPtr->Enum.szName,TEXT('\\'));
  378. if (!p) {
  379. return FALSE;
  380. }
  381. *p = 0;
  382. EnumPtr -> MapIndex = EnumPtr -> Enum.szName;
  383. StringCopy (EnumPtr -> NtTimeZone, _tcsinc(p));
  384. return TRUE;
  385. }
  386. BOOL
  387. pEnumNextNtTimeZone (
  388. OUT PTIMEZONE_ENUM EnumPtr
  389. )
  390. {
  391. PTSTR p;
  392. if (!MemDbEnumNextValue(&EnumPtr -> Enum)) {
  393. return FALSE;
  394. }
  395. p = _tcschr (EnumPtr->Enum.szName,TEXT('\\'));
  396. if (!p) {
  397. return FALSE;
  398. }
  399. *p = 0;
  400. EnumPtr -> MapIndex = EnumPtr -> Enum.szName;
  401. StringCopy (EnumPtr -> NtTimeZone, _tcsinc(p));
  402. return TRUE;
  403. }
  404. BOOL
  405. EnumFirstTimeZone (
  406. OUT PTIMEZONE_ENUM EnumPtr,
  407. IN DWORD Flags
  408. )
  409. /*++
  410. Routine Description:
  411. EnumFirstTimeZone/EnumNextTimeZone enumerate the Nt timezones that can match the
  412. user's current Windows 9x time zone. In most cases, there will be only one,
  413. but, in some cases, there can be several.
  414. Arguments:
  415. EnumPtr - A pointer to a valid timezone enumeration structure. This
  416. variable holds the necessary state between timezone enumeration
  417. calls.
  418. Return Value:
  419. TRUE if there are any timezones to enumerate, FALSE otherwise.
  420. --*/
  421. {
  422. BOOL rSuccess = FALSE;
  423. TCHAR key[MEMDB_MAX];
  424. static BOOL firstTime = TRUE;
  425. if (firstTime) {
  426. if (!pInitTimeZoneData ()) {
  427. LOG ((LOG_ERROR, "Error initializing timezone data."));
  428. return FALSE;
  429. }
  430. firstTime = FALSE;
  431. }
  432. MYASSERT (EnumPtr);
  433. EnumPtr -> CurTimeZone = g_CurrentTimeZone;
  434. EnumPtr -> Flags = Flags;
  435. if (Flags & TZFLAG_ENUM_ALL) {
  436. return pEnumFirstNtTimeZone (EnumPtr);
  437. }
  438. if ((Flags & TZFLAG_USE_FORCED_MAPPINGS) && g_TimeZoneMapped) {
  439. //
  440. // We have a force mapping, so mapcount is 1.
  441. //
  442. EnumPtr -> MapCount = 1;
  443. }
  444. else {
  445. //
  446. // Get count of matches.
  447. //
  448. MemDbBuildKey (key, MEMDB_CATEGORY_9X_TIMEZONES, EnumPtr -> CurTimeZone, MEMDB_FIELD_COUNT, NULL);
  449. if (!MemDbGetValue (key, &(EnumPtr -> MapCount))) {
  450. DEBUGMSG ((
  451. DBG_WARNING,
  452. "EnumFirstTimeZone: Could not retrieve count of nt timezone matches from memdb for %s.",
  453. EnumPtr -> CurTimeZone
  454. ));
  455. return FALSE;
  456. }
  457. }
  458. DEBUGMSG ((DBG_TIMEZONE, "%d Nt time zones match the win9x timezone %s.", EnumPtr -> MapCount, EnumPtr -> CurTimeZone));
  459. if ((Flags & TZFLAG_USE_FORCED_MAPPINGS) && g_TimeZoneMapped) {
  460. //
  461. // Use the previously forced mapping.
  462. //
  463. EnumPtr -> MapIndex = g_TimeZoneMap;
  464. } else {
  465. //
  466. // Now, enumerate the matching map indexes in memdb.
  467. //
  468. rSuccess = MemDbGetValueEx (
  469. &(EnumPtr -> Enum),
  470. MEMDB_CATEGORY_9X_TIMEZONES,
  471. EnumPtr -> CurTimeZone,
  472. MEMDB_FIELD_INDEX
  473. );
  474. if (!rSuccess) {
  475. return FALSE;
  476. }
  477. EnumPtr -> MapIndex = EnumPtr -> Enum.szName;
  478. }
  479. //
  480. // Get the NT display string for this map index.
  481. //
  482. rSuccess = MemDbGetEndpointValueEx (MEMDB_CATEGORY_NT_TIMEZONES, EnumPtr->MapIndex, NULL, EnumPtr->NtTimeZone);
  483. return rSuccess;
  484. }
  485. BOOL
  486. EnumNextTimeZone (
  487. IN OUT PTIMEZONE_ENUM EnumPtr
  488. )
  489. {
  490. if (EnumPtr -> Flags & TZFLAG_ENUM_ALL) {
  491. return pEnumNextNtTimeZone (EnumPtr);
  492. }
  493. if ((EnumPtr -> Flags & TZFLAG_USE_FORCED_MAPPINGS) && g_TimeZoneMapped) {
  494. return FALSE;
  495. }
  496. if (!MemDbEnumNextValue (&(EnumPtr->Enum))) {
  497. return FALSE;
  498. }
  499. EnumPtr->MapIndex = EnumPtr->Enum.szName;
  500. return MemDbGetEndpointValueEx (MEMDB_CATEGORY_NT_TIMEZONES, EnumPtr->MapIndex, NULL, EnumPtr->NtTimeZone);
  501. }
  502. BOOL
  503. ForceTimeZoneMap (
  504. IN PCTSTR NtTimeZone
  505. )
  506. /*++
  507. Routine Description:
  508. ForceTimeZoneMap forces the mapping of a particular 9x timezone to a
  509. particular Nt timezone. This function is used in cases where there are
  510. multiple nt timezones that could map to a particular 9x timezone.
  511. Arguments:
  512. NtTimeZone - String containing the timezone to force mapping to.
  513. Return Value:
  514. TRUE if the function successfully updated the timezone mapping, FALSE
  515. otherwise.
  516. --*/
  517. {
  518. TIMEZONE_ENUM e;
  519. //
  520. // Find index that matches this timezone.
  521. //
  522. if (EnumFirstTimeZone (&e, TZFLAG_ENUM_ALL)) {
  523. do {
  524. if (StringIMatch (NtTimeZone, e.NtTimeZone)) {
  525. //
  526. // this is the index we need.
  527. //
  528. StringCopy (g_TimeZoneMap, e.MapIndex);
  529. g_TimeZoneMapped = TRUE;
  530. break;
  531. }
  532. } while (EnumNextTimeZone (&e));
  533. }
  534. return TRUE;
  535. }