Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

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