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.

3821 lines
99 KiB

  1. /*++
  2. Copyright (c) 1996 Microsoft Corporation
  3. Module Name:
  4. migmain.c
  5. Abstract:
  6. MigMain is called from w95upgnt.dll, which is called from SYSSETUP.DLL.
  7. It is the main migration loop on the NT side of setup. MigMain loops
  8. through all users on the Win95 side of configuration, migrates their
  9. registry, creates their account, and fixes up their profile folders.
  10. Then MigMain migrates all machine-specific settings such as link changes
  11. and file deletion.
  12. Author:
  13. Jim Schmidt (jimschm) 12-Jul-1996
  14. Revision History:
  15. marcw 26-Mar-1999 More boot16 fixes -- hide msdos7 dir, fix to msdos.sys
  16. marcw 18-Mar-1999 fixes for boot16 environment in localized case.
  17. jimschm 23-Sep-1998 Changes for fileops & shell.c
  18. calinn 23-Sep-1998 Changes for memdb fixup
  19. jimschm 02-Jul-1998 Support for progress bar
  20. jimschm 11-Jun-1998 Support for dynamic user profile paths in memdb
  21. jimschm 05-May-1998 Migration of Default User if unattend option is enabled
  22. jimschm 27-Apr-1998 Added icon preservation
  23. jimschm 18-Mar-1998 Added pProcessAutoLogon
  24. calinn 19-Nov-1997 Added pEnable16Boot, will create a 16 bit environment boot entry in boot.ini
  25. jimschm 01-Oct-1997 Localized Everyone group
  26. jimschm 13-Sep-1997 Reg Quota for beta 1 workaround
  27. jimschm 21-Jul-1997 Use of fileops for ConvertWin9xPath (to be moved later)
  28. jimschm 28-May-1997 Cleaned up
  29. marcw 21-Mar-1997 added Pathmapping
  30. jimschm 04-Feb-1997 Moved code into usermig.c and wkstamig.c
  31. jimschm 15-Jan-1997 Plug-in spec modifications (now in migdlls.c)
  32. jimschm 03-Jan-1997 Added g_UserName
  33. jimschm 18-Dec-1996 Extracted code from miginf
  34. mikeco O4-Dec-1996 Enumerate/modify PIF and LNK files
  35. jimschm 23-Oct-1996 Joined ProcessUserInfs and ApplyChanges
  36. jimschm 02-Oct-1996 Added default user migration
  37. --*/
  38. #include "pch.h"
  39. #include "migmainp.h"
  40. #include "fileops.h"
  41. #include "quota.h"
  42. #ifndef UNICODE
  43. #error UNICODE required
  44. #endif
  45. #ifdef DEBUG
  46. BOOL g_NoReloadsAllowed = FALSE;
  47. #define DBG_VALIDNTFILES "NtFiles"
  48. #endif
  49. typedef BOOL (*PROFILE_PATH_PROVIDER)(OUT PTSTR AccountName, OUT PTSTR PathProfile);
  50. //
  51. // Globals for migmain.lib
  52. //
  53. HKEY g_hKeyRoot95, g_hKeyRootNT;
  54. PCTSTR g_DomainUserName;
  55. PCTSTR g_Win9xUserName;
  56. PCTSTR g_FixedUserName;
  57. PVOID g_HiveTable;
  58. POOLHANDLE g_HivePool;
  59. PVOID g_NulSessionTable;
  60. PCTSTR g_EveryoneStr;
  61. PCTSTR g_AdministratorsGroupStr;
  62. PCTSTR g_PowerUsersGroupStr;
  63. PCTSTR g_DomainUsersGroupStr;
  64. PCTSTR g_NoneGroupStr;
  65. TCHAR g_IconBin[MAX_TCHAR_PATH];
  66. TCHAR g_DefaultUserName[MAX_USER_NAME];
  67. TCHAR g_ComputerName[MAX_SERVER_NAME];
  68. BOOL g_BlowAwayTempShellFolders = FALSE;
  69. UINT g_Boot16 = BOOT16_AUTOMATIC;
  70. //
  71. // Buffer for GetString's messages
  72. //
  73. static TCHAR g_MsgBuf[2048];
  74. //
  75. // Flag identifying if the SKU is Personal
  76. //
  77. BOOL g_PersonalSKU = FALSE;
  78. //
  79. // Prototypes for migmain.c only
  80. //
  81. BOOL
  82. pSetWin9xUpgValue (
  83. VOID
  84. );
  85. VOID
  86. pCountUsers (
  87. OUT PDWORD TotalUsersPtr,
  88. OUT PDWORD ActiveUsersPtr
  89. );
  90. BOOL
  91. pMigrateUsers (
  92. VOID
  93. );
  94. VOID
  95. pRaiseRegistryQuota (
  96. PCTSTR Win9xSystemDatSpec
  97. );
  98. VOID
  99. pEnable16Boot (
  100. VOID
  101. );
  102. VOID
  103. pProcessAutoLogon (
  104. BOOL Final
  105. );
  106. VOID
  107. pFixUpMemDb (
  108. VOID
  109. );
  110. BOOL
  111. WINAPI
  112. MigMain_Entry (
  113. IN HINSTANCE hinstDLL,
  114. IN DWORD dwReason,
  115. IN PVOID lpv
  116. )
  117. /*++
  118. Routine Description:
  119. MigMain_Entry is called at DLL initialization time
  120. Arguments:
  121. hinstDLL - (OS-supplied) Instance handle for the DLL
  122. dwReason - (OS-supplied) Type of initialization or termination
  123. lpv - (OS-supplied) Unused
  124. Return Value:
  125. TRUE because LIB always initializes properly.
  126. --*/
  127. {
  128. DWORD Size;
  129. OSVERSIONINFOEX osviex;
  130. switch (dwReason) {
  131. case DLL_PROCESS_ATTACH:
  132. if(!pSetupInitializeUtils()) {
  133. return FALSE;
  134. }
  135. g_hKeyRoot95 = g_hKeyRootNT = NULL;
  136. g_HivePool = PoolMemInitNamedPool ("Hive path pool");
  137. if (!g_HivePool) {
  138. return FALSE;
  139. }
  140. // Alloc string tables
  141. g_HiveTable = pSetupStringTableInitializeEx (MAX_TCHAR_PATH,0);
  142. if (!g_HiveTable) {
  143. return FALSE;
  144. }
  145. g_NulSessionTable = pSetupStringTableInitializeEx (sizeof(PCWSTR), 0);
  146. if (!g_NulSessionTable) {
  147. return FALSE;
  148. }
  149. //
  150. // Determine if upgrading to Personal SKU
  151. //
  152. osviex.dwOSVersionInfoSize = sizeof (OSVERSIONINFOEX);
  153. if (!GetVersionEx ((LPOSVERSIONINFO)&osviex)) {
  154. MYASSERT (FALSE);
  155. }
  156. if (osviex.wProductType == VER_NT_WORKSTATION &&
  157. (osviex.wSuiteMask & VER_SUITE_PERSONAL)
  158. ) {
  159. g_PersonalSKU = TRUE;
  160. }
  161. #if 0
  162. if (g_PersonalSKU) {
  163. g_EveryoneStr = GetStringResource (MSG_EVERYONE_GROUP);
  164. g_AdministratorsGroupStr = GetStringResource (MSG_OWNERS_GROUP);
  165. g_PowerUsersGroupStr = GetStringResource (MSG_POWER_USERS_GROUP);
  166. g_DomainUsersGroupStr = GetStringResource (MSG_DOMAIN_USERS_GROUP);
  167. g_NoneGroupStr = GetStringResource (MSG_NONE_GROUP);
  168. } else {
  169. #endif
  170. g_EveryoneStr = GetStringResource (MSG_EVERYONE_GROUP);
  171. g_AdministratorsGroupStr = GetStringResource (MSG_ADMINISTRATORS_GROUP);
  172. g_PowerUsersGroupStr = GetStringResource (MSG_POWER_USERS_GROUP);
  173. g_DomainUsersGroupStr = GetStringResource (MSG_DOMAIN_USERS_GROUP);
  174. g_NoneGroupStr = GetStringResource (MSG_NONE_GROUP);
  175. Size = ARRAYSIZE(g_ComputerName);
  176. if (!GetComputerName (g_ComputerName, &Size)) {
  177. g_ComputerName[0] = 0;
  178. }
  179. MYASSERT (
  180. g_ComputerName[0] &&
  181. g_EveryoneStr &&
  182. g_AdministratorsGroupStr &&
  183. g_PowerUsersGroupStr &&
  184. g_DomainUsersGroupStr &&
  185. g_NoneGroupStr
  186. );
  187. FindAccountInit();
  188. break;
  189. case DLL_PROCESS_DETACH:
  190. if (g_HiveTable) {
  191. pSetupStringTableDestroy (g_HiveTable);
  192. }
  193. if (g_NulSessionTable) {
  194. pSetupStringTableDestroy (g_NulSessionTable);
  195. }
  196. if (g_HivePool) {
  197. PoolMemDestroyPool (g_HivePool);
  198. }
  199. FreeStringResource (g_EveryoneStr);
  200. FreeStringResource (g_AdministratorsGroupStr);
  201. FreeStringResource (g_DomainUsersGroupStr);
  202. FindAccountTerminate();
  203. pSetupUninitializeUtils();
  204. break;
  205. }
  206. return TRUE;
  207. }
  208. #ifdef DEBUG
  209. BOOL
  210. pValidateNtFiles (
  211. VOID
  212. )
  213. /*++
  214. Routine Description:
  215. pValidateNtFiles validates the list of files that are supposed to be installed
  216. by NT. We check for the flag set on Win95 side and for each entry we check to
  217. see if the file is realy present (e.g. was installed by NT). If not then we delete
  218. the entry.
  219. Arguments:
  220. none
  221. Return Value:
  222. Always returns TRUE
  223. --*/
  224. {
  225. MEMDB_ENUMW enumFiles;
  226. WCHAR key[MEMDB_MAX];
  227. PWSTR fileName;
  228. TREE_ENUMW enumTree;
  229. DWORD value;
  230. if (MemDbEnumFirstValue (
  231. &enumFiles,
  232. TEXT(MEMDB_CATEGORY_NT_FILESA)TEXT("\\*"),
  233. MEMDB_ALL_SUBLEVELS,
  234. MEMDB_ENDPOINTS_ONLY
  235. )) {
  236. do {
  237. if (MemDbBuildKeyFromOffsetW (enumFiles.dwValue, key, 1, NULL)) {
  238. fileName = JoinPaths (key, enumFiles.szName);
  239. if (!DoesFileExistW (fileName)) {
  240. MemDbSetValueEx (
  241. MEMDB_CATEGORY_NT_FILES_BAD,
  242. enumFiles.szName,
  243. NULL,
  244. NULL,
  245. enumFiles.dwValue,
  246. NULL
  247. );
  248. }
  249. FreePathString (fileName);
  250. }
  251. ELSE_DEBUGMSG ((DBG_WHOOPS, "NT_FILES : cannot find installation directory."));
  252. }
  253. while (MemDbEnumNextValue (&enumFiles));
  254. }
  255. // now we have in MEMDB_CATEGORY_NT_FILES_BAD all files that should be installed
  256. // by NT but are not. Now we are going to scan the file system and see if they are
  257. // installed in a different place.
  258. if (EnumFirstFileInTreeEx (&enumTree, g_WinDrive, TEXT("*.*"), FALSE, FALSE, FILE_ENUM_ALL_LEVELS)) {
  259. do {
  260. MemDbBuildKey (key, MEMDB_CATEGORY_NT_FILES_BAD, enumTree.Name, NULL, NULL);
  261. if (MemDbGetValue (key, &value) && (value != 0)) {
  262. MemDbSetValue (key, 0);
  263. MemDbBuildKeyFromOffsetW (value, key, 1, NULL);
  264. DEBUGMSG ((
  265. DBG_VALIDNTFILES,
  266. "%s listed to be installed in %s but installed in %s",
  267. enumTree.Name,
  268. key,
  269. enumTree.FullPath));
  270. }
  271. } while (EnumNextFileInTree (&enumTree));
  272. }
  273. MemDbBuildKey (key, MEMDB_CATEGORY_NT_FILES_BAD, TEXT("*"), NULL, NULL);
  274. if (MemDbEnumFirstValue (
  275. &enumFiles,
  276. key,
  277. MEMDB_ALL_SUBLEVELS,
  278. MEMDB_ENDPOINTS_ONLY
  279. )) {
  280. do {
  281. if (enumFiles.dwValue) {
  282. MemDbBuildKeyFromOffsetW (enumFiles.dwValue, key, 1, NULL);
  283. DEBUGMSG ((
  284. DBG_VALIDNTFILES,
  285. "%s listed to be installed in %s but never installed",
  286. enumFiles.szName,
  287. key,
  288. enumTree.FullPath));
  289. }
  290. }
  291. while (MemDbEnumNextValue (&enumFiles));
  292. }
  293. return TRUE;
  294. }
  295. #endif
  296. DWORD
  297. pGetState (
  298. IN PCTSTR Item
  299. )
  300. {
  301. DWORD Value;
  302. TCHAR Node[MEMDB_MAX];
  303. MemDbBuildKey (Node, MEMDB_CATEGORY_STATE, Item, NULL, NULL);
  304. if (MemDbGetValue (Node, &Value)) {
  305. return Value;
  306. }
  307. return 0;
  308. }
  309. BOOL
  310. MigMain_Init (
  311. VOID
  312. )
  313. /*++
  314. Routine Description:
  315. MigMain_Init is called for initialization, and has a better opportunity
  316. to fail than MigMain_Entry (which is called during DllMain).
  317. Arguments:
  318. none
  319. Return Value:
  320. TRUE if initialization succeeded, or FALSE if an error occurred.
  321. Call GetLastError() for error code.
  322. --*/
  323. {
  324. DWORD rc; // Temp: return code
  325. TCHAR RelocWinDir[MAX_TCHAR_PATH];
  326. TCHAR SrcResBin[MAX_TCHAR_PATH];
  327. TCHAR IconFile[MAX_TCHAR_PATH];
  328. ICON_EXTRACT_CONTEXT Context;
  329. WORD CodePage;
  330. LCID Locale;
  331. TCHAR Node[MEMDB_MAX];
  332. DWORD minorVersion;
  333. #ifdef DEBUG
  334. HANDLE hFile;
  335. HKEY DebugKey = NULL;
  336. CHAR Buf[32];
  337. DWORD Value;
  338. #endif
  339. #ifdef PRERELEASE
  340. //
  341. // !!! This is for internal use only !!! It is used for auto stress.
  342. //
  343. if (g_ConfigOptions.AutoStress) {
  344. SuppressAllLogPopups (TRUE);
  345. }
  346. #endif
  347. //
  348. // Dev: load c:\windbg.reg if it exists
  349. //
  350. #ifdef DEBUG
  351. __try {
  352. TCHAR WindbgRegPath[MAX_PATH] = TEXT("c:\\windbg.reg");
  353. //
  354. // Intentional hard-coded path!! This is for dev purposes only.
  355. //
  356. WindbgRegPath[0] = g_System32Dir[0];
  357. if (!DoesFileExist (WindbgRegPath)) {
  358. StringCopy (WindbgRegPath, TEXT("d:\\tools\\windbg.reg"));
  359. }
  360. hFile = CreateFile (
  361. WindbgRegPath,
  362. GENERIC_READ,
  363. 0,
  364. NULL,
  365. OPEN_EXISTING,
  366. FILE_ATTRIBUTE_NORMAL,
  367. NULL
  368. );
  369. if (hFile != INVALID_HANDLE_VALUE) {
  370. CloseHandle (hFile);
  371. rc = TrackedRegOpenKey (HKEY_CURRENT_USER, TEXT("Software\\Microsoft\\Windbg"), &DebugKey);
  372. if (rc == ERROR_SUCCESS) {
  373. DEBUGMSG ((DBG_VERBOSE, "Not restoring windbg.reg because it was already restored."));
  374. __leave;
  375. }
  376. else {
  377. rc = TrackedRegCreateKey (HKEY_CURRENT_USER, TEXT("Software\\Microsoft\\Windbg"), &DebugKey);
  378. if (rc == ERROR_SUCCESS) {
  379. if (!pSetupEnablePrivilege (SE_BACKUP_NAME, TRUE)) {
  380. DEBUGMSG ((DBG_ERROR, "Windbg restore: pSetupEnablePrivilege SE_BACKUP_NAME failed"));
  381. //__leave;
  382. }
  383. if (!pSetupEnablePrivilege (SE_RESTORE_NAME, TRUE)) {
  384. DEBUGMSG ((DBG_ERROR, "Windbg restore: pSetupEnablePrivilege SE_RESTORE_NAME failed"));
  385. //__leave;
  386. }
  387. rc = RegRestoreKey (DebugKey, WindbgRegPath, 0);
  388. if (rc != ERROR_SUCCESS) {
  389. DEBUGMSG ((DBG_WARNING, "Unable to restore windbg.reg, gle=%u", rc));
  390. }
  391. }
  392. }
  393. }
  394. }
  395. __finally {
  396. if (DebugKey) {
  397. CloseRegKey (DebugKey);
  398. }
  399. }
  400. //
  401. // If debug.inf has a line UserEnv=1, then add a registry key to debug userenv.dll
  402. //
  403. if (GetPrivateProfileStringA (
  404. "Debug",
  405. "UserEnv",
  406. "0",
  407. Buf,
  408. sizeof (Buf) / sizeof (Buf[0]),
  409. g_DebugInfPath
  410. )
  411. ) {
  412. if (atoi (Buf)) {
  413. rc = TrackedRegCreateKey (
  414. HKEY_LOCAL_MACHINE,
  415. TEXT("Software\\Microsoft\\Windows NT\\CurrentVersion\\Winlogon"),
  416. &DebugKey
  417. );
  418. if (rc == ERROR_SUCCESS) {
  419. Value = 0x00010002;
  420. RegSetValueEx (
  421. DebugKey,
  422. TEXT("UserEnvDebugLevel"),
  423. 0,
  424. REG_DWORD,
  425. (PBYTE) &Value,
  426. sizeof (DWORD)
  427. );
  428. CloseRegKey (DebugKey);
  429. }
  430. }
  431. }
  432. #endif
  433. //
  434. // Initialize the registry APIs
  435. //
  436. // We look in memdb for the location of .default
  437. //
  438. if (!MemDbLoad (GetMemDbDat())) {
  439. LOG ((LOG_ERROR, "MigMain Init: MemDbLoad could not load %s", GetMemDbDat()));
  440. return FALSE;
  441. }
  442. //
  443. // Get platform name
  444. //
  445. if (!MemDbGetEndpointValueEx (
  446. MEMDB_CATEGORY_STATE,
  447. MEMDB_ITEM_PLATFORM_NAME,
  448. NULL,
  449. g_Win95Name
  450. )) {
  451. LOG ((LOG_ERROR, "Could not find product name for OS being upgraded."));
  452. StringCopy (g_Win95Name, TEXT("Windows 95"));
  453. }
  454. // Try Paths\Windir first
  455. if (!MemDbGetEndpointValueEx (
  456. MEMDB_CATEGORY_PATHS,
  457. MEMDB_ITEM_RELOC_WINDIR,
  458. NULL,
  459. RelocWinDir
  460. )) {
  461. LOG ((LOG_ERROR, "Could not find relocated windir!"));
  462. return FALSE;
  463. }
  464. //
  465. // if upgrading from Millennium, also map classes.dat
  466. //
  467. MemDbBuildKey (Node, MEMDB_CATEGORY_STATE, MEMDB_ITEM_MINOR_VERSION, NULL, NULL);
  468. if (!MemDbGetValue (Node, &minorVersion)) {
  469. LOG ((LOG_ERROR, "Could not get previous OS version information!"));
  470. minorVersion = 0;
  471. }
  472. rc = Win95RegInit (RelocWinDir, minorVersion == 90);
  473. if (rc != ERROR_SUCCESS) {
  474. SetLastError (rc);
  475. LOG ((LOG_ERROR, "Init Processor: Win95RegInit failed (path: %s)", RelocWinDir));
  476. return FALSE;
  477. }
  478. //
  479. // Update locale
  480. //
  481. CodePage = (WORD) pGetState (MEMDB_ITEM_CODE_PAGE);
  482. Locale = (LCID) pGetState (MEMDB_ITEM_LOCALE);
  483. SetGlobalCodePage (CodePage, Locale);
  484. //
  485. // Prepare path to system.dat, then raise registry quota if necessary
  486. //
  487. StringCopy (AppendWack (RelocWinDir), TEXT("system.dat"));
  488. pRaiseRegistryQuota (RelocWinDir);
  489. //
  490. // Copy migisol.exe to migicons.exe
  491. //
  492. wsprintf (g_IconBin, TEXT("%s\\migicons.exe"), g_System32Dir);
  493. wsprintf (SrcResBin, TEXT("%s\\migisol.exe"), g_TempDir);
  494. if (!CopyFile (SrcResBin, g_IconBin, FALSE)) {
  495. LOG ((LOG_ERROR, "Can't copy %s to %s", SrcResBin, g_IconBin));
  496. }
  497. else {
  498. //
  499. // Insert all icons from migicons.dat into g_IconBin
  500. //
  501. __try {
  502. wsprintf (IconFile, TEXT("%s\\%s"), g_TempDir, S_MIGICONS_DAT);
  503. if (!BeginIconExtraction (&Context, g_IconBin)) {
  504. LOG ((LOG_ERROR, "Can't begin icon extraction"));
  505. __leave;
  506. }
  507. if (!OpenIconImageFile (&Context, IconFile, FALSE)) {
  508. LOG ((LOG_ERROR, "Can't open %s", IconFile));
  509. __leave;
  510. }
  511. while (CopyIcon (&Context, NULL, NULL, 0)) {
  512. // empty
  513. }
  514. }
  515. __finally {
  516. if (!EndIconExtraction (&Context)) {
  517. DEBUGMSG ((DBG_WARNING, "EndIconExtraction failed"));
  518. }
  519. }
  520. }
  521. #ifdef DEBUG
  522. // Validate MEMDB_CATEGORY_NT_FILES category. We need to find if the files
  523. // that were supposed to be installed by NT are really there.
  524. if (g_ConfigOptions.CheckNtFiles) {
  525. pValidateNtFiles ();
  526. }
  527. #endif
  528. return TRUE;
  529. }
  530. BOOL
  531. MigMain_Migrate (
  532. VOID
  533. )
  534. /*++
  535. Routine Description:
  536. MigMain_Migrate is the main migration function in NT GUI mode setup.
  537. w95upgnt.dll calls this function, and it is here that users are migrated,
  538. the local machine settings are migrated, and files are adjusted appropriately.
  539. See the file progress.c for a list of functions that are called.
  540. Arguments:
  541. none
  542. Return Value:
  543. TRUE if migration succeeded, or FALSE if an error occurred. Call
  544. GetLastError() for error code.
  545. --*/
  546. {
  547. BOOL Result;
  548. InitializeProgressBar (
  549. g_ProgressBar,
  550. NULL,
  551. NULL,
  552. NULL
  553. );
  554. PrepareMigrationProgressBar();
  555. pProcessAutoLogon (FALSE);
  556. g_BlowAwayTempShellFolders = TRUE;
  557. Result = CallAllMigrationFunctions();
  558. PushError();
  559. if (Result) {
  560. //
  561. // Save logon prompt settings and set up auto-logon
  562. //
  563. pProcessAutoLogon (TRUE);
  564. } else {
  565. g_BlowAwayTempShellFolders = FALSE;
  566. ClearAdminPassword();
  567. }
  568. //
  569. // All done!
  570. //
  571. TerminateProgressBar();
  572. PopError();
  573. return Result;
  574. }
  575. DWORD
  576. ResolveDomains (
  577. DWORD Request
  578. )
  579. {
  580. DWORD rc = ERROR_SUCCESS;
  581. TCHAR unattendFile[MAX_TCHAR_PATH];
  582. TCHAR buffer[32];
  583. switch (Request) {
  584. case REQUEST_QUERYTICKS:
  585. if (!IsMemberOfDomain()) {
  586. return 1;
  587. }
  588. return TICKS_DOMAIN_SEARCH;
  589. case REQUEST_RUN:
  590. //
  591. // If autologon is enabled, then force classic mode
  592. //
  593. wsprintf (unattendFile, TEXT("%s\\system32\\$winnt$.inf"), g_WinDir);
  594. if (GetPrivateProfileString (
  595. TEXT("GuiUnattended"),
  596. TEXT("AutoLogon"),
  597. TEXT(""),
  598. buffer,
  599. ARRAYSIZE(buffer),
  600. unattendFile
  601. )) {
  602. if (StringIMatch (buffer, TEXT("Yes"))) {
  603. DEBUGMSG ((DBG_VERBOSE, "Found autologon; forcing classic logon type"));
  604. SetClassicLogonType();
  605. }
  606. }
  607. //
  608. // Resolve the domains
  609. //
  610. if (!SearchDomainsForUserAccounts()) {
  611. LOG ((LOG_ERROR, "An error occurred searching for user domains. The upgrade failed."));
  612. rc = GetLastError();
  613. } else {
  614. //
  615. // Fix up memdb for dynamic user profile paths
  616. //
  617. pFixUpMemDb();
  618. }
  619. if (IsMemberOfDomain()) {
  620. TickProgressBarDelta (TICKS_DOMAIN_SEARCH);
  621. } else {
  622. TickProgressBar();
  623. }
  624. break;
  625. }
  626. return rc;
  627. }
  628. DWORD
  629. PrepareEnvironment (
  630. IN DWORD Request
  631. )
  632. {
  633. DWORD rc = ERROR_SUCCESS;
  634. switch (Request) {
  635. case REQUEST_QUERYTICKS:
  636. return TICKS_INIT;
  637. case REQUEST_RUN:
  638. //
  639. // Disable Win 3.1 migration dialog
  640. //
  641. pSetWin9xUpgValue();
  642. // Enable 16 bit environment boot
  643. pEnable16Boot();
  644. //
  645. // Enable privileges (req'd for several things)
  646. //
  647. if (!pSetupEnablePrivilege (SE_BACKUP_NAME, TRUE)) {
  648. LOG ((LOG_ERROR, "MigMain Migrate: pSetupEnablePrivilege SE_BACKUP_NAME failed"));
  649. //rc = GetLastError();
  650. //break;
  651. }
  652. if (!pSetupEnablePrivilege (SE_RESTORE_NAME, TRUE)) {
  653. LOG ((LOG_ERROR, "MigMain Migrate: pSetupEnablePrivilege SE_RESTORE_NAME failed"));
  654. //rc = GetLastError();
  655. //break;
  656. }
  657. TickProgressBarDelta (TICKS_INIT);
  658. break;
  659. }
  660. return rc;
  661. }
  662. BOOL
  663. MigMain_Cleanup (
  664. VOID
  665. )
  666. /*++
  667. Routine Description:
  668. MigMain_Cleanup is called to perform file removal. We delete everything
  669. that is in the memdb category DelFile, and we also try to clean up after
  670. MSN and other empty Win9x directories. Before exiting we delete our
  671. temporary directory.
  672. This function is called very last in Setup and is part of syssetup's
  673. cleanup.
  674. Arguments:
  675. none
  676. Return Value:
  677. TRUE when all file deletes were successful, FALSE if an error occurred.
  678. Call GetLastError for the reason of failure.
  679. --*/
  680. {
  681. BOOL b = TRUE;
  682. PCTSTR TempDir;
  683. TCHAR normalPath[] = S_SHELL_TEMP_NORMAL_PATH;
  684. TCHAR longPath[] = S_SHELL_TEMP_LONG_PATH;
  685. DRIVELETTERS drives;
  686. UINT u;
  687. #ifdef DEBUG
  688. INT n = 0;
  689. #endif
  690. // Remove everything in memdb's DelFile category
  691. b = DoFileDel();
  692. //
  693. // Clean up any remaining directories that are now empty, including shell
  694. // folder temp dirs
  695. //
  696. InitializeDriveLetterStructure (&drives);
  697. if (!g_BlowAwayTempShellFolders) {
  698. for (u = 0 ; u < NUMDRIVELETTERS ; u++) {
  699. if (drives.ExistsOnSystem[u] && drives.Type[u] == DRIVE_FIXED) {
  700. normalPath[0] = drives.Letter[u];
  701. longPath[0] = drives.Letter[u];
  702. MemDbSetValueEx (MEMDB_CATEGORY_CLEAN_UP_DIR, normalPath, NULL, NULL, 1, NULL);
  703. MemDbSetValueEx (MEMDB_CATEGORY_CLEAN_UP_DIR, longPath, NULL, NULL, 1, NULL);
  704. }
  705. }
  706. }
  707. RemoveEmptyDirs();
  708. if (!g_BlowAwayTempShellFolders) {
  709. //
  710. // Setup failed, clean up temp dir but leave it in place
  711. //
  712. for (u = 0 ; u < NUMDRIVELETTERS ; u++) {
  713. if (drives.ExistsOnSystem[u] && drives.Type[u] == DRIVE_FIXED) {
  714. normalPath[0] = drives.Letter[u];
  715. longPath[0] = drives.Letter[u];
  716. RemoveDirectory (normalPath);
  717. if (DoesFileExist (normalPath)) {
  718. LOG ((LOG_ERROR, (PCSTR) MSG_LEFT_TEMP_SHELL_FOLDERS, normalPath));
  719. }
  720. RemoveDirectory (longPath);
  721. if (DoesFileExist (longPath)) {
  722. LOG ((LOG_ERROR, (PCSTR) MSG_LEFT_TEMP_SHELL_FOLDERS, longPath));
  723. }
  724. }
  725. }
  726. } else {
  727. //
  728. // Setup was successful, blow away entire temp dir regardless of its content
  729. //
  730. for (u = 0 ; u < NUMDRIVELETTERS ; u++) {
  731. if (drives.ExistsOnSystem[u] && drives.Type[u] == DRIVE_FIXED) {
  732. normalPath[0] = drives.Letter[u];
  733. longPath[0] = drives.Letter[u];
  734. RemoveCompleteDirectory (normalPath);
  735. DEBUGMSG_IF ((
  736. DoesFileExist (normalPath),
  737. DBG_ERROR,
  738. "Temp dir cannot be removed: %s",
  739. normalPath
  740. ));
  741. RemoveCompleteDirectory (longPath);
  742. DEBUGMSG_IF ((
  743. DoesFileExist (longPath),
  744. DBG_ERROR,
  745. "Temp dir cannot be removed: %s",
  746. longPath
  747. ));
  748. }
  749. }
  750. }
  751. #ifdef DEBUG
  752. n = GetPrivateProfileIntA ("debug", "keeptempfiles", n, g_DebugInfPath);
  753. if (n) {
  754. return b;
  755. }
  756. #endif
  757. if (g_ConfigOptions.KeepTempFiles) {
  758. return b;
  759. }
  760. //
  761. // Blow away temp dir
  762. //
  763. TempDir = JoinPaths (g_WinDir, S_SETUP);
  764. b = DeleteDirectoryContents (TempDir);
  765. if (b) {
  766. b = RemoveDirectory (TempDir);
  767. if (!b) {
  768. LOG ((LOG_ERROR, "Could not delete the tree %s.", TempDir));
  769. }
  770. }
  771. else {
  772. LOG ((LOG_ERROR, "Could not delete the contents of %s.", TempDir));
  773. }
  774. FreePathString (TempDir);
  775. return b;
  776. }
  777. PCTSTR
  778. GetMemDbDat (
  779. VOID
  780. )
  781. /*++
  782. Routine Description:
  783. Returns a pointer to the path of the DAT file holding the Win9x memdb tree.
  784. Arguments:
  785. none
  786. Return Value:
  787. Returns a pointer to the Win32 path of ntsetup.dat.
  788. --*/
  789. {
  790. static TCHAR FileName[MAX_TCHAR_PATH];
  791. MYASSERT (!g_NoReloadsAllowed);
  792. StringCopy (FileName, g_TempDir);
  793. StringCopy (AppendWack (FileName), S_NTSETUPDAT);
  794. return FileName;
  795. }
  796. PCTSTR
  797. GetUserDatLocation (
  798. IN PCTSTR User,
  799. OUT PBOOL CreateOnlyFlag OPTIONAL
  800. )
  801. /*++
  802. Routine Description:
  803. Looks in memdb to locate the user.dat file for the specified user. On
  804. Win9x, migapp.lib writes a line to memdb giving the location of user.dat
  805. for each user, and the default user. This function retrieves that
  806. location to guarantee the same file is used on both NT and Win9x.
  807. Arguments:
  808. User - The fixed name of the user to process, or NULL for the default user.
  809. CreateOnlyFlag - Receives the create-only flag specified on the Win9x side
  810. of the upgrade. If this flag is TRUE, then the account
  811. should not be migrated.
  812. Return Value:
  813. Returns a pointer to the Win32 path of user.dat for the given user.
  814. If the entry does not exist, NULL will be returned, and the user
  815. will not be processed.
  816. --*/
  817. {
  818. MEMDB_ENUM e;
  819. static TCHAR UserDatLocation[MAX_TCHAR_PATH];
  820. if (!MemDbGetValueEx (&e, MEMDB_CATEGORY_USER_DAT_LOC, User, NULL)) {
  821. if (!StringIMatch (User, g_AdministratorStr)) {
  822. DEBUGMSG ((DBG_WARNING, "'UserDatLocation' for %s does not exist.", User?User:S_DOT_DEFAULT));
  823. }
  824. return NULL;
  825. }
  826. StringCopy (UserDatLocation, e.szName);
  827. if (CreateOnlyFlag) {
  828. *CreateOnlyFlag = (BOOL) e.dwValue;
  829. }
  830. return UserDatLocation;
  831. }
  832. VOID
  833. pSaveVersionStr (
  834. IN HKEY Key,
  835. IN PCTSTR Name
  836. )
  837. {
  838. TCHAR Data[MEMDB_MAX];
  839. if (MemDbGetEndpointValueEx (MEMDB_CATEGORY_STATE, Name, NULL, Data)) {
  840. RegSetValueEx (
  841. Key,
  842. Name,
  843. 0,
  844. REG_SZ,
  845. (PBYTE) Data,
  846. SizeOfString (Data)
  847. );
  848. }
  849. }
  850. VOID
  851. pSaveVersionDword (
  852. IN HKEY Key,
  853. IN PCTSTR Name
  854. )
  855. {
  856. DWORD Data;
  857. TCHAR Node[MEMDB_MAX];
  858. MemDbBuildKey (Node, MEMDB_CATEGORY_STATE, Name, NULL, NULL);
  859. if (MemDbGetValue (Node, &Data)) {
  860. RegSetValueEx (
  861. Key,
  862. Name,
  863. 0,
  864. REG_DWORD,
  865. (PBYTE) &Data,
  866. sizeof (Data)
  867. );
  868. }
  869. }
  870. BOOL
  871. pSetWin9xUpgValue (
  872. VOID
  873. )
  874. /*++
  875. Routine Description:
  876. Create the value entry Win9xUpg on
  877. HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\WinLogon
  878. This routine should always be called when setup is installing an NT system
  879. on top of Win9x, otherwise NT will think it has to migrate Win 3.1.
  880. Arguments:
  881. None.
  882. Return Value:
  883. Returns TRUE if the opearation succeeds.
  884. --*/
  885. {
  886. ULONG Error;
  887. HKEY Key;
  888. DWORD Value;
  889. HKEY VersionKey;
  890. Key = OpenRegKeyStr (S_WINLOGON_REGKEY);
  891. if (!Key) {
  892. return FALSE;
  893. }
  894. Value = 1;
  895. Error = RegSetValueEx (
  896. Key,
  897. S_WIN9XUPG_FLAG_VALNAME,
  898. 0,
  899. REG_DWORD,
  900. (PBYTE) &Value,
  901. sizeof (DWORD)
  902. );
  903. //
  904. // Save the version info
  905. //
  906. VersionKey = CreateRegKey (Key, TEXT("PrevOsVersion"));
  907. if (VersionKey) {
  908. pSaveVersionStr (VersionKey, MEMDB_ITEM_PLATFORM_NAME);
  909. pSaveVersionStr (VersionKey, MEMDB_ITEM_VERSION_TEXT);
  910. pSaveVersionDword (VersionKey, MEMDB_ITEM_MAJOR_VERSION);
  911. pSaveVersionDword (VersionKey, MEMDB_ITEM_MINOR_VERSION);
  912. pSaveVersionDword (VersionKey, MEMDB_ITEM_BUILD_NUMBER);
  913. pSaveVersionDword (VersionKey, MEMDB_ITEM_PLATFORM_ID);
  914. CloseRegKey (VersionKey);
  915. }
  916. CloseRegKey (Key);
  917. if (Error != ERROR_SUCCESS) {
  918. SetLastError (Error);
  919. return FALSE;
  920. }
  921. return TRUE;
  922. }
  923. PCTSTR
  924. GetString (
  925. WORD wMsg
  926. )
  927. /*++
  928. Routine Description:
  929. Load the string resource given in wMsg and copy it to a global string
  930. buffer. Return the a pointer to the buffer.
  931. Arguments:
  932. wMsg - The identifier of the message to load.
  933. Return Value:
  934. Returns a pointer to the loaded message, or NULL. The message must be
  935. smaller than 2048 characters.
  936. --*/
  937. {
  938. PCTSTR String;
  939. String = GetStringResource (wMsg);
  940. if (!String) {
  941. return TEXT("Error: String resource could not be loaded");
  942. }
  943. _tcssafecpy (g_MsgBuf, String, ARRAYSIZE(g_MsgBuf));
  944. FreeStringResource (String);
  945. return g_MsgBuf;
  946. }
  947. VOID
  948. pCountUsers (
  949. OUT PDWORD TotalUsersPtr,
  950. OUT PDWORD ActiveUsersPtr
  951. )
  952. /*++
  953. Routine Description:
  954. Counts all Win9x users, and determines how many of them are active
  955. for migration. The count includes the Administrator account, the
  956. logon prompt account, and optional default user account.
  957. NOTE: Administrator may be counted twice in ActiveUsersPtr, once for
  958. a real Win9x user named Administrator, and again for the
  959. NT Administrator account that is always migrated. The caller
  960. must handle this special case.
  961. Arguments:
  962. TotalUsersPtr - A DWORD that receives the total number of Win9x users,
  963. including the NT-only users.
  964. ActiveUsersPtr - A DWORD that receives the number of users that require
  965. migration. Migration may or may not be enabled for any
  966. user.
  967. Return Value:
  968. none
  969. --*/
  970. {
  971. USERPOSITION up;
  972. TCHAR User[MAX_TCHAR_PATH];
  973. DWORD rc;
  974. PCTSTR UserDatLocation;
  975. *ActiveUsersPtr = 0;
  976. *TotalUsersPtr = 3; // include logon, default and administrator in the total
  977. rc = Win95RegGetFirstUser (&up, User);
  978. if (rc != ERROR_SUCCESS) {
  979. *TotalUsersPtr = 0;
  980. return;
  981. }
  982. while (Win95RegHaveUser (&up)) {
  983. GetFixedUserName (User);
  984. // see if this user requires migration
  985. UserDatLocation = GetUserDatLocation (User, NULL);
  986. if (UserDatLocation) {
  987. *ActiveUsersPtr += 1;
  988. }
  989. // count all users, migrated and non-migrated
  990. *TotalUsersPtr += 1;
  991. Win95RegGetNextUser (&up, User);
  992. }
  993. // test migration requirement of default user and adminsistrator
  994. UserDatLocation = GetUserDatLocation (g_AdministratorStr, NULL);
  995. if (UserDatLocation) {
  996. *ActiveUsersPtr += 1;
  997. }
  998. UserDatLocation = GetUserDatLocation (S_DOT_DEFAULT, NULL);
  999. if (UserDatLocation) {
  1000. *ActiveUsersPtr += 1;
  1001. }
  1002. if (g_ConfigOptions.MigrateDefaultUser) {
  1003. *ActiveUsersPtr += 1;
  1004. }
  1005. DEBUGMSG ((DBG_VERBOSE, "pCountUsers: %u users, %u require migration", *TotalUsersPtr, *ActiveUsersPtr));
  1006. }
  1007. CONVERTPATH_RC
  1008. ConvertWin9xPath (
  1009. PTSTR PathBuf
  1010. )
  1011. {
  1012. TCHAR Buffer[MEMDB_MAX];
  1013. DWORD status;
  1014. status = GetFileInfoOnNt (PathBuf, Buffer, MEMDB_MAX);
  1015. if (status & FILESTATUS_REPLACED) {
  1016. if (status & FILESTATUS_MOVED) {
  1017. _tcssafecpy (PathBuf, Buffer, MAX_TCHAR_PATH);
  1018. return CONVERTPATH_REMAPPED;
  1019. }
  1020. return CONVERTPATH_NOT_REMAPPED;
  1021. }
  1022. if (status & FILESTATUS_MOVED) {
  1023. _tcssafecpy (PathBuf, Buffer, MAX_TCHAR_PATH);
  1024. return CONVERTPATH_REMAPPED;
  1025. }
  1026. if (status & FILESTATUS_DELETED) {
  1027. return CONVERTPATH_DELETED;
  1028. }
  1029. return CONVERTPATH_NOT_REMAPPED;
  1030. }
  1031. VOID
  1032. pRaiseRegistryQuota (
  1033. PCTSTR Win9xSystemDatSpec
  1034. )
  1035. {
  1036. NTSTATUS Status;
  1037. SYSTEM_REGISTRY_QUOTA_INFORMATION RegQuotaInfo;
  1038. HANDLE FileHandle;
  1039. DWORD QuotaNeeded;
  1040. ULARGE_INTEGER FreeBytes, dc1, dc2;
  1041. LONGLONG FreeBytesNeeded;
  1042. HKEY SaveKey;
  1043. DWORD rc;
  1044. #ifdef PAGED_POOL_INCREASE
  1045. SYSTEM_POOL_INFORMATION PoolInfo;
  1046. //
  1047. // Obtain current system settings
  1048. //
  1049. Status = NtQuerySystemInformation (
  1050. SystemPagedPoolInformation,
  1051. (PVOID) &PoolInfo,
  1052. sizeof(PoolInfo),
  1053. NULL
  1054. );
  1055. if (Status != ERROR_SUCCESS) {
  1056. LOG ((LOG_ERROR, "Cannot obtain PoolInfo"));
  1057. return;
  1058. }
  1059. #endif
  1060. pSetupEnablePrivilege (SE_INCREASE_QUOTA_NAME, TRUE);
  1061. Status = NtQuerySystemInformation (
  1062. SystemRegistryQuotaInformation,
  1063. (PVOID) &RegQuotaInfo,
  1064. sizeof(RegQuotaInfo),
  1065. NULL
  1066. );
  1067. if (Status != ERROR_SUCCESS) {
  1068. LOG ((LOG_ERROR, "Cannot obtain RegQuotaInfo"));
  1069. return;
  1070. }
  1071. //
  1072. // Obtain Win9x registry system.dat size
  1073. //
  1074. FileHandle = CreateFile (
  1075. Win9xSystemDatSpec,
  1076. GENERIC_READ,
  1077. FILE_SHARE_READ,
  1078. NULL, // security attributes
  1079. OPEN_EXISTING,
  1080. FILE_ATTRIBUTE_NORMAL,
  1081. NULL // template file
  1082. );
  1083. if (FileHandle == INVALID_HANDLE_VALUE) {
  1084. LOG ((LOG_ERROR, "Cannot open %s; cannot raise registry quota", Win9xSystemDatSpec));
  1085. return;
  1086. }
  1087. QuotaNeeded = GetFileSize (FileHandle, NULL);
  1088. CloseHandle (FileHandle);
  1089. if (QuotaNeeded > 0x3fffffff) {
  1090. LOG ((LOG_ERROR, "Cannot obtain size for %s; cannot raise registry quota", Win9xSystemDatSpec));
  1091. return;
  1092. }
  1093. QuotaNeeded *= 6;
  1094. //
  1095. // Get free disk space on boot drive
  1096. //
  1097. if (!GetDiskFreeSpaceEx (
  1098. g_WinDir,
  1099. &FreeBytes,
  1100. &dc1,
  1101. &dc2
  1102. )) {
  1103. LOG ((LOG_ERROR, "Can't get free space on drive holding %s; cannot raise registry quota", g_WinDir));
  1104. return;
  1105. }
  1106. //
  1107. // Lots of disk space? Raise paged pool by 5 times the size of system.dat.
  1108. // Example: Win9x system.dat is 5M; must have 150M free to raise paged pool.
  1109. //
  1110. FreeBytesNeeded = (LONGLONG) QuotaNeeded * (LONGLONG) 6;
  1111. if (FreeBytes.QuadPart >= (DWORDLONG) FreeBytesNeeded) {
  1112. //
  1113. // Unimplemented: Raise the paged pool and return
  1114. //
  1115. DEBUGMSG ((DBG_WARNING, "RegQuota: Really should be raising paged pool -- this machine has %u bytes free", FreeBytes.LowPart));
  1116. }
  1117. //
  1118. // Last resort: raise the registry quota (if necessary)
  1119. //
  1120. if (RegQuotaInfo.RegistryQuotaAllowed < QuotaNeeded) {
  1121. DEBUGMSG ((DBG_VERBOSE, "Raising registry quota from %u to %u", RegQuotaInfo.RegistryQuotaAllowed, QuotaNeeded));
  1122. RegQuotaInfo.RegistryQuotaAllowed = QuotaNeeded;
  1123. Status = NtSetSystemInformation (
  1124. SystemRegistryQuotaInformation,
  1125. &RegQuotaInfo,
  1126. sizeof (RegQuotaInfo)
  1127. );
  1128. if (Status != ERROR_SUCCESS) {
  1129. LOG ((LOG_ERROR, "Can't set raised registry quota"));
  1130. }
  1131. //
  1132. // Set a permanent value in the registry
  1133. //
  1134. SaveKey = OpenRegKeyStr (TEXT("HKLM\\System\\CurrentControlSet\\Control"));
  1135. if (SaveKey) {
  1136. rc = RegSetValueEx (
  1137. SaveKey,
  1138. TEXT("RegistrySizeLimit"),
  1139. 0,
  1140. REG_DWORD,
  1141. (PBYTE) &QuotaNeeded,
  1142. sizeof (DWORD)
  1143. );
  1144. CloseRegKey (SaveKey);
  1145. if (rc != ERROR_SUCCESS) {
  1146. LOG ((LOG_ERROR, "Could not set HKLM\\System\\CurrentControlSet\\Control [RegistrySizeLimit]"));
  1147. }
  1148. }
  1149. ELSE_DEBUGMSG ((DBG_ERROR, "Can't open HKLM\\System\\CurrentControlSet\\Control"));
  1150. }
  1151. }
  1152. BOOL
  1153. pCopyDosFile (
  1154. IN PCTSTR FileName,
  1155. IN BOOL InRootDir
  1156. )
  1157. /*++
  1158. Routine Description:
  1159. Copies a file from %windir%\setup\msdos7 into the designated DOS directory
  1160. Arguments:
  1161. FileName - file to copy (no path).
  1162. Return Value:
  1163. TRUE if succeeded, FALSE if not
  1164. --*/
  1165. {
  1166. PTSTR sourcePath;
  1167. PTSTR sourceFileName;
  1168. PTSTR destPath;
  1169. PTSTR destFileName;
  1170. BOOL result;
  1171. sourcePath = JoinPaths (g_TempDir, S_BOOT16_DOS_DIR);
  1172. sourceFileName = JoinPaths (sourcePath, FileName);
  1173. if (InRootDir) {
  1174. destPath = NULL;
  1175. destFileName = JoinPaths (ISPC98() ? g_Win9xBootDrivePath : g_BootDrivePath,
  1176. FileName);
  1177. }
  1178. else {
  1179. destPath = JoinPaths (ISPC98() ? g_Win9xBootDrivePath : g_BootDrivePath,
  1180. S_BOOT16_DOS_DIR);
  1181. destFileName = JoinPaths (destPath, FileName);
  1182. }
  1183. SetFileAttributes (destFileName, FILE_ATTRIBUTE_NORMAL);
  1184. result = CopyFile (sourceFileName, destFileName, FALSE);
  1185. FreePathString (sourcePath);
  1186. FreePathString (sourceFileName);
  1187. if (destPath != NULL) {
  1188. FreePathString (destPath);
  1189. }
  1190. FreePathString (destFileName);
  1191. return result;
  1192. }
  1193. VOID
  1194. pWriteBoot16ConfigLines (
  1195. IN HANDLE File,
  1196. IN PCTSTR BaseSection,
  1197. IN PCTSTR DosPath,
  1198. IN BOOL Localized
  1199. )
  1200. /*++
  1201. Routine Description:
  1202. pWriteBoot16ConfigLines reads configuration lines from wkstamig.inf and
  1203. writes them to the specified file handle. The caller can control wether the
  1204. lines should contain first boot only items or not and can control wether to
  1205. read in the base dos lines (same for all languages) or special lines used
  1206. for specific languages.
  1207. Arguments:
  1208. File - An opened handle with appropriate access to the file where
  1209. the data should be written.
  1210. BaseSection - Contains the Base Section name to read from the INF. This
  1211. section may be modified with a code page if Localized is TRUE.
  1212. DosPath - Contains the full path to the dos boot files (typically
  1213. c:\msdos7)
  1214. Localized - Controls wether data from the localized section is read. If
  1215. this parameter is TRUE, then the code page will be appended to
  1216. the BaseSection string for purposes of reading from wkstamig.inf.
  1217. Return Value:
  1218. none
  1219. ++*/
  1220. {
  1221. INFSTRUCT is = INITINFSTRUCT_GROWBUFFER;
  1222. GROWLIST list = GROWLIST_INIT;
  1223. PTSTR line;
  1224. TCHAR codePageSection[MAX_TCHAR_PATH];
  1225. USHORT codePage;
  1226. PCTSTR infSection;
  1227. //
  1228. // Add boot16 line specific environment variables.
  1229. //
  1230. GrowListAppendString (&list, TEXT("BOOTDRIVE"));
  1231. GrowListAppendString (&list, g_BootDrive);
  1232. GrowListAppendString (&list, TEXT("BOOT16DIR"));
  1233. GrowListAppendString (&list, DosPath);
  1234. //
  1235. // Terminate the arg list with two NULLs
  1236. //
  1237. GrowListAppendEmptyItem (&list);
  1238. GrowListAppendEmptyItem (&list);
  1239. if (Localized) {
  1240. //
  1241. // Caller wants data from the localized section.
  1242. //
  1243. GetGlobalCodePage (&codePage, NULL);
  1244. wsprintf (codePageSection, TEXT("%s %u"), BaseSection, codePage);
  1245. infSection = codePageSection;
  1246. }
  1247. else {
  1248. infSection = BaseSection;
  1249. }
  1250. //
  1251. // Write lines from base section.
  1252. //
  1253. if (InfFindFirstLine (g_WkstaMigInf, infSection, NULL, &is)) {
  1254. do {
  1255. //
  1256. // Get the line from the section and expand any environment
  1257. // variables.
  1258. //
  1259. line = InfGetLineText (&is);
  1260. MYASSERT (line);
  1261. line = ExpandEnvironmentTextEx (line,GrowListGetStringPtrArray (&list));
  1262. MYASSERT (line);
  1263. //
  1264. // Write the line to the file.
  1265. //
  1266. WriteFileString (File, line);
  1267. WriteFileString (File, TEXT("\r\n"));
  1268. FreeText (line);
  1269. } while (InfFindNextLine (&is));
  1270. }
  1271. FreeGrowList (&list);
  1272. InfCleanUpInfStruct (&is);
  1273. }
  1274. BOOL
  1275. pCreateConfigFile(
  1276. IN PCTSTR DosPath
  1277. )
  1278. /*++
  1279. Routine Description:
  1280. Creates a CONFIG.SYS file containing default settings.
  1281. Arguments:
  1282. DosPath - Contains the path to the dos files. (e.g. c:\msdos7)
  1283. Return Value:
  1284. TRUE if file was created, FALSE if not
  1285. --*/
  1286. {
  1287. PTSTR configName = NULL;
  1288. HANDLE handle;
  1289. configName = JoinPaths (ISPC98() ? g_Win9xBootDrivePath : g_BootDrivePath,
  1290. S_BOOT16_CONFIG_FILE);
  1291. SetFileAttributes (configName, FILE_ATTRIBUTE_NORMAL);
  1292. handle = CreateFile (
  1293. configName,
  1294. GENERIC_READ | GENERIC_WRITE,
  1295. 0,
  1296. NULL,
  1297. CREATE_ALWAYS,
  1298. FILE_ATTRIBUTE_ARCHIVE | FILE_ATTRIBUTE_NORMAL
  1299. ,
  1300. NULL
  1301. );
  1302. if (handle == INVALID_HANDLE_VALUE) {
  1303. return FALSE;
  1304. }
  1305. //
  1306. // Read lines from wkstamig.inf into this file.
  1307. //
  1308. pWriteBoot16ConfigLines (handle, S_BOOT16_CONFIGSYS_SECTION, DosPath, FALSE);
  1309. pWriteBoot16ConfigLines (handle, S_BOOT16_CONFIGSYS_SECTION, DosPath, TRUE);
  1310. CloseHandle (handle);
  1311. FreePathString (configName);
  1312. return TRUE;
  1313. }
  1314. BOOL
  1315. pCreateStartupFile(
  1316. IN PCTSTR DosPath
  1317. )
  1318. /*++
  1319. Routine Description:
  1320. Creates an AUTOEXEC.BAT file containing default settings.
  1321. Arguments:
  1322. DosPath - Contains the path to the dos files. (e.g. c:\msdos7)
  1323. Return Value:
  1324. TRUE if file was created, FALSE if not
  1325. --*/
  1326. {
  1327. PTSTR startupName = NULL;
  1328. PCTSTR comment = NULL;
  1329. HANDLE handle;
  1330. PCTSTR args[2];
  1331. args[0] = DosPath;
  1332. args[1] = NULL;
  1333. startupName = JoinPaths (ISPC98() ? g_Win9xBootDrivePath : g_BootDrivePath,
  1334. S_BOOT16_STARTUP_FILE);
  1335. SetFileAttributes (startupName, FILE_ATTRIBUTE_NORMAL);
  1336. handle = CreateFile (
  1337. startupName,
  1338. GENERIC_READ | GENERIC_WRITE,
  1339. 0,
  1340. NULL,
  1341. CREATE_ALWAYS,
  1342. FILE_ATTRIBUTE_ARCHIVE | FILE_ATTRIBUTE_HIDDEN,
  1343. NULL
  1344. );
  1345. if (handle == INVALID_HANDLE_VALUE) {
  1346. return FALSE;
  1347. }
  1348. comment = ParseMessageID (MSG_BOOT16_STARTUP_COMMENT, args);
  1349. //
  1350. // Read lines from wkstamig.inf into this file.
  1351. //
  1352. pWriteBoot16ConfigLines (handle, S_BOOT16_AUTOEXEC_SECTION, DosPath, FALSE);
  1353. pWriteBoot16ConfigLines (handle, S_BOOT16_AUTOEXEC_SECTION, DosPath, TRUE);
  1354. //
  1355. // Write localized comment.
  1356. //
  1357. WriteFileString (handle, comment);
  1358. WriteFileString (handle, TEXT("\r\n"));
  1359. FreeStringResource (comment);
  1360. CloseHandle (handle);
  1361. FreePathString (startupName);
  1362. return TRUE;
  1363. }
  1364. VOID
  1365. pEliminateCollision (
  1366. IN PCTSTR FileSpec
  1367. )
  1368. /*++
  1369. Routine Description:
  1370. pEliminateCollision checks to see if the specified file spec already
  1371. exists. If it does, the file is renamed with a numeric .nnn extension. If
  1372. the file can't be renamed, it is removed.
  1373. Arguments:
  1374. FileSpec - Specifies the file spec that is going to be used for a new file.
  1375. If this file already exists, it is renamed.
  1376. Return Value:
  1377. None.
  1378. --*/
  1379. {
  1380. PTSTR p;
  1381. PCTSTR NewFileSpec;
  1382. UINT u;
  1383. BOOL b;
  1384. if (DoesFileExist (FileSpec)) {
  1385. NewFileSpec = DuplicatePathString (FileSpec, 0);
  1386. p = _tcsrchr (NewFileSpec, TEXT('.'));
  1387. if (!p || _tcschr (p, TEXT('\\'))) {
  1388. p = GetEndOfString (NewFileSpec);
  1389. }
  1390. u = 0;
  1391. do {
  1392. wsprintf (p, TEXT(".%03u"), u);
  1393. u++;
  1394. } while (DoesFileExist (NewFileSpec));
  1395. b = OurMoveFile (FileSpec, NewFileSpec);
  1396. LOG_IF ((
  1397. !b,
  1398. LOG_ERROR,
  1399. "Could not rename %s to %s; source file might be lost",
  1400. FileSpec,
  1401. NewFileSpec
  1402. ));
  1403. if (!b) {
  1404. SetFileAttributes (FileSpec, FILE_ATTRIBUTE_NORMAL);
  1405. b = DeleteFile (FileSpec);
  1406. LOG_IF ((
  1407. !b,
  1408. LOG_ERROR,
  1409. "Could not remove %s to make room for a new file. The new file is lost.",
  1410. FileSpec
  1411. ));
  1412. }
  1413. FreePathString (NewFileSpec);
  1414. }
  1415. }
  1416. BOOL
  1417. pRenameCfgFiles (
  1418. IN PCTSTR DosDrive
  1419. )
  1420. /*++
  1421. Routine Description:
  1422. Renames old CONFIG.SYS and AUTOEXEC.BAT to make room for automatically generated ones.
  1423. Arguments:
  1424. DosDirectory - Contains the directory where the msdos files live (typeically c:\msdos7)
  1425. Return Value:
  1426. TRUE if rename succeeded, FALSE if not
  1427. --*/
  1428. {
  1429. PTSTR fileName1 = NULL;
  1430. PTSTR fileName2 = NULL;
  1431. fileName1 = JoinPaths (
  1432. ISPC98() ? g_Win9xBootDrivePath : g_BootDrivePath,
  1433. S_BOOT16_CONFIG_FILE
  1434. );
  1435. fileName2 = JoinPaths (
  1436. DosDrive,
  1437. S_BOOT16_CONFIGUPG_FILE
  1438. );
  1439. OurMoveFile (fileName1, fileName2);
  1440. SetFileAttributes (fileName2, FILE_ATTRIBUTE_NORMAL);
  1441. FreePathString (fileName1);
  1442. FreePathString (fileName2);
  1443. fileName1 = JoinPaths (
  1444. ISPC98() ? g_Win9xBootDrivePath : g_BootDrivePath,
  1445. S_BOOT16_STARTUP_FILE
  1446. );
  1447. fileName2 = JoinPaths (
  1448. DosDrive,
  1449. S_BOOT16_STARTUPUPG_FILE
  1450. );
  1451. OurMoveFile (fileName1, fileName2);
  1452. SetFileAttributes (fileName2, FILE_ATTRIBUTE_NORMAL);
  1453. FreePathString (fileName1);
  1454. FreePathString (fileName2);
  1455. return TRUE;
  1456. }
  1457. VOID
  1458. pCleanRootDir (
  1459. VOID
  1460. )
  1461. /*++
  1462. Routine Description:
  1463. Blows away dos files in root directory.
  1464. Arguments:
  1465. none
  1466. Return Value:
  1467. none
  1468. --*/
  1469. {
  1470. PTSTR fileName = NULL;
  1471. fileName = JoinPaths (ISPC98() ? g_Win9xBootDrivePath : g_BootDrivePath,
  1472. S_BOOT16_SYSMAIN_FILE);
  1473. MarkFileForDelete (fileName);
  1474. FreePathString (fileName);
  1475. fileName = JoinPaths (ISPC98() ? g_Win9xBootDrivePath : g_BootDrivePath,
  1476. S_BOOT16_DOSINI_FILE);
  1477. MarkFileForDelete (fileName);
  1478. FreePathString (fileName);
  1479. }
  1480. #define IoFile TEXT("IO.SYS")
  1481. VOID
  1482. pEnable16Boot (
  1483. VOID
  1484. )
  1485. /*++
  1486. Routine Description:
  1487. Creates a 16 bit environment boot option.
  1488. First we will check to see if everything is OK, we have all the files we need etc.
  1489. Then create DOS directory, rename old AUTOEXEC and CONFIG, create new ones and
  1490. add an entry in BOOT.INI
  1491. Arguments:
  1492. none
  1493. Return Value:
  1494. TRUE if file was created, FALSE if not
  1495. --*/
  1496. {
  1497. PTSTR fileName = NULL;
  1498. PTSTR dosPath = NULL;
  1499. INFCONTEXT infContext;
  1500. DWORD oldFileAttr;
  1501. BOOL result = TRUE;
  1502. HANDLE fileHandle = INVALID_HANDLE_VALUE;
  1503. if (g_Boot16 == BOOT16_NO) {
  1504. pCleanRootDir ();
  1505. return;
  1506. }
  1507. __try {
  1508. //
  1509. // first thing. Copy IO.SYS in root directory (BOOTSECT.DOS should be there)
  1510. //
  1511. pCopyDosFile (IoFile, TRUE);
  1512. fileName = JoinPaths (ISPC98() ? g_Win9xBootDrivePath : g_BootDrivePath,
  1513. IoFile);
  1514. SetFileAttributes (fileName, FILE_ATTRIBUTE_HIDDEN | FILE_ATTRIBUTE_READONLY | FILE_ATTRIBUTE_SYSTEM);
  1515. FreePathString (fileName);
  1516. //
  1517. // Create DOS7 directory and copy dos files there
  1518. //
  1519. dosPath = JoinPaths (ISPC98() ? g_Win9xBootDrivePath : g_BootDrivePath,
  1520. S_BOOT16_DOS_DIR);
  1521. if (!CreateDirectory (dosPath, NULL) && (GetLastError()!=ERROR_ALREADY_EXISTS)) {
  1522. LOG ((LOG_ERROR,"BOOT16 : Unable to create DOS directory %s",dosPath));
  1523. __leave;
  1524. }
  1525. //
  1526. // If we find autoexec.bat and config.sys rename them as *.upg
  1527. //
  1528. if (!pRenameCfgFiles (dosPath)) {
  1529. __leave;
  1530. }
  1531. if (g_WkstaMigInf == INVALID_HANDLE_VALUE) {
  1532. LOG ((LOG_ERROR,"BOOT16 : WKSTAMIG.INF is not opened"));
  1533. __leave;
  1534. }
  1535. //
  1536. // Read the section, for every file, we are trying to read it from our temp dir
  1537. // and copy it to the new DOS7 location
  1538. //
  1539. fileName = AllocPathString (MAX_TCHAR_PATH);
  1540. if (!SetupFindFirstLine (
  1541. g_WkstaMigInf,
  1542. S_BOOT16_SECTION,
  1543. NULL,
  1544. &infContext
  1545. )) {
  1546. LOG ((LOG_ERROR,"BOOT16 : Cannot read from %s section (WKSTAMIG.INF)",S_BOOT16_SECTION));
  1547. __leave;
  1548. }
  1549. do {
  1550. if (SetupGetStringField (
  1551. &infContext,
  1552. 0,
  1553. fileName,
  1554. MAX_TCHAR_PATH/sizeof(fileName[0]),
  1555. NULL
  1556. )) {
  1557. pCopyDosFile (fileName, FALSE);
  1558. }
  1559. }
  1560. while (SetupFindNextLine (&infContext, &infContext));
  1561. //
  1562. // Hide the msdos7 directory (not our idea...)
  1563. //
  1564. SetFileAttributes (dosPath, FILE_ATTRIBUTE_HIDDEN | FILE_ATTRIBUTE_SYSTEM);
  1565. FreePathString (fileName);
  1566. fileName = NULL;
  1567. //
  1568. // Next step, build MSDOS.SYS file.
  1569. //
  1570. fileName = JoinPaths (ISPC98() ? g_Win9xBootDrivePath : g_BootDrivePath,
  1571. S_BOOT16_DOSINI_FILE);
  1572. if (SetFileAttributes (fileName, FILE_ATTRIBUTE_NORMAL)) {
  1573. if (!DeleteFile (fileName)) {
  1574. LOG ((LOG_ERROR, "BOOT16 : Unable to delete %s",fileName));
  1575. __leave;
  1576. }
  1577. }
  1578. result &= WritePrivateProfileString (TEXT("Paths"), TEXT("WinDir"), dosPath, fileName);
  1579. result &= WritePrivateProfileString (TEXT("Paths"), TEXT("WinBootDir"), dosPath, fileName);
  1580. result &= WritePrivateProfileString (TEXT("Options"), TEXT("LOGO"), TEXT("0"), fileName);
  1581. result &= WritePrivateProfileString (TEXT("Options"), TEXT("BootGUI"), TEXT("0"), fileName);
  1582. if (!result) {
  1583. LOG((LOG_ERROR,"Unable to write to %s",fileName));
  1584. __leave;
  1585. }
  1586. FreePathString (fileName);
  1587. fileName = NULL;
  1588. //
  1589. // Generate config.sys and autoexec.bat files.
  1590. //
  1591. if (!pCreateConfigFile (dosPath)) {
  1592. LOG ((LOG_ERROR, "BOOT16 : Unable to create %s",S_BOOT16_CONFIG_FILE));
  1593. __leave;
  1594. }
  1595. if (!pCreateStartupFile (dosPath)) {
  1596. LOG ((LOG_ERROR, "BOOT16 : Unable to create %s",S_BOOT16_STARTUP_FILE));
  1597. __leave;
  1598. }
  1599. if ((!ISPC98()) || (g_BootDrivePath[0] == g_Win9xBootDrivePath[0])) {
  1600. //
  1601. // If boot16 is set to BOOT16_AUTOMATIC, we create a boot.dos file,
  1602. // but don't actually modify boot.ini. If it is BOOT16_YES, then
  1603. // we modify boot.ini
  1604. //
  1605. // The result is that DOS will not show up as a boot option unless
  1606. // there was a specific reason it was turned on originally. However,
  1607. // there will be a way to enable it if needed.
  1608. //
  1609. if (g_Boot16 == BOOT16_AUTOMATIC) {
  1610. fileName = JoinPaths (g_BootDrivePath, S_BOOT16_BOOTDOS_FILE);
  1611. fileHandle = CreateFile (
  1612. fileName,
  1613. GENERIC_READ | GENERIC_WRITE,
  1614. 0,
  1615. NULL,
  1616. CREATE_ALWAYS,
  1617. FILE_ATTRIBUTE_HIDDEN | FILE_ATTRIBUTE_ARCHIVE,
  1618. NULL
  1619. );
  1620. if (fileHandle != INVALID_HANDLE_VALUE) {
  1621. WriteFileString (fileHandle, ISPC98() ? L"C:\\" : g_BootDrivePath);
  1622. WriteFileString (fileHandle, TEXT("="));
  1623. WriteFileString (fileHandle, S_BOOT16_OS_ENTRY);
  1624. }
  1625. }
  1626. else {
  1627. fileName = JoinPaths (g_BootDrivePath, S_BOOT16_BOOTINI_FILE);
  1628. oldFileAttr = GetFileAttributes (fileName);
  1629. SetFileAttributes (fileName, FILE_ATTRIBUTE_NORMAL);
  1630. if (!WritePrivateProfileString (
  1631. S_BOOT16_OS_SECTION,
  1632. ISPC98() ? L"C:\\" : g_BootDrivePath,
  1633. S_BOOT16_OS_ENTRY,
  1634. fileName
  1635. )) {
  1636. LOG((LOG_ERROR,"Unable to write to %s",fileName));
  1637. SetFileAttributes (fileName, oldFileAttr);
  1638. __leave;
  1639. }
  1640. SetFileAttributes (fileName, oldFileAttr);
  1641. }
  1642. }
  1643. }
  1644. __finally {
  1645. if (fileName != NULL) {
  1646. FreePathString (fileName);
  1647. fileName = NULL;
  1648. }
  1649. if (dosPath != NULL) {
  1650. FreePathString (dosPath);
  1651. dosPath = NULL;
  1652. }
  1653. }
  1654. }
  1655. VOID
  1656. pCopyRegString (
  1657. IN HKEY DestKey,
  1658. IN HKEY SrcKey,
  1659. IN PCTSTR SrcValue
  1660. )
  1661. {
  1662. PCTSTR Data;
  1663. Data = GetRegValueString (SrcKey, SrcValue);
  1664. if (Data) {
  1665. RegSetValueEx (DestKey, SrcValue, 0, REG_SZ, (PBYTE) Data, SizeOfString (Data));
  1666. MemFree (g_hHeap, 0, Data);
  1667. }
  1668. }
  1669. #ifdef PRERELEASE
  1670. //
  1671. // !!! This is for internal use only !!! It is used for auto stress.
  1672. //
  1673. VOID
  1674. pTransferAutoStressVal (
  1675. IN HKEY StressKey,
  1676. IN PCTSTR ValueName
  1677. )
  1678. {
  1679. TCHAR Data[MEMDB_MAX];
  1680. LONG rc;
  1681. if (!MemDbGetEndpointValueEx (
  1682. MEMDB_CATEGORY_STATE,
  1683. ValueName,
  1684. NULL, // no field
  1685. Data
  1686. )) {
  1687. return;
  1688. }
  1689. rc = RegSetValueEx (
  1690. StressKey,
  1691. ValueName,
  1692. 0,
  1693. REG_SZ,
  1694. (PBYTE) Data,
  1695. SizeOfString (Data)
  1696. );
  1697. DEBUGMSG_IF ((rc == ERROR_SUCCESS, DBG_VERBOSE, "Transferred autostress value %s", ValueName));
  1698. }
  1699. #endif
  1700. VOID
  1701. pProcessAutoLogon (
  1702. BOOL Final
  1703. )
  1704. /*++
  1705. Routine Description:
  1706. pProcessAutoLogon copies the logon defaults to a special key, so the
  1707. migpwd.exe tool can restore them if it runs. Then, the function calls
  1708. AutoStartProcessing to set up RunOnce and AutoAdminLogon.
  1709. This function is called early in migration to save the clean install
  1710. autologon, and then again at the end to prepare migpwd.exe.
  1711. Arguments:
  1712. Final - Specifies FALSE if this is the early call, TRUE if it is the
  1713. final call.
  1714. Return Value:
  1715. None.
  1716. --*/
  1717. {
  1718. HKEY SrcKey, DestKey;
  1719. PCTSTR Data;
  1720. BOOL copyNow = FALSE;
  1721. static BOOL alreadyCopied = FALSE;
  1722. //
  1723. // If autologon is enabled, preserve it in Win9xUpg key, so that
  1724. // migpwd.exe will restore it.
  1725. //
  1726. SrcKey = OpenRegKeyStr (S_WINLOGON_REGKEY);
  1727. if (SrcKey) {
  1728. if (!Final) {
  1729. //
  1730. // Early in migration, we get the clean install autologon values.
  1731. // If autologon is enabled, preserve the settings.
  1732. //
  1733. Data = GetRegValueString (SrcKey, S_AUTOADMIN_LOGON_VALUE);
  1734. if (Data) {
  1735. if (_ttoi (Data)) {
  1736. //
  1737. // on PER, don't want to preserve this value;
  1738. // instead, we need to preserve the name of
  1739. // the Win9x username as migrated via wkstamig.inf (see below)
  1740. //
  1741. copyNow = !g_PersonalSKU;
  1742. }
  1743. MemFree (g_hHeap, 0, Data);
  1744. }
  1745. } else if (!alreadyCopied) {
  1746. //
  1747. // Near the end of migration, we get the default logon prompt
  1748. // settings via wkstamig.inf migration. We want the attended case
  1749. // to work properly (preserving default user name & password).
  1750. //
  1751. // But if we've already preserved autologon, then we don't get
  1752. // here.
  1753. //
  1754. copyNow = TRUE;
  1755. }
  1756. if (copyNow) {
  1757. MYASSERT (!alreadyCopied);
  1758. alreadyCopied = TRUE;
  1759. DestKey = CreateRegKeyStr (S_WIN9XUPG_KEY);
  1760. if (DestKey) {
  1761. pCopyRegString (DestKey, SrcKey, S_AUTOADMIN_LOGON_VALUE);
  1762. pCopyRegString (DestKey, SrcKey, S_DEFAULT_PASSWORD_VALUE);
  1763. pCopyRegString (DestKey, SrcKey, S_DEFAULT_USER_NAME_VALUE);
  1764. pCopyRegString (DestKey, SrcKey, S_DEFAULT_DOMAIN_NAME_VALUE);
  1765. CloseRegKey (DestKey);
  1766. }
  1767. }
  1768. CloseRegKey (SrcKey);
  1769. }
  1770. if (!Final) {
  1771. return;
  1772. }
  1773. AutoStartProcessing();
  1774. #ifdef PRERELEASE
  1775. //
  1776. // !!! This is for internal use only !!! It is used for auto stress.
  1777. //
  1778. if (g_ConfigOptions.AutoStress) {
  1779. HKEY StressKey;
  1780. StressKey = CreateRegKeyStr (S_AUTOSTRESS_KEY);
  1781. MYASSERT (StressKey);
  1782. pTransferAutoStressVal (StressKey, S_AUTOSTRESS_USER);
  1783. pTransferAutoStressVal (StressKey, S_AUTOSTRESS_PASSWORD);
  1784. pTransferAutoStressVal (StressKey, S_AUTOSTRESS_OFFICE);
  1785. pTransferAutoStressVal (StressKey, S_AUTOSTRESS_DBG);
  1786. pTransferAutoStressVal (StressKey, S_AUTOSTRESS_FLAGS);
  1787. CloseRegKey (StressKey);
  1788. }
  1789. #endif
  1790. }
  1791. PCTSTR
  1792. GetProfilePathForAllUsers (
  1793. VOID
  1794. )
  1795. {
  1796. PTSTR result = NULL;
  1797. DWORD size = 0;
  1798. if (!GetAllUsersProfileDirectory (NULL, &size) &&
  1799. ERROR_INSUFFICIENT_BUFFER != GetLastError()) {
  1800. return NULL;
  1801. }
  1802. result = AllocPathString (size + 1);
  1803. if (!GetAllUsersProfileDirectory (result, &size)) {
  1804. FreePathString (result);
  1805. return NULL;
  1806. }
  1807. return result;
  1808. }
  1809. PCTSTR
  1810. pGetDefaultShellFolderLocationFromInf (
  1811. IN PCTSTR FolderName,
  1812. IN PCTSTR ProfilePath
  1813. )
  1814. {
  1815. INFSTRUCT is = INITINFSTRUCT_GROWBUFFER;
  1816. PCTSTR data;
  1817. PCTSTR result = NULL;
  1818. MYASSERT (g_WkstaMigInf && g_WkstaMigInf != INVALID_HANDLE_VALUE);
  1819. if (InfFindFirstLine (g_WkstaMigInf, TEXT("ShellFolders.DefaultNtLocation"), FolderName, &is)) {
  1820. data = InfGetStringField (&is, 1);
  1821. if (data) {
  1822. result = StringSearchAndReplace (data, S_USERPROFILE_ENV, ProfilePath);
  1823. if (!result) {
  1824. result = DuplicatePathString (data, 0);
  1825. }
  1826. }
  1827. }
  1828. InfCleanUpInfStruct (&is);
  1829. return result;
  1830. }
  1831. VOID
  1832. pFixUpDynamicPaths (
  1833. PCTSTR Category
  1834. )
  1835. {
  1836. MEMDB_ENUM e;
  1837. TCHAR Pattern[MEMDB_MAX];
  1838. PTSTR p;
  1839. GROWBUFFER Roots = GROWBUF_INIT;
  1840. MULTISZ_ENUM e2;
  1841. TCHAR NewRoot[MEMDB_MAX];
  1842. TCHAR AllProfilePath[MAX_TCHAR_PATH];
  1843. PCTSTR ProfilePath;
  1844. DWORD Size;
  1845. PTSTR UserName;
  1846. HKEY sfKey = NULL;
  1847. PCTSTR sfPath = NULL;
  1848. PTSTR NtLocation;
  1849. PCTSTR tempExpand;
  1850. BOOL regFolder;
  1851. BOOL mkDir;
  1852. //
  1853. // Collect all the roots that need to be renamed
  1854. //
  1855. StringCopy (Pattern, Category);
  1856. p = AppendWack (Pattern);
  1857. StringCopy (p, TEXT("*"));
  1858. if (MemDbEnumFirstValue (&e, Pattern, MEMDB_THIS_LEVEL_ONLY, MEMDB_ALL_BUT_PROXY)) {
  1859. do {
  1860. if ((_tcsnextc (e.szName) == TEXT('>')) ||
  1861. (_tcsnextc (e.szName) == TEXT('<'))
  1862. ) {
  1863. StringCopy (p, e.szName);
  1864. MultiSzAppend (&Roots, Pattern);
  1865. }
  1866. } while (MemDbEnumNextValue (&e));
  1867. }
  1868. //
  1869. // Now change each root
  1870. //
  1871. if (EnumFirstMultiSz (&e2, (PCTSTR) Roots.Buf)) {
  1872. do {
  1873. //
  1874. // Compute NewRoot
  1875. //
  1876. StringCopy (NewRoot, e2.CurrentString);
  1877. p = _tcschr (NewRoot, TEXT('<'));
  1878. if (p) {
  1879. UserName = _tcschr (p, TEXT('>'));
  1880. MYASSERT (UserName);
  1881. StringCopyAB (Pattern, _tcsinc (p), UserName);
  1882. UserName = _tcsinc (UserName);
  1883. regFolder = TRUE;
  1884. if (StringIMatch (Pattern, TEXT("Profiles"))) {
  1885. regFolder = FALSE;
  1886. }
  1887. if (StringIMatch (Pattern, TEXT("Common Profiles"))) {
  1888. regFolder = FALSE;
  1889. }
  1890. //
  1891. // Get the profile root
  1892. //
  1893. if (StringIMatch (UserName, S_DOT_ALLUSERS)) {
  1894. Size = MAX_TCHAR_PATH;
  1895. if (regFolder) {
  1896. if (!GetAllUsersProfileDirectory (AllProfilePath, &Size)) {
  1897. DEBUGMSG ((DBG_WHOOPS, "Cannot get All Users profile path."));
  1898. continue;
  1899. }
  1900. sfKey = OpenRegKeyStr (S_USHELL_FOLDERS_KEY_SYSTEM);
  1901. } else {
  1902. if (!GetProfilesDirectory (AllProfilePath, &Size)) {
  1903. DEBUGMSG ((DBG_WHOOPS, "Cannot get All Users profile path."));
  1904. continue;
  1905. }
  1906. }
  1907. } else if (StringMatch (UserName, S_DEFAULT_USER)) {
  1908. Size = MAX_TCHAR_PATH;
  1909. if (regFolder) {
  1910. if (!GetDefaultUserProfileDirectory (AllProfilePath, &Size)) {
  1911. DEBUGMSG ((DBG_WHOOPS, "Cannot get Default User profile path."));
  1912. continue;
  1913. }
  1914. sfKey = OpenRegKey (HKEY_CURRENT_USER, S_USHELL_FOLDERS_KEY_USER);
  1915. } else {
  1916. if (!GetProfilesDirectory (AllProfilePath, &Size)) {
  1917. DEBUGMSG ((DBG_WHOOPS, "Cannot get All Users profile path."));
  1918. continue;
  1919. }
  1920. }
  1921. } else {
  1922. ProfilePath = GetProfilePathForUser (UserName);
  1923. if (!ProfilePath) {
  1924. DEBUGMSG ((DBG_WHOOPS, "Cannot get profile path for user:%s", UserName));
  1925. continue;
  1926. }
  1927. StringCopy (AllProfilePath, ProfilePath);
  1928. if (regFolder) {
  1929. sfKey = OpenRegKey (HKEY_CURRENT_USER, S_USHELL_FOLDERS_KEY_USER);
  1930. }
  1931. }
  1932. //
  1933. // If a specific reg folder is specified, get its path
  1934. //
  1935. mkDir = FALSE;
  1936. if (regFolder) {
  1937. if (!sfKey) {
  1938. DEBUGMSG ((DBG_ERROR, "Could not open Shell folders key."));
  1939. continue;
  1940. }
  1941. sfPath = GetRegValueString (sfKey, Pattern);
  1942. CloseRegKey (sfKey);
  1943. if (!sfPath || *sfPath == 0) {
  1944. DEBUGMSG ((DBG_WARNING, "Could not get Shell Folder path for: %s", Pattern));
  1945. tempExpand = pGetDefaultShellFolderLocationFromInf (Pattern, AllProfilePath);
  1946. if (!tempExpand) {
  1947. DEBUGMSG ((
  1948. DBG_WHOOPS,
  1949. "Shell folder %s is not in registry nor is it in [ShellFolders.DefaultNtLocation] of wkstamig.inf",
  1950. Pattern
  1951. ));
  1952. continue;
  1953. }
  1954. //
  1955. // Special case: Shell wants read-only on this folder. Create it now.
  1956. //
  1957. mkDir = TRUE;
  1958. } else {
  1959. tempExpand = StringSearchAndReplace (
  1960. sfPath,
  1961. S_USERPROFILE_ENV,
  1962. AllProfilePath
  1963. );
  1964. if (!tempExpand) {
  1965. tempExpand = DuplicatePathString (sfPath, 0);
  1966. }
  1967. }
  1968. if (sfPath) {
  1969. MemFree (g_hHeap, 0, sfPath);
  1970. }
  1971. } else {
  1972. tempExpand = DuplicatePathString (AllProfilePath, 0);
  1973. }
  1974. //
  1975. // Move symbolic name to full path
  1976. //
  1977. NtLocation = ExpandEnvironmentText (tempExpand);
  1978. if (mkDir) {
  1979. MakeSurePathExists (NtLocation, TRUE);
  1980. SetFileAttributes (NtLocation, FILE_ATTRIBUTE_READONLY);
  1981. }
  1982. StringCopy (p, NtLocation);
  1983. MemDbMoveTree (e2.CurrentString, NewRoot);
  1984. FreeText (NtLocation);
  1985. FreePathString (tempExpand);
  1986. } else {
  1987. p = _tcschr (NewRoot, TEXT('>'));
  1988. MYASSERT (p);
  1989. if (StringIMatch (_tcsinc (p), S_DOT_ALLUSERS)) {
  1990. Size = MAX_TCHAR_PATH;
  1991. if (!GetAllUsersProfileDirectory (AllProfilePath, &Size)) {
  1992. DEBUGMSG ((DBG_WARNING, "Dynamic path for %s could not be resolved", e2.CurrentString));
  1993. }
  1994. else {
  1995. StringCopy (p, AllProfilePath);
  1996. MemDbMoveTree (e2.CurrentString, NewRoot);
  1997. }
  1998. } else if (StringMatch (_tcsinc (p), S_DEFAULT_USER)) {
  1999. Size = MAX_TCHAR_PATH;
  2000. if (!GetDefaultUserProfileDirectory (AllProfilePath, &Size)) {
  2001. DEBUGMSG ((DBG_WARNING, "Dynamic path for %s could not be resolved", e2.CurrentString));
  2002. }
  2003. else {
  2004. StringCopy (p, AllProfilePath);
  2005. MemDbMoveTree (e2.CurrentString, NewRoot);
  2006. }
  2007. } else {
  2008. ProfilePath = GetProfilePathForUser (_tcsinc (p));
  2009. if (ProfilePath) {
  2010. StringCopy (p, ProfilePath);
  2011. MemDbMoveTree (e2.CurrentString, NewRoot);
  2012. }
  2013. else {
  2014. DEBUGMSG ((DBG_WARNING, "Dynamic path for %s could not be resolved", e2.CurrentString));
  2015. }
  2016. }
  2017. }
  2018. } while (EnumNextMultiSz (&e2));
  2019. }
  2020. FreeGrowBuffer (&Roots);
  2021. }
  2022. VOID
  2023. pFixUpMemDb (
  2024. VOID
  2025. )
  2026. {
  2027. MEMDB_ENUM e;
  2028. TCHAR node[MEMDB_MAX];
  2029. pFixUpDynamicPaths (MEMDB_CATEGORY_PATHROOT);
  2030. //pFixUpDynamicPaths (MEMDB_CATEGORY_DATA); OPTIMIZATION -- Data overlaps PathRoot
  2031. pFixUpDynamicPaths (MEMDB_CATEGORY_USERFILEMOVE_DEST);
  2032. pFixUpDynamicPaths (MEMDB_CATEGORY_SHELLFOLDERS_DEST);
  2033. pFixUpDynamicPaths (MEMDB_CATEGORY_SHELLFOLDERS_SRC);
  2034. pFixUpDynamicPaths (MEMDB_CATEGORY_LINKEDIT_TARGET);
  2035. pFixUpDynamicPaths (MEMDB_CATEGORY_LINKEDIT_WORKDIR);
  2036. pFixUpDynamicPaths (MEMDB_CATEGORY_LINKEDIT_ICONPATH);
  2037. pFixUpDynamicPaths (MEMDB_CATEGORY_LINKSTUB_TARGET);
  2038. pFixUpDynamicPaths (MEMDB_CATEGORY_LINKSTUB_WORKDIR);
  2039. pFixUpDynamicPaths (MEMDB_CATEGORY_LINKSTUB_ICONPATH);
  2040. //
  2041. // Enumerate each user in MyDocsMoveWarning, then update dynamic paths
  2042. //
  2043. // MyDocsMoveWarning\<user>\<path>
  2044. MemDbBuildKey (
  2045. node,
  2046. MEMDB_CATEGORY_MYDOCS_WARNING,
  2047. TEXT("*"),
  2048. NULL,
  2049. NULL
  2050. );
  2051. if (MemDbEnumFirstValue (&e, node, MEMDB_THIS_LEVEL_ONLY, MEMDB_ALL_MATCHES)) {
  2052. do {
  2053. MemDbBuildKey (
  2054. node,
  2055. MEMDB_CATEGORY_MYDOCS_WARNING,
  2056. e.szName, // <user>
  2057. NULL,
  2058. NULL
  2059. );
  2060. pFixUpDynamicPaths (node);
  2061. } while (MemDbEnumNextValue (&e));
  2062. }
  2063. }
  2064. BOOL
  2065. EnumFirstUserToMigrate (
  2066. OUT PMIGRATE_USER_ENUM e,
  2067. IN DWORD Flags
  2068. )
  2069. {
  2070. ZeroMemory (e, sizeof (MIGRATE_USER_ENUM));
  2071. e->Flags = Flags;
  2072. pCountUsers (&e->TotalUsers, &e->ActiveUsers);
  2073. e->UserNumber = e->TotalUsers;
  2074. Win95RegGetFirstUser (&e->up, e->Win95RegName);
  2075. return EnumNextUserToMigrate (e);
  2076. }
  2077. BOOL
  2078. EnumNextUserToMigrate (
  2079. IN OUT PMIGRATE_USER_ENUM e
  2080. )
  2081. {
  2082. LONG rc;
  2083. PCTSTR Domain;
  2084. TCHAR Win9xAccount[MEMDB_MAX];
  2085. TCHAR EnumAccount[MAX_TCHAR_PATH];
  2086. USERPOSITION *AdminPosPtr;
  2087. USERPOSITION AdminPos;
  2088. BOOL Loop = TRUE;
  2089. PCTSTR UserDatLocation;
  2090. while (Loop) {
  2091. if (e->UserNumber == 0) {
  2092. return FALSE;
  2093. }
  2094. Loop = FALSE;
  2095. e->UserNumber--;
  2096. __try {
  2097. e->UserDoingTheUpgrade = FALSE;
  2098. if (e->UserNumber == INDEX_ADMINISTRATOR) {
  2099. _tcssafecpy (e->FixedUserName, g_AdministratorStr, MAX_USER_NAME);
  2100. StringCopy (e->Win9xUserName, e->FixedUserName);
  2101. e->AccountType = ADMINISTRATOR_ACCOUNT;
  2102. } else if (e->UserNumber == INDEX_LOGON_PROMPT) {
  2103. StringCopy (e->FixedUserName, S_DOT_DEFAULT);
  2104. StringCopy (e->Win9xUserName, e->FixedUserName);
  2105. e->AccountType = LOGON_USER_SETTINGS;
  2106. } else if (e->UserNumber == INDEX_DEFAULT_USER) {
  2107. //
  2108. // Do not process unless default user migration is enabled
  2109. //
  2110. if (!g_ConfigOptions.MigrateDefaultUser) {
  2111. Loop = (e->Flags & ENUM_ALL_USERS) == 0;
  2112. __leave;
  2113. }
  2114. StringCopy (e->FixedUserName, S_DEFAULT_USER);
  2115. StringCopy (e->Win9xUserName, e->FixedUserName);
  2116. e->AccountType = DEFAULT_USER_ACCOUNT;
  2117. } else {
  2118. _tcssafecpy (e->Win9xUserName, e->Win95RegName, MAX_USER_NAME);
  2119. StringCopy (e->FixedUserName, e->Win95RegName);
  2120. GetFixedUserName (e->FixedUserName);
  2121. e->AccountType = WIN9X_USER_ACCOUNT;
  2122. //
  2123. // Special case: Account named Administrator exists. In this
  2124. // case, we'd have two Administrator users unless
  2125. // one was skipped. So here is the test to skip
  2126. // if the user is named Administrator.
  2127. //
  2128. if (StringIMatch (e->Win9xUserName, g_AdministratorStr)) {
  2129. Loop = TRUE;
  2130. __leave;
  2131. }
  2132. }
  2133. StringCopy (e->FixedDomainName, e->FixedUserName);
  2134. //
  2135. // See if we are to migrate this user, and if so, perpare
  2136. // the Win95 registry and call ProcessUser.
  2137. //
  2138. UserDatLocation = GetUserDatLocation (e->FixedUserName, &e->CreateOnly);
  2139. if (UserDatLocation && DoesFileExist (UserDatLocation)) {
  2140. e->Valid = TRUE;
  2141. StringCopy (e->UserDatLocation, UserDatLocation);
  2142. } else {
  2143. e->Valid = FALSE;
  2144. e->UserDatLocation[0] = 0;
  2145. }
  2146. if (e->Flags & ENUM_SET_WIN9X_HKR) {
  2147. //
  2148. // Make HKCU equal to the enumerated user
  2149. //
  2150. g_hKeyRoot95 = HKEY_CURRENT_USER;
  2151. }
  2152. if (e->Valid) {
  2153. //
  2154. // Is this user the user doing migration?
  2155. //
  2156. if (MemDbGetEndpointValueEx (
  2157. MEMDB_CATEGORY_ADMINISTRATOR_INFO,
  2158. MEMDB_ITEM_AI_USER_DOING_MIG,
  2159. NULL, // no field
  2160. Win9xAccount
  2161. )) {
  2162. //
  2163. // Win9xAccount is unfixed name, convert to fixed name then
  2164. // compare with the current enumerated user.
  2165. //
  2166. GetFixedUserName (Win9xAccount);
  2167. DEBUGMSG ((DBG_NAUSEA, "Comparing %s to %s", e->FixedUserName, Win9xAccount));
  2168. if (StringIMatch (e->FixedUserName, Win9xAccount)) {
  2169. e->UserDoingTheUpgrade = TRUE;
  2170. }
  2171. }
  2172. //
  2173. // Perform special init depending on the user type
  2174. //
  2175. if (e->AccountType == WIN9X_USER_ACCOUNT) {
  2176. if (e->Flags & ENUM_SET_WIN9X_HKR) {
  2177. //
  2178. // Map HKCU on Win95 to current user
  2179. //
  2180. rc = Win95RegSetCurrentUserNt (&e->up, e->UserDatLocation);
  2181. if (rc != ERROR_SUCCESS) {
  2182. SetLastError (rc);
  2183. LOG ((
  2184. LOG_ERROR,
  2185. "Migrate Users: Win95RegSetCurrentUserNt could not set user "
  2186. "to %s (user path %s)",
  2187. e->FixedUserName,
  2188. e->UserDatLocation
  2189. ));
  2190. LOG ((LOG_ERROR, "Could not load %s", e->UserDatLocation));
  2191. Loop = (e->Flags & ENUM_ALL_USERS) == 0;
  2192. __leave;
  2193. }
  2194. }
  2195. // Obtain the full user name
  2196. Domain = GetDomainForUser (e->FixedUserName);
  2197. if (Domain) {
  2198. StringCopy (e->FixedDomainName, Domain);
  2199. StringCopy (AppendWack (e->FixedDomainName), e->FixedUserName);
  2200. }
  2201. }
  2202. else if (e->AccountType == ADMINISTRATOR_ACCOUNT) {
  2203. //
  2204. // Map Win9x registry appropriate for the Administrator hive
  2205. //
  2206. if (e->Flags & ENUM_SET_WIN9X_HKR) {
  2207. AdminPosPtr = NULL;
  2208. // Obtain user account from memdb and find USERPOSITION for it
  2209. if (MemDbGetEndpointValueEx (
  2210. MEMDB_CATEGORY_ADMINISTRATOR_INFO,
  2211. MEMDB_ITEM_AI_ACCOUNT,
  2212. NULL, // no field
  2213. Win9xAccount
  2214. )) {
  2215. // Search Win9x user list for user
  2216. Win95RegGetFirstUser (&AdminPos, EnumAccount);
  2217. while (Win95RegHaveUser (&AdminPos)) {
  2218. GetFixedUserName (EnumAccount);
  2219. if (StringIMatch (Win9xAccount, EnumAccount)) {
  2220. AdminPosPtr = &AdminPos;
  2221. break;
  2222. }
  2223. Win95RegGetNextUser (&AdminPos, EnumAccount);
  2224. }
  2225. if (!AdminPosPtr) {
  2226. DEBUGMSG ((
  2227. DBG_WARNING,
  2228. "pMigrateUsers: Account %s not found",
  2229. Win9xAccount
  2230. ));
  2231. }
  2232. }
  2233. //
  2234. // Map HKCU on Win95 to match, or default user if no match or
  2235. // no memdb entry
  2236. //
  2237. rc = Win95RegSetCurrentUserNt (AdminPosPtr, e->UserDatLocation);
  2238. if (rc != ERROR_SUCCESS) {
  2239. SetLastError (rc);
  2240. LOG ((LOG_ERROR, "Could not load %s for Administrator", e->UserDatLocation));
  2241. Loop = (e->Flags & ENUM_ALL_USERS) == 0;
  2242. __leave;
  2243. }
  2244. }
  2245. }
  2246. else if (e->AccountType == LOGON_USER_SETTINGS || e->AccountType == DEFAULT_USER_ACCOUNT) {
  2247. //
  2248. // Map HKCU on Win95 to default user
  2249. //
  2250. if (e->Flags & ENUM_SET_WIN9X_HKR) {
  2251. rc = Win95RegSetCurrentUserNt (NULL, e->UserDatLocation);
  2252. if (rc != ERROR_SUCCESS) {
  2253. SetLastError (rc);
  2254. LOG ((LOG_ERROR, "Could not load default user hive"));
  2255. Loop = (e->Flags & ENUM_ALL_USERS) == 0;
  2256. __leave;
  2257. }
  2258. }
  2259. }
  2260. } /* if (e->Valid) */
  2261. else {
  2262. Loop = (e->Flags & ENUM_ALL_USERS) == 0;
  2263. }
  2264. } /* try */
  2265. __finally {
  2266. //
  2267. // Get the next user for next time through loop, ignore errors
  2268. //
  2269. if (e->AccountType == WIN9X_USER_ACCOUNT) {
  2270. Win95RegGetNextUser (&e->up, e->Win95RegName);
  2271. }
  2272. }
  2273. } /* while (Loop) */
  2274. DEBUGMSG_IF ((
  2275. e->Flags & ENUM_SET_WIN9X_HKR,
  2276. DBG_VERBOSE,
  2277. "--- User Info ---\n"
  2278. " User Name: %s (%s)\n"
  2279. " Domain User Name: %s\n"
  2280. " Win95Reg Name: %s\n"
  2281. " User Hive: %s\n"
  2282. " Account Type: %s\n"
  2283. " Create Only: %s\n"
  2284. " Valid: %s\n"
  2285. " UserDoingTheUpgrade: %s\n",
  2286. e->Win9xUserName,
  2287. e->FixedUserName,
  2288. e->FixedDomainName,
  2289. e->Win95RegName,
  2290. e->UserDatLocation,
  2291. e->AccountType == WIN9X_USER_ACCOUNT ? TEXT("User") :
  2292. e->AccountType == ADMINISTRATOR_ACCOUNT ? TEXT("Administrator") :
  2293. e->AccountType == LOGON_USER_SETTINGS ? TEXT("Logon User") :
  2294. e->AccountType == DEFAULT_USER_ACCOUNT ? TEXT("Default User") : TEXT("Unknown"),
  2295. e->CreateOnly ? TEXT("Yes") : TEXT("No"),
  2296. e->Valid ? TEXT("Yes") : TEXT("No"),
  2297. e->UserDoingTheUpgrade ? TEXT("Yes") : TEXT("No")
  2298. ));
  2299. return TRUE;
  2300. }
  2301. VOID
  2302. RunExternalProcesses (
  2303. IN HINF Inf,
  2304. IN PMIGRATE_USER_ENUM EnumPtr OPTIONAL
  2305. )
  2306. {
  2307. INFSTRUCT is = INITINFSTRUCT_GROWBUFFER;
  2308. GROWLIST List = GROWLIST_INIT;
  2309. PCTSTR RawCmdLine;
  2310. PCTSTR ExpandedCmdLine;
  2311. BOOL ProcessResult;
  2312. STARTUPINFO si;
  2313. PROCESS_INFORMATION pi;
  2314. DWORD rc;
  2315. GrowListAppendString (&List, TEXT("SYSTEMDIR"));
  2316. GrowListAppendString (&List, g_System32Dir);
  2317. if (EnumPtr) {
  2318. GrowListAppendString (&List, TEXT("USERNAME"));
  2319. GrowListAppendString (&List, EnumPtr->FixedUserName);
  2320. GrowListAppendString (&List, TEXT("USERNAMEWITHDOMAIN"));
  2321. GrowListAppendString (&List, EnumPtr->FixedDomainName);
  2322. GrowListAppendString (&List, TEXT("PREVOS_USERNAME"));
  2323. GrowListAppendString (&List, EnumPtr->Win9xUserName);
  2324. if (EnumPtr->AccountType != LOGON_USER_SETTINGS) {
  2325. GrowListAppendString (&List, TEXT("USERHIVEROOT"));
  2326. GrowListAppendString (&List, S_FULL_TEMP_USER_KEY);
  2327. } else {
  2328. GrowListAppendString (&List, TEXT("USERHIVEROOT"));
  2329. GrowListAppendString (&List, S_DEFAULT_USER_KEY);
  2330. }
  2331. if (EnumPtr->ExtraData) {
  2332. GrowListAppendString (&List, TEXT("USERPROFILE"));
  2333. GrowListAppendString (&List, EnumPtr->ExtraData->TempProfile);
  2334. }
  2335. }
  2336. //
  2337. // Terminate the arg list with two NULLs
  2338. //
  2339. GrowListAppendEmptyItem (&List);
  2340. GrowListAppendEmptyItem (&List);
  2341. if (InfFindFirstLine (Inf, S_EXTERNAL_PROCESSES, NULL, (&is))) {
  2342. do {
  2343. //
  2344. // Get the command line
  2345. //
  2346. RawCmdLine = InfGetLineText (&is);
  2347. //
  2348. // Expand environment variables
  2349. //
  2350. ExpandedCmdLine = ExpandEnvironmentTextEx (
  2351. RawCmdLine,
  2352. GrowListGetStringPtrArray (&List)
  2353. );
  2354. //
  2355. // Launch the process
  2356. //
  2357. ZeroMemory (&si, sizeof (si));
  2358. si.cb = sizeof (si);
  2359. si.dwFlags = STARTF_FORCEOFFFEEDBACK;
  2360. ProcessResult = CreateProcess (
  2361. NULL,
  2362. (PTSTR) ExpandedCmdLine,
  2363. NULL,
  2364. NULL,
  2365. FALSE,
  2366. CREATE_DEFAULT_ERROR_MODE,
  2367. NULL,
  2368. NULL,
  2369. &si,
  2370. &pi
  2371. );
  2372. if (ProcessResult) {
  2373. CloseHandle (pi.hThread);
  2374. //
  2375. // Wait 60 seconds for the process to complete
  2376. //
  2377. rc = WaitForSingleObject (pi.hProcess, 60000);
  2378. if (rc != WAIT_OBJECT_0) {
  2379. TerminateProcess (pi.hProcess, 0);
  2380. DEBUGMSG ((DBG_ERROR, "Process %s timed out and was aborted", ExpandedCmdLine));
  2381. }
  2382. ELSE_DEBUGMSG ((DBG_VERBOSE, "External process completed: %s", ExpandedCmdLine));
  2383. CloseHandle (pi.hProcess);
  2384. }
  2385. ELSE_DEBUGMSG ((DBG_ERROR, "Cannot launch %s", ExpandedCmdLine));
  2386. FreeText (ExpandedCmdLine);
  2387. } while (InfFindNextLine (&is));
  2388. }
  2389. FreeGrowList (&List);
  2390. InfCleanUpInfStruct (&is);
  2391. }
  2392. DWORD
  2393. MigrateGhostSystemFiles (
  2394. IN DWORD Request
  2395. )
  2396. {
  2397. /*
  2398. TREE_ENUM e;
  2399. PCTSTR systemName;
  2400. DWORD status;
  2401. */
  2402. if (Request == REQUEST_QUERYTICKS) {
  2403. return TICKS_GHOST_SYSTEM_MIGRATION;
  2404. } else if (Request != REQUEST_RUN) {
  2405. return ERROR_SUCCESS;
  2406. }
  2407. /*
  2408. if (EnumFirstFileInTreeEx (&e, g_System32Dir, NULL, FALSE, FALSE, FILE_ENUM_THIS_LEVEL)) {
  2409. do {
  2410. systemName = JoinPaths (g_SystemDir, e.Name);
  2411. status = GetFileStatusOnNt (systemName);
  2412. if ((status & FILESTATUS_NTINSTALLED) &&
  2413. !(status & FILESTATUS_MOVED)
  2414. ) {
  2415. if (!DoesFileExist (systemName)) {
  2416. MarkFileForMove (systemName, e.FullPath);
  2417. }
  2418. }
  2419. FreePathString (systemName);
  2420. } while (EnumNextFileInTree (&e));
  2421. }
  2422. */
  2423. return ERROR_SUCCESS;
  2424. }
  2425. typedef struct _KNOWN_DIRS {
  2426. PCTSTR DirId;
  2427. PCTSTR Translation;
  2428. }
  2429. KNOWN_DIRS, *PKNOWN_DIRS;
  2430. KNOWN_DIRS g_KnownDirs [] = {
  2431. {TEXT("10"), g_WinDir},
  2432. {NULL, NULL}
  2433. };
  2434. typedef struct {
  2435. PCTSTR ShellFolderName;
  2436. PCTSTR DirId;
  2437. PCTSTR ShellFolderNameDefault;
  2438. BOOL bUsed;
  2439. } SHELL_TO_DIRS, *PSHELL_TO_DIRS;
  2440. SHELL_TO_DIRS g_ShellToDirs[] = {
  2441. {TEXT("Administrative Tools"), TEXT("7501"), TEXT("7517\\Administrative Tools")},
  2442. {TEXT("Common Administrative Tools"), TEXT("7501"), TEXT("7517\\Administrative Tools")},
  2443. {TEXT("AppData"), TEXT("7502"), TEXT("Application Data")},
  2444. {TEXT("Common AppData"), TEXT("7502"), TEXT("Application Data")},
  2445. {TEXT("Cache"), TEXT("7503"), NULL},
  2446. {TEXT("Cookies"), TEXT("7504"), NULL},
  2447. {TEXT("Desktop"), TEXT("7505"), NULL},
  2448. {TEXT("Common Desktop"), TEXT("7505"), TEXT("Desktop")},
  2449. {TEXT("Favorites"), TEXT("7506"), NULL},
  2450. {TEXT("Common Favorites"), TEXT("7506"), TEXT("Favorites")},
  2451. {TEXT("Local Settings"), TEXT("7510"), NULL},
  2452. {TEXT("History"), TEXT("7508"), TEXT("7510\\History")},
  2453. {TEXT("Local AppData"), TEXT("7509"), TEXT("7510\\Application Data")},
  2454. {TEXT("Personal"), TEXT("7515"), TEXT("My Documents")},
  2455. {TEXT("Common Documents"), TEXT("7515"), TEXT("My Documents")},
  2456. {TEXT("My Music"), TEXT("7511"), TEXT("7515\\My Music")},
  2457. {TEXT("CommonMusic"), TEXT("7511"), TEXT("7515\\My Music")},
  2458. {TEXT("My Pictures"), TEXT("7512"), TEXT("7515\\My Pictures")},
  2459. {TEXT("CommonPictures"), TEXT("7512"), TEXT("7515\\My Pictures")},
  2460. {TEXT("My Video"), TEXT("7513"), TEXT("7515\\My Video")},
  2461. {TEXT("CommonVideo"), TEXT("7513"), TEXT("7515\\My Video")},
  2462. {TEXT("NetHood"), TEXT("7514"), NULL},
  2463. {TEXT("PrintHood"), TEXT("7516"), NULL},
  2464. {TEXT("Start Menu"), TEXT("7520"), NULL},
  2465. {TEXT("Common Start Menu"), TEXT("7520"), TEXT("Start Menu")},
  2466. {TEXT("Programs"), TEXT("7517"), TEXT("7520\\Programs")},
  2467. {TEXT("Common Programs"), TEXT("7517"), TEXT("7520\\Programs")},
  2468. {TEXT("Recent"), TEXT("7518"), NULL},
  2469. {TEXT("SendTo"), TEXT("7519"), NULL},
  2470. {TEXT("Startup"), TEXT("7521"), TEXT("7517\\Startup")},
  2471. {TEXT("Common Startup"), TEXT("7521"), TEXT("7517\\Startup")},
  2472. {TEXT("Templates"), TEXT("7522"), NULL},
  2473. {TEXT("Common Templates"), TEXT("7522"), TEXT("Templates")},
  2474. {TEXT("Fonts"), TEXT("7507"), TEXT("10\\Fonts")},
  2475. {NULL, NULL, NULL, FALSE}
  2476. };
  2477. GROWLIST g_KnownDirIds = GROWLIST_INIT;
  2478. GROWLIST g_KnownDirPaths = GROWLIST_INIT;
  2479. VOID
  2480. pAddKnownShellFolder (
  2481. IN PCTSTR ShellFolderName,
  2482. IN PCTSTR SrcPath
  2483. )
  2484. {
  2485. PSHELL_TO_DIRS p;
  2486. for (p = g_ShellToDirs ; p->ShellFolderName ; p++) {
  2487. if (StringIMatch (ShellFolderName, p->ShellFolderName)) {
  2488. break;
  2489. }
  2490. }
  2491. if (!p->ShellFolderName) {
  2492. DEBUGMSG ((DBG_ERROR, "This system has an unsupported shell folder tag: %s", ShellFolderName));
  2493. return;
  2494. }
  2495. p->bUsed = TRUE;
  2496. GrowListAppendString (&g_KnownDirIds, p->DirId);
  2497. GrowListAppendString (&g_KnownDirPaths, SrcPath);
  2498. }
  2499. typedef struct {
  2500. PCTSTR sfName;
  2501. PCTSTR sfPath;
  2502. HKEY SfKey;
  2503. REGVALUE_ENUM SfKeyEnum;
  2504. BOOL UserSf;
  2505. } SF_ENUM, *PSF_ENUM;
  2506. BOOL
  2507. EnumFirstRegShellFolder (
  2508. IN OUT PSF_ENUM e,
  2509. IN BOOL UserSf
  2510. );
  2511. BOOL
  2512. EnumNextRegShellFolder (
  2513. IN OUT PSF_ENUM e
  2514. );
  2515. BOOL
  2516. pConvertDirName (
  2517. PCTSTR OldDirName,
  2518. PTSTR NewDirName,
  2519. PINT NameNumber
  2520. );
  2521. VOID
  2522. pInitKnownDirs (
  2523. IN BOOL bUser
  2524. )
  2525. {
  2526. SF_ENUM e;
  2527. PCTSTR profileForAllUsers;
  2528. PCTSTR profileForAllUsersVar = TEXT("%ALLUSERSPROFILE%");
  2529. PCTSTR sfPathPtr;
  2530. TCHAR shellPartialPath[MAX_PATH];
  2531. UINT charCount;
  2532. UINT charCountProfileVar;
  2533. UINT charCountProfile;
  2534. PSHELL_TO_DIRS p;
  2535. KNOWN_DIRS * pKnownDirs;
  2536. INT nameNumber;
  2537. for (p = g_ShellToDirs ; p->ShellFolderName; p++){
  2538. p->bUsed = FALSE;
  2539. }
  2540. if(bUser){
  2541. if (EnumFirstRegShellFolder(&e, TRUE)) {
  2542. do {
  2543. pAddKnownShellFolder(e.sfName, e.sfPath);
  2544. DEBUGMSG((DBG_VERBOSE, "USER: ShellFolderPath=%s\nCutedFolderPath=%s", e.sfPath, e.sfPath));
  2545. } while (EnumNextRegShellFolder(&e));
  2546. }
  2547. }
  2548. else{
  2549. profileForAllUsers = GetProfilePathForAllUsers();
  2550. MYASSERT(profileForAllUsers);
  2551. if(profileForAllUsers){
  2552. charCountProfile = TcharCount(profileForAllUsers);
  2553. }
  2554. charCountProfileVar = TcharCount(profileForAllUsersVar);
  2555. if (EnumFirstRegShellFolder(&e, FALSE)) {
  2556. do {
  2557. if(profileForAllUsers){
  2558. charCount = 0;
  2559. if(StringIMatchCharCount(e.sfPath, profileForAllUsers, charCountProfile)){
  2560. charCount = charCountProfile;
  2561. }
  2562. else{
  2563. if(StringIMatchCharCount(e.sfPath, profileForAllUsersVar, charCountProfileVar)){
  2564. charCount = charCountProfileVar;
  2565. }
  2566. }
  2567. StringCopy(shellPartialPath, TEXT("%USERPROFILE%"));
  2568. StringCat(shellPartialPath, &e.sfPath[charCount]);
  2569. sfPathPtr = shellPartialPath;
  2570. }
  2571. else{
  2572. sfPathPtr = e.sfPath;
  2573. }
  2574. DEBUGMSG((DBG_VERBOSE, "SYSTEM: ShellFolderPath=%s\r\nCutedFolderPath=%s", e.sfPath, shellPartialPath));
  2575. pAddKnownShellFolder(e.sfName, sfPathPtr);
  2576. } while (EnumNextRegShellFolder(&e));
  2577. }
  2578. FreePathString (profileForAllUsers);
  2579. }
  2580. for (pKnownDirs = g_KnownDirs ; pKnownDirs->DirId ; pKnownDirs++) {
  2581. GrowListAppendString (&g_KnownDirIds, pKnownDirs->DirId);
  2582. GrowListAppendString (&g_KnownDirPaths, pKnownDirs->Translation);
  2583. }
  2584. for (p = g_ShellToDirs ; p->ShellFolderName; p++){
  2585. if(p->bUsed){
  2586. continue;
  2587. }
  2588. shellPartialPath[0] = '\0';
  2589. nameNumber = 0;
  2590. pConvertDirName(p->DirId, shellPartialPath, &nameNumber);
  2591. if(!StringMatch (p->DirId, shellPartialPath)){
  2592. p->bUsed = TRUE;
  2593. continue;
  2594. }
  2595. if(p->ShellFolderNameDefault){
  2596. if(_istdigit(p->ShellFolderNameDefault[0])){
  2597. nameNumber = 0;
  2598. pConvertDirName(
  2599. p->ShellFolderNameDefault,
  2600. shellPartialPath,
  2601. &nameNumber);
  2602. }
  2603. else{
  2604. StringCopy(shellPartialPath, TEXT("%USERPROFILE%\\"));
  2605. StringCat(shellPartialPath, p->ShellFolderNameDefault);
  2606. }
  2607. }
  2608. else{
  2609. StringCopy(shellPartialPath, TEXT("%USERPROFILE%\\"));
  2610. StringCat(shellPartialPath, p->ShellFolderName);
  2611. }
  2612. pAddKnownShellFolder(p->ShellFolderName, shellPartialPath);
  2613. DEBUGMSG((DBG_VERBOSE, "REST: ShellFolderPath=%s\nCutedFolderPath=%s", p->ShellFolderName, shellPartialPath));
  2614. }
  2615. }
  2616. VOID
  2617. pCleanUpKnownDirs (
  2618. VOID
  2619. )
  2620. {
  2621. FreeGrowList (&g_KnownDirPaths);
  2622. FreeGrowList (&g_KnownDirIds);
  2623. }
  2624. BOOL
  2625. pConvertDirName (
  2626. PCTSTR OldDirName,
  2627. PTSTR NewDirName,
  2628. PINT NameNumber
  2629. )
  2630. {
  2631. PCTSTR OldDirCurr = OldDirName;
  2632. PCTSTR OldDirNext;
  2633. BOOL match = FALSE;
  2634. INT index;
  2635. PCTSTR listStr;
  2636. if (*NameNumber == -1) {
  2637. return FALSE;
  2638. }
  2639. //
  2640. // Extract the dir id, keeping a pointer to the subdir
  2641. //
  2642. NewDirName[0] = 0;
  2643. OldDirNext = _tcschr (OldDirCurr, '\\');
  2644. if (OldDirNext == NULL) {
  2645. OldDirNext = GetEndOfString (OldDirCurr);
  2646. }
  2647. StringCopyAB (NewDirName, OldDirCurr, OldDirNext);
  2648. //
  2649. // Find the next match in the known dir ID list
  2650. //
  2651. listStr = GrowListGetString (&g_KnownDirIds, *NameNumber);
  2652. while (listStr) {
  2653. *NameNumber += 1;
  2654. if (StringMatch (NewDirName, listStr)) {
  2655. listStr = GrowListGetString (&g_KnownDirPaths, (*NameNumber) - 1);
  2656. MYASSERT (listStr);
  2657. StringCopy (NewDirName, listStr);
  2658. break;
  2659. }
  2660. listStr = GrowListGetString (&g_KnownDirIds, *NameNumber);
  2661. }
  2662. //
  2663. // Cat the subpath to the output string and return
  2664. //
  2665. StringCat (NewDirName, OldDirNext);
  2666. if (!listStr) {
  2667. *NameNumber = -1;
  2668. return FALSE;
  2669. }
  2670. return TRUE;
  2671. }
  2672. VOID
  2673. pUninstallUserProfileCleanupPreparation (
  2674. IN HINF Inf,
  2675. IN PTSTR UserNamePtr,
  2676. IN PCTSTR PathProfileRootPtr,
  2677. IN PCTSTR DocsAndSettingsRoot,
  2678. IN GROWLIST * ListOfLogicalPathsPtr,
  2679. IN OUT GROWLIST * ListOfPaths
  2680. )
  2681. {
  2682. INFSTRUCT is = INITINFSTRUCT_GROWBUFFER;
  2683. GROWLIST List = GROWLIST_INIT;
  2684. PTSTR rawDir;
  2685. TCHAR rawPath[MAX_PATH];
  2686. PTSTR ExpandedPath;
  2687. PTSTR fileName;
  2688. TCHAR shellPath[MAX_PATH];
  2689. INT nameNumber;
  2690. INT i;
  2691. INT listSize;
  2692. PCTSTR pathLogicalPath;
  2693. GrowListAppendString (&List, TEXT("USERPROFILE"));
  2694. GrowListAppendString (&List, PathProfileRootPtr);
  2695. GrowListAppendString (&List, TEXT("PROFILES"));
  2696. GrowListAppendString (&List, DocsAndSettingsRoot);
  2697. GrowListAppendString (&List, TEXT("USERNAME"));
  2698. GrowListAppendString (&List, UserNamePtr);
  2699. GrowListAppendEmptyItem (&List);
  2700. GrowListAppendEmptyItem (&List);
  2701. DEBUGMSG ((DBG_VERBOSE, "USERPROFILE.pathProfileRoot=%s\n", PathProfileRootPtr));
  2702. if (InfFindFirstLine (Inf, S_UNINSTALL_PROFILE_CLEAN_OUT, NULL, (&is))) {
  2703. do{
  2704. rawDir = InfGetStringField (&is, 1);
  2705. if(!rawDir || *rawDir == 0){
  2706. DEBUGMSG ((DBG_VERBOSE, "rawDir == NULL"));
  2707. continue;
  2708. }
  2709. StringCopy (rawPath, rawDir);
  2710. fileName = InfGetStringField (&is, 2);
  2711. if (fileName && *fileName) {
  2712. StringCopy (AppendWack(rawPath), fileName);
  2713. }
  2714. nameNumber = 0;
  2715. pConvertDirName(rawPath, shellPath, &nameNumber);
  2716. ExpandedPath = ExpandEnvironmentTextEx (
  2717. shellPath,
  2718. GrowListGetStringPtrArray (&List)
  2719. );
  2720. DEBUGMSG ((DBG_VERBOSE, "rawPath=%s\nExpandedPath=%s\nShellPath=%s", rawPath, ExpandedPath, shellPath));
  2721. GrowListAppendString (ListOfPaths, ExpandedPath);
  2722. FreeText (ExpandedPath);
  2723. } while (InfFindNextLine (&is));
  2724. }
  2725. if(ListOfLogicalPathsPtr){
  2726. for(i = 0, listSize = GrowListGetSize (ListOfLogicalPathsPtr); i < listSize; i++) {
  2727. pathLogicalPath = GrowListGetString(ListOfLogicalPathsPtr, i);
  2728. if(!pathLogicalPath){
  2729. continue;
  2730. }
  2731. nameNumber = 0;
  2732. pConvertDirName(pathLogicalPath, shellPath, &nameNumber);
  2733. ExpandedPath = ExpandEnvironmentTextEx (
  2734. shellPath,
  2735. GrowListGetStringPtrArray (&List)
  2736. );
  2737. GrowListAppendString (ListOfPaths, ExpandedPath);
  2738. FreeText (ExpandedPath);
  2739. }
  2740. }
  2741. FreeGrowList (&List);
  2742. InfCleanUpInfStruct (&is);
  2743. DEBUGMSG ((DBG_VERBOSE, "UninstallUserProfileCleanupPreparation end"));
  2744. }
  2745. BOOL
  2746. pGetProfilePathForAllUsers(
  2747. OUT PTSTR AccountName,
  2748. OUT PTSTR PathProfile
  2749. )
  2750. {
  2751. PCTSTR pathProfileForAllUser;
  2752. MYASSERT(AccountName && PathProfile);
  2753. if(!AccountName || !PathProfile){
  2754. MYASSERT(FALSE);
  2755. return FALSE;
  2756. }
  2757. pathProfileForAllUser = GetProfilePathForAllUsers();
  2758. if(!pathProfileForAllUser) {
  2759. return FALSE;
  2760. }
  2761. StringCopy (AccountName, S_ALL_USERS);
  2762. StringCopy (PathProfile, pathProfileForAllUser);
  2763. return TRUE;
  2764. }
  2765. BOOL
  2766. pGetProfilePathForDefaultUser(
  2767. OUT PTSTR AccountName,
  2768. OUT PTSTR PathProfile
  2769. )
  2770. {
  2771. DWORD bufferSize;
  2772. MYASSERT(AccountName && PathProfile);
  2773. if(!AccountName || !PathProfile){
  2774. MYASSERT(FALSE);
  2775. return FALSE;
  2776. }
  2777. bufferSize = MAX_PATH;
  2778. if(!GetDefaultUserProfileDirectory(PathProfile, &bufferSize) ||
  2779. !PathProfile[0]) {
  2780. return FALSE;
  2781. }
  2782. StringCopy (AccountName, S_DEFAULT_USER);
  2783. return TRUE;
  2784. }
  2785. BOOL
  2786. pGetProfilePathForUser(
  2787. IN PCTSTR UserName,
  2788. OUT PTSTR AccountName,
  2789. OUT PTSTR PathProfile
  2790. )
  2791. {
  2792. DWORD bufferSize;
  2793. MYASSERT(UserName && UserName[0] && AccountName && PathProfile);
  2794. if(!UserName || !UserName[0] || !AccountName || !PathProfile){
  2795. MYASSERT(FALSE);
  2796. return FALSE;
  2797. }
  2798. bufferSize = MAX_PATH;
  2799. if(!GetProfilesDirectory(PathProfile, &bufferSize) ||
  2800. !PathProfile[0]) {
  2801. MYASSERT(FALSE);
  2802. return FALSE;
  2803. }
  2804. StringCat(AppendWack(PathProfile), UserName);
  2805. StringCopy (AccountName, UserName);
  2806. return TRUE;
  2807. }
  2808. BOOL
  2809. pGetProfilePathForLocalService(
  2810. OUT PTSTR AccountName,
  2811. OUT PTSTR PathProfile
  2812. )
  2813. {
  2814. return pGetProfilePathForUser(S_LOCALSERVICE_USER, AccountName, PathProfile);
  2815. }
  2816. BOOL
  2817. pGetProfilePathForNetworkService(
  2818. OUT PTSTR AccountName,
  2819. OUT PTSTR PathProfile
  2820. )
  2821. {
  2822. return pGetProfilePathForUser(S_NETWORKSERVICE_USER, AccountName, PathProfile);
  2823. }
  2824. BOOL
  2825. pGetProfilePathForMachineName(
  2826. OUT PTSTR AccountName,
  2827. OUT PTSTR PathProfile
  2828. )
  2829. {
  2830. TCHAR machineName[MAX_COMPUTERNAME_LENGTH + 2];
  2831. PTSTR machineNamePtr = ExpandEnvironmentTextEx (TEXT("%COMPUTERNAME%"), NULL);
  2832. BOOL bResult;
  2833. if(!machineNamePtr || machineNamePtr[0] == '%'){
  2834. MYASSERT(FALSE);
  2835. DEBUGMSG((DBG_VERBOSE, "ComputerName is NULL"));
  2836. return FALSE;
  2837. }
  2838. DEBUGMSG ((DBG_VERBOSE, "machineName=%s", machineNamePtr? machineNamePtr: TEXT("NULL")));
  2839. StringCopy(machineName, machineNamePtr);
  2840. StringCat(machineName, TEXT("$"));
  2841. return pGetProfilePathForUser(machineName, AccountName, PathProfile);
  2842. }
  2843. VOID
  2844. UninstallUserProfileCleanupPreparation (
  2845. IN HINF Inf,
  2846. IN PMIGRATE_USER_ENUM EnumPtr,
  2847. IN BOOL Playback
  2848. )
  2849. {
  2850. static GROWLIST listOfPaths = GROWLIST_INIT;
  2851. static PROFILE_PATH_PROVIDER profilePathProviders[] =
  2852. {
  2853. pGetProfilePathForAllUsers,
  2854. pGetProfilePathForDefaultUser,
  2855. pGetProfilePathForLocalService,
  2856. pGetProfilePathForNetworkService,
  2857. pGetProfilePathForMachineName
  2858. };
  2859. TCHAR accountName[MAX_PATH];
  2860. TCHAR pathProfile[MAX_PATH];
  2861. TCHAR docsAndSettingsRoot[MAX_PATH];
  2862. PCTSTR pathProfileRootPtr;
  2863. UINT i;
  2864. UINT listSize;
  2865. DWORD bufferSize;
  2866. INT stringLen;
  2867. INT cleanOutType;
  2868. TCHAR pathDir[MAX_PATH];
  2869. bufferSize = ARRAYSIZE (docsAndSettingsRoot);
  2870. if (!GetProfilesDirectory (docsAndSettingsRoot, &bufferSize)) {
  2871. DEBUGMSG ((DBG_ERROR, "Can't get Documents and Settings root"));
  2872. *docsAndSettingsRoot = 0;
  2873. }
  2874. if (EnumPtr) {
  2875. pathProfileRootPtr = GetProfilePathForUser(EnumPtr->FixedUserName);
  2876. if(pathProfileRootPtr) {
  2877. pInitKnownDirs(TRUE);
  2878. pUninstallUserProfileCleanupPreparation(
  2879. Inf,
  2880. EnumPtr->FixedUserName,
  2881. pathProfileRootPtr,
  2882. docsAndSettingsRoot,
  2883. &g_StartMenuItemsForCleanUpPrivate,
  2884. &listOfPaths
  2885. );
  2886. pCleanUpKnownDirs();
  2887. }
  2888. } else {
  2889. pInitKnownDirs(FALSE);
  2890. for(i = 0; i < ARRAYSIZE(profilePathProviders); i++){
  2891. if(profilePathProviders[i](accountName, pathProfile)){
  2892. pUninstallUserProfileCleanupPreparation(
  2893. Inf,
  2894. accountName,
  2895. pathProfile,
  2896. docsAndSettingsRoot,
  2897. &g_StartMenuItemsForCleanUpCommon,
  2898. &listOfPaths
  2899. );
  2900. }
  2901. }
  2902. pCleanUpKnownDirs();
  2903. }
  2904. if (Playback) {
  2905. for(i = 0, listSize = GrowListGetSize (&listOfPaths); i < listSize; i++) {
  2906. pathProfileRootPtr = GrowListGetString(&listOfPaths, i);
  2907. if (pathProfileRootPtr){
  2908. stringLen = TcharCount(pathProfileRootPtr);
  2909. if(stringLen > 2 && '*' == pathProfileRootPtr[stringLen - 1]){
  2910. MYASSERT('\\' == pathProfileRootPtr[stringLen - 2] || '/' == pathProfileRootPtr[stringLen - 2]);
  2911. StringCopyTcharCount(pathDir, pathProfileRootPtr, stringLen - 1);
  2912. pathProfileRootPtr = pathDir;
  2913. cleanOutType = BACKUP_AND_CLEAN_TREE;
  2914. }
  2915. else{
  2916. cleanOutType = BACKUP_FILE;
  2917. }
  2918. if (!MemDbSetValueEx (
  2919. MEMDB_CATEGORY_CLEAN_OUT,
  2920. pathProfileRootPtr,
  2921. NULL,
  2922. NULL,
  2923. cleanOutType,
  2924. NULL
  2925. )){
  2926. DEBUGMSG ((DBG_VERBOSE, "MemDbSetValueEx - failed"));
  2927. }
  2928. }
  2929. }
  2930. FreeGrowList (&listOfPaths);
  2931. FreeGrowList (&g_StartMenuItemsForCleanUpCommon);
  2932. FreeGrowList (&g_StartMenuItemsForCleanUpPrivate);
  2933. }
  2934. }
  2935. VOID
  2936. SetClassicLogonType (
  2937. VOID
  2938. )
  2939. {
  2940. static BOOL logonTypeChanged = FALSE;
  2941. DWORD d;
  2942. HKEY key;
  2943. LONG regResult;
  2944. if (!logonTypeChanged) {
  2945. key = OpenRegKeyStr (S_WINLOGON_REGKEY);
  2946. if (key) {
  2947. d = 0; // classic logon style
  2948. regResult = RegSetValueEx (
  2949. key,
  2950. TEXT("LogonType"),
  2951. 0,
  2952. REG_DWORD,
  2953. (PCBYTE)(&d),
  2954. sizeof (d)
  2955. );
  2956. if (regResult == ERROR_SUCCESS) {
  2957. logonTypeChanged = TRUE;
  2958. LOG ((LOG_INFORMATION, "Logon type set to classic style because of MigrateUserAs answer file settings"));
  2959. }
  2960. CloseRegKey (key);
  2961. }
  2962. if (!logonTypeChanged) {
  2963. LOG ((LOG_ERROR, "Failed to set logon type to classic style; users will not appear in the logon menu"));
  2964. logonTypeChanged = TRUE;
  2965. }
  2966. }
  2967. }