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.

726 lines
17 KiB

  1. /*++
  2. Copyright (c) 1997 Microsoft Corporation
  3. Module Name:
  4. defer.c
  5. Abstract:
  6. This module implements deferred initialization, code that must run only
  7. after WINNT32 has obtained source directories.
  8. Author:
  9. Jim Schmidt (jimschm) 08-Jan-1998
  10. Revision History:
  11. jimschm 23-Sep-1998 InitNtEnvironment move
  12. --*/
  13. #include "pch.h"
  14. #include "init9xp.h"
  15. #include "ntverp.h"
  16. //
  17. // Local prototypes
  18. //
  19. HWND
  20. pFindProcessWindow (
  21. VOID
  22. );
  23. BOOL
  24. pGetProfilesDirectory (
  25. OUT PTSTR Path, OPTIONAL
  26. IN OUT PDWORD Size
  27. );
  28. INT
  29. pGetProcessorSpeed (
  30. OUT PTSTR *Family
  31. );
  32. BOOL
  33. pReloadWin95upgInf (
  34. VOID
  35. )
  36. {
  37. if (g_Win95UpgInf != INVALID_HANDLE_VALUE) {
  38. InfCloseInfFile (g_Win95UpgInf);
  39. g_Win95UpgInf = INVALID_HANDLE_VALUE;
  40. }
  41. MYASSERT (g_Win95UpgInfFile);
  42. g_Win95UpgInf = InfOpenInfFile (g_Win95UpgInfFile);
  43. return g_Win95UpgInf != INVALID_HANDLE_VALUE;
  44. }
  45. //
  46. // Implementation
  47. //
  48. BOOL
  49. pPutBootFileInUninstallTempDir (
  50. IN PCTSTR SrcFileName,
  51. IN PCTSTR DestFileName OPTIONAL
  52. )
  53. {
  54. PCTSTR src;
  55. PCTSTR dest;
  56. UINT rc = ERROR_SUCCESS;
  57. DWORD attribs;
  58. src = JoinPaths (g_BootDrivePath, SrcFileName);
  59. dest = JoinPaths (g_TempDir, DestFileName ? DestFileName : SrcFileName);
  60. if (DoesFileExist (src)) {
  61. SetFileAttributes (dest, FILE_ATTRIBUTE_NORMAL);
  62. DeleteFile (dest);
  63. if (!CopyFile (src, dest, FALSE)) {
  64. DEBUGMSG ((DBG_ERROR, "Can't copy %s to %s", src, dest));
  65. rc = GetLastError();
  66. }
  67. }
  68. SetLastError (rc);
  69. return rc == ERROR_SUCCESS;
  70. }
  71. BOOL
  72. DeferredInit (
  73. IN HWND WizardPageHandle
  74. )
  75. /*++
  76. Routine Description:
  77. DeferredInit performs all initialization that requires the source directories
  78. to be provied by Windows NT. It runs after the user has selected the
  79. correct source directory, and WINNT32 has validated the choice.
  80. Arguments:
  81. WizardPageHandle - Specifies handle to wizard page and is used to display
  82. abnormal end popups.
  83. Return Value:
  84. TRUE if init succeeds, or FALSE if it fails. If FALSE is returned,
  85. Setup terminates without any popups.
  86. --*/
  87. {
  88. INT speed;
  89. PSTR family;
  90. MEMORYSTATUS memoryStatus;
  91. UINT index;
  92. TCHAR ProfileTemp[MAX_TCHAR_PATH];
  93. DWORD Size;
  94. BYTE bootSector[FAT_BOOT_SECTOR_SIZE];
  95. HANDLE fileHandle = INVALID_HANDLE_VALUE;
  96. DWORD dontCare;
  97. DWORD attribs;
  98. BOOL result = FALSE;
  99. TCHAR dest[MAX_TCHAR_PATH];
  100. HKEY key;
  101. PCTSTR TempStr;
  102. WIN32_FIND_DATA fd;
  103. LOG ((LOG_INFORMATION, "UpgradeModuleBuild: %u", VER_PRODUCTBUILD));
  104. __try {
  105. //
  106. // Check if DU was successful; if it was then
  107. // set the INF patch directory
  108. //
  109. if (g_DUCompletedSuccessfully && *g_DUCompletedSuccessfully &&
  110. g_DynamicUpdateLocalDir && *g_DynamicUpdateLocalDir) {
  111. //
  112. // use a hardcoded path here; we know DynamicUpdate uses this folder to
  113. // store downloaded INFs
  114. //
  115. TempStr = JoinPaths (g_DynamicUpdateLocalDir, S_UPGINFSDIR);
  116. //
  117. // Update the list of INF modifications in %windir%\setupupd\upginfs.
  118. //
  119. if (InitInfReplaceTable (TempStr)) {
  120. //
  121. // reload win95upg.inf to make sure it's up-to-date
  122. //
  123. if (!pReloadWin95upgInf ()) {
  124. LOG ((LOG_FATAL_ERROR, (PCSTR)MSG_WIN95UPG_RELOAD_FAILED, g_Win95UpgInfFile));
  125. __leave;
  126. }
  127. }
  128. FreePathString (TempStr);
  129. }
  130. //
  131. // Update the configuration settings (i.e. WINNT32 command line options)
  132. //
  133. if (!Cfg_InitializeUserOptions()) {
  134. if (!g_ConfigOptions.Help) {
  135. LOG ((LOG_FATAL_ERROR, (PCSTR)MSG_DEFERRED_INIT_FAILED_POPUP));
  136. }
  137. __leave;
  138. }
  139. //
  140. // Initialize safe/recovery mechanism
  141. //
  142. SafeModeInitialize (g_ConfigOptions.SafeMode);
  143. //
  144. // Initialize our fake NT environment block
  145. //
  146. InitNtEnvironment();
  147. //
  148. // Save parent window
  149. //
  150. g_ParentWndAlwaysValid = pFindProcessWindow();
  151. if (!g_ParentWndAlwaysValid) {
  152. DEBUGMSG ((DBG_WHOOPS, "Cannot find parent window handle!"));
  153. g_ParentWndAlwaysValid = GetParent(WizardPageHandle);
  154. }
  155. //
  156. // Make a symbol that is NULL in unattend mode, and a valid parent window
  157. // handle otherwise. This is used by migration DLLs and LOG functions.
  158. //
  159. g_ParentWnd = UNATTENDED() ? NULL : g_ParentWndAlwaysValid;
  160. LogReInit (&g_ParentWnd, NULL);
  161. //
  162. // Get information about the system we are running on...This can be very useful.
  163. //
  164. speed = pGetProcessorSpeed(&family);
  165. memoryStatus.dwLength = sizeof(MEMORYSTATUS);
  166. GlobalMemoryStatus(&memoryStatus);
  167. LOG((
  168. LOG_INFORMATION,
  169. "System Statistics:\n Family: %s\n Processor Speed: %u mhz\n Memory: %u bytes",
  170. family ? family : "Unknown",
  171. speed,
  172. memoryStatus.dwTotalPhys
  173. ));
  174. if (!Cfg_CreateWorkDirectories()) {
  175. LOG ((LOG_FATAL_ERROR, (PCSTR)MSG_COULD_NOT_CREATE_DIRECTORY));
  176. __leave;
  177. }
  178. //
  179. // Start background copy thread
  180. //
  181. StartCopyThread();
  182. //
  183. // Get NT Profile dir.
  184. //
  185. Size = sizeof (ProfileTemp) / sizeof (ProfileTemp[0]);
  186. if (!pGetProfilesDirectory (ProfileTemp, &Size)) {
  187. LOG ((LOG_FATAL_ERROR, (PCSTR)MSG_DEFERRED_INIT_FAILED_POPUP));
  188. __leave;
  189. }
  190. //
  191. // replace any NT string env vars with actual values
  192. //
  193. ExpandNtEnvironmentVariables (ProfileTemp, ProfileTemp, sizeof (ProfileTemp));
  194. g_ProfileDirNt = PoolMemDuplicateString (g_GlobalPool, ProfileTemp);
  195. DEBUGMSG ((DBG_NAUSEA, "NT profile dir: %s", g_ProfileDirNt));
  196. //
  197. // Put current user name in the setup key
  198. //
  199. Size = ARRAYSIZE (ProfileTemp);
  200. if (GetUserName (ProfileTemp, &Size)) {
  201. key = CreateRegKeyStr (S_WIN9XUPG_KEY);
  202. if (key) {
  203. RegSetValueEx (
  204. key,
  205. S_CURRENT_USER_VALUENAME,
  206. 0,
  207. REG_SZ,
  208. (PBYTE) ProfileTemp,
  209. SizeOfString (ProfileTemp)
  210. );
  211. CloseRegKey (key);
  212. }
  213. }
  214. //
  215. // Open txtsetup.sif
  216. //
  217. if (g_TxtSetupSif == INVALID_HANDLE_VALUE) {
  218. g_TxtSetupSif = InfOpenInfInAllSources (S_TXTSETUP_SIF);
  219. if (g_TxtSetupSif == INVALID_HANDLE_VALUE) {
  220. LOG ((LOG_FATAL_ERROR, (PCSTR)MSG_TXTSETUP_SIF_ERROR));
  221. __leave;
  222. }
  223. }
  224. if (!BeginMigrationDllProcessing()) {
  225. DEBUGMSG ((DBG_WARNING, "BeginMigrationDllProcessing returned FALSE"));
  226. __leave;
  227. }
  228. if (!InitAccessibleDrives()) {
  229. __leave;
  230. }
  231. //
  232. // exclude all of the directories in source directories and optional directories from processing.
  233. //
  234. for (index = 0; index < SOURCEDIRECTORYCOUNT(); index++) {
  235. ExcludePath (g_ExclusionValue, SOURCEDIRECTORY(index));
  236. }
  237. for (index = 0; index < OPTIONALDIRECTORYCOUNT(); index++) {
  238. ExcludePath (g_ExclusionValue, OPTIONALDIRECTORY(index));
  239. }
  240. //
  241. // also exclude the directory used by Dynamic Setup
  242. //
  243. if (g_DynamicUpdateLocalDir && *g_DynamicUpdateLocalDir) {
  244. ExcludePath (g_ExclusionValue, g_DynamicUpdateLocalDir);
  245. }
  246. //
  247. // Put original boot.ini, bootfont.bin, ntdetect.com, ntldr and boot
  248. // sector in setup temp dir
  249. //
  250. if (g_BootDrivePath && g_TempDir) {
  251. if (!pPutBootFileInUninstallTempDir (S_BOOTINI, S_BOOTINI_BACKUP)) {
  252. __leave;
  253. }
  254. if (!pPutBootFileInUninstallTempDir (S_BOOTFONT_BIN, S_BOOTFONT_BACKUP)) {
  255. __leave;
  256. }
  257. if (!pPutBootFileInUninstallTempDir (S_NTDETECT, S_NTDETECT_BACKUP)) {
  258. __leave;
  259. }
  260. if (!pPutBootFileInUninstallTempDir (S_NTLDR, S_NTLDR_BACKUP)) {
  261. __leave;
  262. }
  263. if (ReadDiskSectors (
  264. *g_BootDrive,
  265. FAT_STARTING_SECTOR,
  266. FAT_BOOT_SECTOR_COUNT,
  267. FAT_BOOT_SECTOR_SIZE,
  268. bootSector
  269. )) {
  270. StringCopy (dest, g_TempDir);
  271. StringCopy (AppendWack (dest), S_BOOTSECT_BACKUP);
  272. fileHandle = CreateFile (
  273. dest,
  274. GENERIC_WRITE,
  275. 0,
  276. NULL,
  277. CREATE_ALWAYS,
  278. FILE_ATTRIBUTE_NORMAL,
  279. NULL
  280. );
  281. if (fileHandle == INVALID_HANDLE_VALUE) {
  282. DEBUGMSG ((DBG_ERROR, "Can't create %s", dest));
  283. __leave;
  284. }
  285. if (!WriteFile (fileHandle, bootSector, sizeof (bootSector), &dontCare, NULL)) {
  286. DEBUGMSG ((DBG_ERROR, "Can't write boot sector to %s", dest));
  287. __leave;
  288. }
  289. }
  290. } else {
  291. MYASSERT (FALSE);
  292. __leave;
  293. }
  294. result = TRUE;
  295. }
  296. __finally {
  297. if (fileHandle != INVALID_HANDLE_VALUE) {
  298. CloseHandle (fileHandle);
  299. }
  300. }
  301. return result;
  302. }
  303. BOOL
  304. pGetProfilesDirectory (
  305. OUT PTSTR Path, OPTIONAL
  306. IN OUT PDWORD Size
  307. )
  308. /*++
  309. Routine Description:
  310. pGetProfileDirectory emulates the NT 5 API GetProfileDirectory. It looks in
  311. hivesft.inf for Winlogon's ProfilesDirectory key. If an override to the NT
  312. profile directory is given in the winnt.sif file, then the override is used
  313. instead.
  314. Arguments:
  315. Path - Receives the user profile path
  316. Size - Specifies the size of Path, in TCHAR characters. Receives the number
  317. of characters needed to hold the profile path.
  318. Return Value:
  319. TRUE if the API succeeds, or FALSE if an unexpected error occurs.
  320. --*/
  321. {
  322. TCHAR Buffer[MAX_TCHAR_PATH];
  323. PCTSTR p;
  324. BOOL b;
  325. DWORD SizeNeeded;
  326. PCTSTR EndOfString;
  327. PCTSTR UserProfiles;
  328. if (!Size) {
  329. return FALSE;
  330. }
  331. MYASSERT (g_WinDir);
  332. MYASSERT (g_SourceDirectoryCountFromWinnt32);
  333. //
  334. // Look in answer file for setting, use it if it exists
  335. //
  336. Buffer[0] = 0;
  337. if (g_UnattendScriptFile && *g_UnattendScriptFile) {
  338. GetPrivateProfileString (
  339. S_GUIUNATTENDED,
  340. S_PROFILEDIR,
  341. S_EMPTY,
  342. Buffer,
  343. MAX_TCHAR_PATH,
  344. *g_UnattendScriptFile
  345. );
  346. }
  347. if (!(*Buffer)) {
  348. //
  349. // Default to %systemroot%\Documents and Settings
  350. //
  351. UserProfiles = GetStringResource (MSG_USER_PROFILE_ROOT);
  352. MYASSERT (UserProfiles);
  353. StringCopy (Buffer, UserProfiles);
  354. FreeStringResource (UserProfiles);
  355. }
  356. Buffer[MAX_TCHAR_PATH - 1] = 0; // user can pass in anything via answer file!
  357. SizeNeeded = ByteCount (Buffer) / sizeof (TCHAR);
  358. if (Path) {
  359. b = *Size >= SizeNeeded;
  360. if (*Size) {
  361. EndOfString = GetEndOfString (Buffer);
  362. p = min (EndOfString, Buffer + *Size);
  363. StringCopyAB (Path, Buffer, p);
  364. }
  365. } else {
  366. b = TRUE;
  367. }
  368. *Size = SizeNeeded;
  369. return b;
  370. }
  371. typedef struct {
  372. DWORD ProcessId;
  373. HWND hwnd;
  374. } FINDPROCESSWINDOW, *PFINDPROCESSWINDOW;
  375. BOOL
  376. CALLBACK
  377. pFindProcessWindowCallback (
  378. HWND hwnd,
  379. LPARAM lParam
  380. )
  381. /*++
  382. Routine Description:
  383. pFindProcessWindowCallback is called by the window enumeration started by
  384. pFindProcessWindow. If the process ID of the window matches our process
  385. ID, then the enumeration is stopped so the proper window handle can
  386. be returned by pFindProcessWindow.
  387. Arguments:
  388. hwnd - Specifies the current enumerated window handle
  389. lParam - Specifies the FINDPROCESSWINDOW structure allocated by
  390. pFindProcessWindow
  391. Return Value:
  392. TRUE if enuemration should continue, or FALSE if it should stop.
  393. --*/
  394. {
  395. PFINDPROCESSWINDOW p;
  396. DWORD ProcessId = 0;
  397. p = (PFINDPROCESSWINDOW) lParam;
  398. GetWindowThreadProcessId (hwnd, &ProcessId);
  399. if (ProcessId == p->ProcessId) {
  400. p->hwnd = hwnd;
  401. return FALSE;
  402. }
  403. return TRUE;
  404. }
  405. HWND
  406. pFindProcessWindow (
  407. VOID
  408. )
  409. /*++
  410. Routine Description:
  411. pFindProcessWindow enumerates all windows and returns the first one that
  412. the current process owns. There should only be one, so the end result
  413. is a handle to the main window of the process.
  414. Arguments:
  415. none
  416. Return Value:
  417. A handle to the process main window, or NULL if no windows exist for
  418. the process.
  419. --*/
  420. {
  421. FINDPROCESSWINDOW Enum;
  422. ZeroMemory (&Enum, sizeof (Enum));
  423. Enum.ProcessId = GetCurrentProcessId();
  424. EnumWindows (pFindProcessWindowCallback, (LPARAM) &Enum);
  425. return Enum.hwnd;
  426. }
  427. INT
  428. pGetProcessorSpeed (
  429. OUT PTSTR *Family
  430. )
  431. /*++
  432. Routine Description:
  433. pGetProcessorSpeed returns the speed in MHz of the computer, and identifies
  434. the processor if it is a Pentium or better. Code from Todd Laney (toddla).
  435. Arguments:
  436. Family - Receives a pointer to the name of the processor family
  437. Return Value:
  438. The speed of the processor, in MHz.
  439. --*/
  440. {
  441. SYSTEM_INFO si;
  442. __int64 start, end, freq;
  443. INT flags,family;
  444. INT time;
  445. INT clocks;
  446. DWORD oldclass;
  447. HANDLE hprocess;
  448. INT familyIndex = 0;
  449. static PTSTR familyStrings[] = {
  450. "Unknown (0)",
  451. "Unknown (1)",
  452. "Unknown (2)",
  453. "x386",
  454. "x486",
  455. "Pentium",
  456. "Pentium Pro",
  457. "Pentium II (?)",
  458. "Unknown..."
  459. };
  460. *Family = NULL;
  461. ZeroMemory(&si, sizeof(si));
  462. GetSystemInfo(&si);
  463. //Set the family. If wProcessorLevel is not specified, dig it out of dwProcessorType
  464. //Because wProcessor level is not implemented on Win95
  465. if (si.wProcessorLevel) {
  466. family = si.wProcessorLevel;
  467. } else {
  468. family = 0;
  469. //Ok, we're on Win95
  470. switch (si.dwProcessorType) {
  471. case PROCESSOR_INTEL_386:
  472. familyIndex=3;
  473. break;
  474. case PROCESSOR_INTEL_486:
  475. familyIndex=4;
  476. break;
  477. default:
  478. familyIndex=0;
  479. break;
  480. }
  481. }
  482. //
  483. // make sure this is a INTEL Pentium (or clone) or higher.
  484. //
  485. if (si.wProcessorArchitecture != PROCESSOR_ARCHITECTURE_INTEL)
  486. return 0;
  487. if (si.dwProcessorType < PROCESSOR_INTEL_PENTIUM)
  488. return 0;
  489. //
  490. // see if this chip supports rdtsc before using it.
  491. //
  492. __try
  493. {
  494. _asm
  495. {
  496. mov eax,1
  497. _emit 00Fh ;; CPUID
  498. _emit 0A2h
  499. mov flags,edx
  500. mov family,eax
  501. }
  502. }
  503. __except(1)
  504. {
  505. flags = 0;
  506. }
  507. //check for support of CPUID and fail
  508. if (!(flags & 0x10))
  509. return 0;
  510. //If we don't have a family, set it now
  511. //Family is bits 11:8 of eax from CPU, with eax=1
  512. if (!familyIndex) {
  513. familyIndex=(family & 0x0F00) >> 8;
  514. }
  515. hprocess = GetCurrentProcess();
  516. oldclass = GetPriorityClass(hprocess);
  517. SetPriorityClass(hprocess, REALTIME_PRIORITY_CLASS);
  518. Sleep(10);
  519. QueryPerformanceFrequency((LARGE_INTEGER*)&freq);
  520. QueryPerformanceCounter((LARGE_INTEGER*)&start);
  521. _asm
  522. {
  523. _emit 0Fh ;; RDTSC
  524. _emit 31h
  525. mov ecx,100000
  526. x: dec ecx
  527. jnz x
  528. mov ebx,eax
  529. _emit 0Fh ;; RDTSC
  530. _emit 31h
  531. sub eax,ebx
  532. mov dword ptr clocks[0],eax
  533. }
  534. QueryPerformanceCounter((LARGE_INTEGER*)&end);
  535. SetPriorityClass(hprocess, oldclass);
  536. time = MulDiv((int)(end-start),1000000,(int)freq);
  537. if (familyIndex > 7) {
  538. familyIndex = 7;
  539. }
  540. *Family = familyStrings[familyIndex];
  541. return (clocks + time/2) / time;
  542. }