Leaked source code of windows server 2003
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.

678 lines
20 KiB

  1. /*++
  2. Copyright (c) 1991-2000, Microsoft Corporation All rights reserved.
  3. Module Name:
  4. init.c
  5. Abstract:
  6. This file contains the initialization code for the NLS APIs.
  7. External Routines found in this file:
  8. NlsDllInitialize
  9. Revision History:
  10. 05-31-91 JulieB Created.
  11. --*/
  12. //
  13. // Include Files.
  14. //
  15. #include "nls.h"
  16. #include "nlssafe.h"
  17. #include "stdio.h"
  18. //
  19. // Global Variables.
  20. //
  21. HANDLE hModule; // handle to module
  22. RTL_CRITICAL_SECTION gcsTblPtrs; // critical section for tbl ptrs
  23. UINT gAnsiCodePage; // Ansi code page value
  24. UINT gOemCodePage; // OEM code page value
  25. UINT gMacCodePage; // MAC code page value
  26. LCID gSystemLocale; // system locale value
  27. LANGID gSystemInstallLang; // system's original install language
  28. PLOC_HASH gpSysLocHashN; // ptr to system loc hash node
  29. PLOC_HASH gpInvLocHashN; // ptr to invariant loc hash node
  30. PCP_HASH gpACPHashN; // ptr to ACP hash node
  31. PCP_HASH gpOEMCPHashN; // ptr to OEMCP hash node
  32. PCP_HASH gpMACCPHashN; // ptr to MACCP hash node
  33. HANDLE hCodePageKey; // handle to System\Nls\CodePage key
  34. HANDLE hLocaleKey; // handle to System\Nls\Locale key
  35. HANDLE hAltSortsKey; // handle to Locale\Alternate Sorts key
  36. HANDLE hLangGroupsKey; // handle to System\Nls\Language Groups key
  37. PNLS_USER_INFO pNlsUserInfo; // ptr to the user info cache
  38. PNLS_USER_INFO pServerNlsUserInfo; // ptr to the user info cache in the csrss.exe.
  39. NLS_USER_INFO gProcUserInfo; // The user info cache for the process.
  40. // The values in this cached are updated from the content of the
  41. // server side cache (pNlsRegUserInfo in csrss.exe).
  42. // Every time when we read the cache, we will check a version count (ulCacheUpdateCount
  43. // field in NLS_USER_INFO) against the server-side cache (pNlsRegUserInfo) to
  44. // see if the process cache is still valid. The ulCacheUpdateCount will be incremented
  45. // and sync'ed in the server-side when SetLocaleInfo() happens or intl registry key changes.
  46. RTL_CRITICAL_SECTION gcsNlsProcessCache; // critical section for nls process cache
  47. //
  48. // Forward Declarations.
  49. //
  50. ULONG
  51. NlsServerInitialize(void);
  52. ULONG
  53. NlsProcessInitialize(void);
  54. void
  55. InitKoreanWeights(void);
  56. //-------------------------------------------------------------------------//
  57. // EXTERNAL ROUTINES //
  58. //-------------------------------------------------------------------------//
  59. ////////////////////////////////////////////////////////////////////////////
  60. //
  61. // NlsDllInitialize
  62. //
  63. // DLL Entry initialization procedure for NLSAPI. This is called by
  64. // the base dll initialization.
  65. //
  66. // 05-31-91 JulieB Created.
  67. ////////////////////////////////////////////////////////////////////////////
  68. BOOLEAN NlsDllInitialize(
  69. IN PVOID hMod,
  70. ULONG Reason,
  71. IN PBASE_STATIC_SERVER_DATA pBaseStaticServerData)
  72. {
  73. if (Reason == DLL_PROCESS_ATTACH)
  74. {
  75. ULONG rc;
  76. //
  77. // Save module handle for use later.
  78. //
  79. hModule = (HANDLE)hMod;
  80. //
  81. // Initialize the cached user info pointer.
  82. //
  83. pServerNlsUserInfo = &(pBaseStaticServerData->NlsUserInfo);
  84. pNlsUserInfo = &gProcUserInfo;
  85. //
  86. // Process attaching, so initialize tables.
  87. //
  88. rc = NlsServerInitialize();
  89. if (rc)
  90. {
  91. KdPrint(("NLSAPI: Could NOT initialize Server - %lx.\n", rc));
  92. return (FALSE);
  93. }
  94. rc = NlsProcessInitialize();
  95. if (rc)
  96. {
  97. KdPrint(("NLSAPI: Could NOT initialize Process - %lx.\n", rc));
  98. return (FALSE);
  99. }
  100. }
  101. //
  102. // Return success.
  103. //
  104. return (TRUE);
  105. }
  106. ////////////////////////////////////////////////////////////////////////////
  107. //
  108. // NlsThreadCleanup
  109. //
  110. // Cleanup for thread resources when it terminates.
  111. //
  112. // 03-30-99 SamerA Created.
  113. ////////////////////////////////////////////////////////////////////////////
  114. VOID NlsThreadCleanup(
  115. VOID)
  116. {
  117. if (NtCurrentTeb()->NlsCache)
  118. {
  119. CLOSE_REG_KEY( ((PNLS_LOCAL_CACHE)NtCurrentTeb()->NlsCache)->CurrentUserKeyHandle );
  120. RtlFreeHeap( RtlProcessHeap(),
  121. 0,
  122. NtCurrentTeb()->NlsCache
  123. );
  124. }
  125. }
  126. //-------------------------------------------------------------------------//
  127. // INTERNAL ROUTINES //
  128. //-------------------------------------------------------------------------//
  129. ////////////////////////////////////////////////////////////////////////////
  130. //
  131. // NlsServerInitialize
  132. //
  133. // Server initialization procedure for NLSAPI. This is the ONE-TIME
  134. // initialization code for the NLSAPI DLL. It simply does the calls
  135. // to NtCreateSection for the code pages that are currently found in the
  136. // system.
  137. //
  138. // 05-31-91 JulieB Created.
  139. ////////////////////////////////////////////////////////////////////////////
  140. ULONG NlsServerInitialize(void)
  141. {
  142. HANDLE hSec = (HANDLE)0; // section handle
  143. ULONG rc;
  144. PPEB Peb;
  145. #ifndef DOSWIN32
  146. PIMAGE_NT_HEADERS NtHeaders;
  147. #endif
  148. Peb = NtCurrentPeb();
  149. //
  150. // MultiUser NT (Hydra). SesssionId = 0 is the console CSRSS.
  151. // If this is NOT the first server process, then just return success,
  152. // since we only want to create the object directories once.
  153. //
  154. if (Peb->SessionId != 0)
  155. {
  156. return (NO_ERROR);
  157. }
  158. #ifndef DOSWIN32
  159. //
  160. // This is to avoid being initialized again when NTSD dynlinks to
  161. // a server to get at its debugger extensions.
  162. //
  163. NtHeaders = RtlImageNtHeader(Peb->ImageBaseAddress);
  164. if (NtHeaders &&
  165. (NtHeaders->OptionalHeader.Subsystem != IMAGE_SUBSYSTEM_NATIVE))
  166. {
  167. return (NO_ERROR);
  168. }
  169. #endif
  170. //
  171. // Create the NLS object directory.
  172. //
  173. // Must create a separate directory off the root in order to have
  174. // CreateSection access on the fly.
  175. //
  176. if (rc = CreateNlsObjectDirectory())
  177. {
  178. return (rc);
  179. }
  180. //
  181. // The ACP, OEMCP, and Default Language files are already created
  182. // at boot time. The pointers to the files are stored in the PEB.
  183. //
  184. // Create the section for the following data files:
  185. // UNICODE
  186. // LOCALE
  187. // CTYPE
  188. // SORTKEY
  189. // SORT TABLES
  190. //
  191. // All other data files will have the sections created only as they
  192. // are needed.
  193. //
  194. if ((!NT_SUCCESS(rc = CsrBasepNlsCreateSection( NLS_CREATE_SECTION_UNICODE, 0, &hSec))) ||
  195. (!NT_SUCCESS(rc = CsrBasepNlsCreateSection( NLS_CREATE_SECTION_LOCALE, 0, &hSec))) ||
  196. (!NT_SUCCESS(rc = CsrBasepNlsCreateSection( NLS_CREATE_SECTION_CTYPE, 0, &hSec))) ||
  197. (!NT_SUCCESS(rc = CsrBasepNlsCreateSection( NLS_CREATE_SECTION_SORTKEY, 0, &hSec))) ||
  198. (!NT_SUCCESS(rc = CsrBasepNlsCreateSection( NLS_CREATE_SECTION_SORTTBLS, 0, &hSec))))
  199. {
  200. return (rc);
  201. }
  202. //
  203. // Return success.
  204. //
  205. return (NO_ERROR);
  206. }
  207. ////////////////////////////////////////////////////////////////////////////
  208. //
  209. // NlsProcessInitialize
  210. //
  211. // Process initialization procedure for NLS API. This routine sets up all
  212. // of the tables so that they are accessable from the current process. If
  213. // it is unable to allocate the appropriate memory or memory map the
  214. // appropriate files, an error is returned.
  215. //
  216. // 05-31-91 JulieB Created.
  217. ////////////////////////////////////////////////////////////////////////////
  218. ULONG NlsProcessInitialize(void)
  219. {
  220. ULONG rc;
  221. LPWORD pBaseAddr; // ptr to base address of section
  222. LCID UserLocale; // user locale id
  223. PLOC_HASH pUserLocHashN; // ptr to user locale hash node
  224. PPEB Peb;
  225. Peb = NtCurrentPeb();
  226. //
  227. // Initialize the critical section that protects the NLS cache for
  228. // this process.
  229. //
  230. if ((rc = RtlInitializeCriticalSection(&gcsNlsProcessCache)) != ERROR_SUCCESS)
  231. {
  232. return (rc);
  233. }
  234. //
  235. // Initialize the table pointers critical section.
  236. // Enter the critical section to set up the tables.
  237. //
  238. if ((rc = RtlInitializeCriticalSectionAndSpinCount(&gcsTblPtrs, 4000)) != ERROR_SUCCESS)
  239. {
  240. return (rc);
  241. }
  242. RtlEnterCriticalSection(&gcsTblPtrs);
  243. //
  244. // Allocate initial tables.
  245. //
  246. if (rc = AllocTables())
  247. {
  248. KdPrint(("AllocTables failed, rc %lx\n", rc));
  249. RtlLeaveCriticalSection(&gcsTblPtrs);
  250. return (rc);
  251. }
  252. //
  253. // Initialize the handles to the various registry keys to NULL.
  254. //
  255. hCodePageKey = NULL;
  256. hLocaleKey = NULL;
  257. hAltSortsKey = NULL;
  258. hLangGroupsKey = NULL;
  259. //
  260. // Get the ANSI code page value.
  261. // Create the hash node for the ACP.
  262. // Insert the hash node into the global CP hash table.
  263. //
  264. // At this point, the ACP table has already been mapped into
  265. // the process, so get the pointer from the PEB.
  266. //
  267. pBaseAddr = Peb->AnsiCodePageData;
  268. gAnsiCodePage = ((PCP_TABLE)(pBaseAddr + CP_HEADER))->CodePage;
  269. if (rc = MakeCPHashNode( gAnsiCodePage,
  270. pBaseAddr,
  271. &gpACPHashN,
  272. FALSE,
  273. NULL ))
  274. {
  275. RtlLeaveCriticalSection(&gcsTblPtrs);
  276. return (rc);
  277. }
  278. //
  279. // Get the OEM code page value.
  280. // Create the hash node for the OEMCP.
  281. // Insert the hash node into the global CP hash table.
  282. //
  283. // At this point, the OEMCP table has already been mapped into
  284. // the process, so get the pointer from the PEB.
  285. //
  286. pBaseAddr = Peb->OemCodePageData;
  287. gOemCodePage = ((PCP_TABLE)(pBaseAddr + CP_HEADER))->CodePage;
  288. if (gOemCodePage != gAnsiCodePage)
  289. {
  290. //
  291. // Oem code page is different than the Ansi code page, so
  292. // need to create and store the new hash node.
  293. //
  294. if (rc = MakeCPHashNode( gOemCodePage,
  295. pBaseAddr,
  296. &gpOEMCPHashN,
  297. FALSE,
  298. NULL ))
  299. {
  300. RtlLeaveCriticalSection(&gcsTblPtrs);
  301. return (rc);
  302. }
  303. }
  304. else
  305. {
  306. //
  307. // Oem code page is the same as the Ansi code page, so set
  308. // the oem cp hash node to be the same as the ansi cp hash node.
  309. //
  310. gpOEMCPHashN = gpACPHashN;
  311. }
  312. //
  313. // Initialize the MAC code page values to 0.
  314. // These values will be set the first time they are requested for use.
  315. //
  316. gMacCodePage = 0;
  317. gpMACCPHashN = NULL;
  318. //
  319. // Open and Map a View of the Section for UNICODE.NLS.
  320. // Save the pointers to the table information in the table ptrs
  321. // structure.
  322. //
  323. if (rc = GetUnicodeFileInfo())
  324. {
  325. KdPrint(("GetUnicodeFileInfo failed, rc %lx\n", rc));
  326. RtlLeaveCriticalSection(&gcsTblPtrs);
  327. return (rc);
  328. }
  329. //
  330. // Cache the system locale value.
  331. //
  332. rc = NtQueryDefaultLocale(FALSE, &gSystemLocale);
  333. if (!NT_SUCCESS(rc))
  334. {
  335. RtlLeaveCriticalSection(&gcsTblPtrs);
  336. return (rc);
  337. }
  338. //
  339. // Store the user locale value.
  340. //
  341. UserLocale = pNlsUserInfo->UserLocaleId;
  342. if (UserLocale == 0)
  343. {
  344. UserLocale = gSystemLocale;
  345. }
  346. //
  347. // Initialize the system install language to zero. This will only
  348. // be retrieved on an as need basis.
  349. //
  350. gSystemInstallLang = 0;
  351. //
  352. // Open and Map a View of the Section for LOCALE.NLS.
  353. // Create and insert the hash node into the global Locale hash table
  354. // for the system default locale.
  355. //
  356. if (rc = GetLocaleFileInfo( gSystemLocale,
  357. &gpSysLocHashN,
  358. TRUE ))
  359. {
  360. //
  361. // Change the system locale to be the default (English).
  362. //
  363. if (GetLocaleFileInfo( MAKELCID(NLS_DEFAULT_LANGID, SORT_DEFAULT),
  364. &gpSysLocHashN,
  365. TRUE ))
  366. {
  367. KdPrint(("Couldn't do English\n"));
  368. RtlLeaveCriticalSection(&gcsTblPtrs);
  369. return (rc);
  370. }
  371. else
  372. {
  373. //
  374. // Registry is corrupt, but allow the English default to
  375. // work. Need to reset the system default.
  376. //
  377. gSystemLocale = MAKELCID(NLS_DEFAULT_LANGID, SORT_DEFAULT);
  378. KdPrint(("NLSAPI: Registry is corrupt - Using Default Locale.\n"));
  379. }
  380. }
  381. //
  382. // If the user default locale is different from the system default
  383. // locale, then create and insert the hash node into the global
  384. // Locale hash table for the user default locale.
  385. //
  386. // NOTE: The System Default Locale Hash Node should be
  387. // created before this call.
  388. //
  389. if (UserLocale != gSystemLocale)
  390. {
  391. if (rc = GetLocaleFileInfo( UserLocale,
  392. &pUserLocHashN,
  393. TRUE ))
  394. {
  395. //
  396. // Change the user locale to be equal to the system default.
  397. //
  398. UserLocale = gSystemLocale;
  399. KdPrint(("NLSAPI: Registry is corrupt - User Locale Now Equals System Locale.\n"));
  400. }
  401. }
  402. //
  403. // Create and insert the hash node into the global Locale hash
  404. // table for the invariant locale.
  405. //
  406. if (rc = GetLocaleFileInfo( LOCALE_INVARIANT,
  407. &gpInvLocHashN,
  408. TRUE ))
  409. {
  410. KdPrint(("NLSAPI: Registry is corrupt - Invariant Locale Cannot Be Initialized.\n"));
  411. }
  412. //
  413. // Open and Map a View of the Section for SORTKEY.NLS.
  414. // Save the pointers to the semaphore dword and the default sortkey
  415. // table in the table ptrs structure.
  416. //
  417. if (rc = GetDefaultSortkeyFileInfo())
  418. {
  419. KdPrint(("NLSAPI: Initialization, GetDefaultSortkeyFileInfo failed with rc %lx.\n", rc));
  420. // RtlLeaveCriticalSection(&gcsTblPtrs);
  421. // return (rc);
  422. }
  423. //
  424. // Open and Map a View of the Section for SORTTBLS.NLS.
  425. // Save the pointers to the sort table information in the
  426. // table ptrs structure.
  427. //
  428. if (rc = GetDefaultSortTablesFileInfo())
  429. {
  430. RtlLeaveCriticalSection(&gcsTblPtrs);
  431. return (rc);
  432. }
  433. //
  434. // Get the language information portion of the system locale.
  435. //
  436. // NOTE: GetDefaultSortkeyFileInfo and GetDefaultSortTablesFileInfo
  437. // should be called before this so that the default sorting
  438. // tables are already initialized at the time of the call.
  439. //
  440. if (rc = GetLanguageFileInfo( gSystemLocale,
  441. &gpSysLocHashN,
  442. FALSE,
  443. 0 ))
  444. {
  445. RtlLeaveCriticalSection(&gcsTblPtrs);
  446. return (rc);
  447. }
  448. //
  449. // Get the language information portion of the invariant locale. We
  450. // use the default locale (US English).
  451. //
  452. if (rc = GetLanguageFileInfo( MAKELCID(NLS_DEFAULT_LANGID, SORT_DEFAULT),
  453. &gpInvLocHashN,
  454. FALSE,
  455. 0 ))
  456. {
  457. RtlLeaveCriticalSection(&gcsTblPtrs);
  458. return (rc);
  459. }
  460. //
  461. // If the user default is different from the system default,
  462. // get the language information portion of the user default locale.
  463. //
  464. // NOTE: GetDefaultSortkeyFileInfo and GetDefaultSortTablesFileInfo
  465. // should be called before this so that the default sorting
  466. // tables are already initialized at the time of the call.
  467. //
  468. if (gSystemLocale != UserLocale)
  469. {
  470. if (rc = MakeLangHashNode( UserLocale,
  471. NULL,
  472. &pUserLocHashN,
  473. FALSE ))
  474. {
  475. RtlLeaveCriticalSection(&gcsTblPtrs);
  476. return (rc);
  477. }
  478. }
  479. //
  480. // Initialize the Korean SMWeight values.
  481. //
  482. InitKoreanWeights();
  483. //
  484. // Leave the critical section.
  485. //
  486. RtlLeaveCriticalSection(&gcsTblPtrs);
  487. RtlEnterCriticalSection(&gcsNlsProcessCache);
  488. //
  489. // Fill up the cache from the cache in csrss.exe so that we have a fresh copy of cache
  490. // values. We will retrieve a copy of ulCacheUpdateCount so that we can check
  491. // if the cache values are no longer valid after they are retrieved here.
  492. //
  493. // Enter a critical section gcsNlsProcessCache to provide synchronization between
  494. // threads since we are updating the process-wide cache.
  495. //
  496. if (!NT_SUCCESS(CsrBasepNlsGetUserInfo(pNlsUserInfo, sizeof(NLS_USER_INFO))))
  497. {
  498. RtlLeaveCriticalSection(&gcsNlsProcessCache);
  499. return (ERROR_INVALID_FUNCTION);
  500. }
  501. RtlLeaveCriticalSection(&gcsNlsProcessCache);
  502. //
  503. // Return success.
  504. //
  505. return (NO_ERROR);
  506. }
  507. ////////////////////////////////////////////////////////////////////////////
  508. //
  509. // InitKoreanWeights
  510. //
  511. // Creates the SMWeight array with the IDEOGRAPH script member sorting
  512. // before all other script members.
  513. //
  514. // NOTE: This function assumes we're in a critical section.
  515. //
  516. // 05-31-91 JulieB Created.
  517. ////////////////////////////////////////////////////////////////////////////
  518. void InitKoreanWeights()
  519. {
  520. DWORD ctr; // loop counter
  521. BYTE NewScript; // new script to store
  522. LPBYTE pSMWeight = pTblPtrs->SMWeight; // ptr to script member weights
  523. PMULTI_WT pMulti; // ptr to multi weight
  524. //
  525. // Set the 0 to FIRST_SCRIPT of script structure to its default
  526. // value.
  527. //
  528. RtlZeroMemory(pSMWeight, NUM_SM);
  529. for (ctr = 1; ctr < FIRST_SCRIPT; ctr++)
  530. {
  531. pSMWeight[ctr] = (BYTE)ctr;
  532. }
  533. //
  534. // Save the order in the SMWeight array.
  535. //
  536. NewScript = FIRST_SCRIPT;
  537. pSMWeight[IDEOGRAPH] = NewScript;
  538. NewScript++;
  539. //
  540. // See if the script is part of a multiple weights script.
  541. //
  542. pMulti = pTblPtrs->pMultiWeight;
  543. for (ctr = pTblPtrs->NumMultiWeight; ctr > 0; ctr--, pMulti++)
  544. {
  545. if (pMulti->FirstSM == IDEOGRAPH)
  546. {
  547. //
  548. // Part of multiple weight, so must move entire range
  549. // by setting each value in range to NewScript and
  550. // then incrementing NewScript.
  551. //
  552. // NOTE: May use 'ctr' here since it ALWAYS breaks
  553. // out of outer for loop.
  554. //
  555. for (ctr = 1; ctr < pMulti->NumSM; ctr++)
  556. {
  557. pSMWeight[IDEOGRAPH + ctr] = NewScript;
  558. NewScript++;
  559. }
  560. break;
  561. }
  562. }
  563. //
  564. // Must set each script member that has not yet been reset to its
  565. // new order.
  566. //
  567. // The default ordering is to assign:
  568. // Order = Script Member Value
  569. //
  570. // Therefore, can simply set each zero entry in order to the end
  571. // of the array to the next 'NewScript' value.
  572. //
  573. for (ctr = FIRST_SCRIPT; ctr < NUM_SM; ctr++)
  574. {
  575. //
  576. // If it's a zero value, set it to the next sorting order value.
  577. //
  578. if (pSMWeight[ctr] == 0)
  579. {
  580. pSMWeight[ctr] = NewScript;
  581. NewScript++;
  582. }
  583. }
  584. }