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

3232 lines
84 KiB

  1. /*++
  2. Copyright (c) 1997 Microsoft Corporation
  3. Module Name:
  4. sysmig.c
  5. Abstract:
  6. System migration functions for Win95
  7. Author:
  8. Jim Schmidt (jimschm) 13-Feb-1997
  9. Revision History:
  10. jimschm 09-Mar-2001 Redesigned file list code to support LDID enumeration in
  11. a clear way
  12. marcw 18-Mar-1999 Boot16 now set to BOOT16_YES unless it has been
  13. explicitly set to BOOT16_NO or the partition will
  14. be converted to NTFS.
  15. jimschm 23-Sep-1998 Updated for new fileops code
  16. jimschm 12-May-1998 Added .386 warning
  17. calinn 19-Nov-1997 Added pSaveDosFiles, will move DOS files out of the way
  18. during upgrade
  19. marcw 21-Jul-1997 Added end-processing of special keys.
  20. (e.g. HKLM\Software\Microsoft\CurrentVersion\RUN)
  21. jimschm 20-Jun-1997 Hooked up user loop and saved user
  22. names to memdb
  23. --*/
  24. #include "pch.h"
  25. #include "sysmigp.h"
  26. #include "progbar.h"
  27. #include "regops.h"
  28. #include "oleregp.h"
  29. #include <mmsystem.h>
  30. typedef struct TAG_DIRPATH {
  31. struct TAG_DIRPATH *Next;
  32. TCHAR DirPath[];
  33. } DIRIDPATH, *PDIRIDPATH;
  34. typedef struct TAG_DIRID {
  35. struct TAG_DIRID *Next;
  36. PDIRIDPATH FirstDirPath;
  37. UINT DirId;
  38. } DIRIDMAP, *PDIRIDMAP;
  39. typedef struct {
  40. PDIRIDPATH LastMatch;
  41. PCTSTR SubPath;
  42. PTSTR ResultBuffer;
  43. } DIRNAME_ENUM, *PDIRNAME_ENUM;
  44. UINT *g_Boot16;
  45. UINT g_ProgressBarTime;
  46. PDIRIDMAP g_HeadDirId;
  47. PDIRIDMAP g_TailDirId;
  48. POOLHANDLE g_DirIdPool;
  49. PDIRIDMAP g_LastIdPtr;
  50. BOOL
  51. pWarnAboutOldDrivers (
  52. VOID
  53. );
  54. VOID
  55. pAddNtFile (
  56. IN PCTSTR Dir, OPTIONAL
  57. IN PCTSTR FileName, OPTIONAL
  58. IN BOOL BackupThisFile,
  59. IN BOOL CleanThisFile,
  60. IN BOOL OsFile
  61. );
  62. BOOL
  63. WINAPI
  64. SysMig_Entry (
  65. IN HINSTANCE hinstDLL,
  66. IN DWORD dwReason,
  67. IN LPVOID lpv
  68. )
  69. /*++
  70. Routine Description:
  71. SysMig_Entry is a DllMain-like init funciton, called by w95upg\dll.
  72. This function is called at process attach and detach.
  73. Arguments:
  74. hinstDLL - (OS-supplied) instance handle for the DLL
  75. dwReason - (OS-supplied) indicates attach or detatch from process or
  76. thread
  77. lpv - unused
  78. Return Value:
  79. Return value is always TRUE (indicating successful init).
  80. --*/
  81. {
  82. switch (dwReason)
  83. {
  84. case DLL_PROCESS_ATTACH:
  85. g_DirIdPool = PoolMemInitNamedPool ("FileList");
  86. break;
  87. case DLL_PROCESS_DETACH:
  88. TerminateCacheFolderTracking();
  89. if (g_DirIdPool) {
  90. PoolMemDestroyPool (g_DirIdPool);
  91. }
  92. break;
  93. }
  94. return TRUE;
  95. }
  96. BOOL
  97. pPreserveShellIcons (
  98. VOID
  99. )
  100. /*++
  101. Routine Description:
  102. This routine scans the Shell Icons for references to files that
  103. are expected to be deleted. If a reference is found, the file is
  104. removed from the deleted list, and marked to be moved to
  105. %windir%\migicons\shl<n>.
  106. Arguments:
  107. none
  108. Return Value:
  109. none
  110. --*/
  111. {
  112. REGVALUE_ENUM e;
  113. HKEY ShellIcons;
  114. PCTSTR Data;
  115. TCHAR ArgZero[MAX_CMDLINE];
  116. DWORD Binary = 0;
  117. INT IconIndex;
  118. PCTSTR p;
  119. //
  120. // Scan all ProgIDs, looking for default icons that are currently
  121. // set for deletion. Once found, save the icon.
  122. //
  123. ShellIcons = OpenRegKeyStr (S_SHELL_ICONS_REG_KEY);
  124. if (ShellIcons) {
  125. if (EnumFirstRegValue (&e, ShellIcons)) {
  126. do {
  127. Data = (PCTSTR) GetRegValueDataOfType (ShellIcons, e.ValueName, REG_SZ);
  128. if (Data) {
  129. ExtractArgZero (Data, ArgZero);
  130. if (FILESTATUS_UNCHANGED != GetFileStatusOnNt (ArgZero)) {
  131. p = _tcschr (Data, TEXT(','));
  132. if (p) {
  133. IconIndex = _ttoi (_tcsinc (p));
  134. } else {
  135. IconIndex = 0;
  136. }
  137. //
  138. // Extract will fail only if the icon is known good
  139. //
  140. if (ExtractIconIntoDatFile (
  141. ArgZero,
  142. IconIndex,
  143. &g_IconContext,
  144. NULL
  145. )) {
  146. DEBUGMSG ((DBG_SYSMIG, "Preserving shell icon file %s", ArgZero));
  147. }
  148. }
  149. MemFree (g_hHeap, 0, Data);
  150. }
  151. } while (EnumNextRegValue (&e));
  152. }
  153. CloseRegKey (ShellIcons);
  154. }
  155. return TRUE;
  156. }
  157. BOOL
  158. pMoveStaticFiles (
  159. VOID
  160. )
  161. {
  162. BOOL rSuccess = TRUE;
  163. INFSTRUCT is = INITINFSTRUCT_POOLHANDLE;
  164. PCTSTR from;
  165. PCTSTR to;
  166. PCTSTR fromExpanded;
  167. PCTSTR toExpanded;
  168. PCTSTR toFinalDest;
  169. PTSTR Pattern;
  170. FILE_ENUM e;
  171. //
  172. // Cycle through all of the entries in the static move files section.
  173. //
  174. if (InfFindFirstLine(g_Win95UpgInf,S_STATIC_MOVE_FILES,NULL,&is)) {
  175. do {
  176. //
  177. // For each entry, check to see if the file exists. If it does,
  178. // add it into the memdb move file section.
  179. //
  180. from = InfGetStringField(&is,0);
  181. to = InfGetStringField(&is,1);
  182. if (from && to) {
  183. fromExpanded = ExpandEnvironmentText(from);
  184. toExpanded = ExpandEnvironmentText(to);
  185. Pattern = _tcsrchr (fromExpanded, TEXT('\\'));
  186. //
  187. // full path please
  188. //
  189. MYASSERT (Pattern);
  190. if (!Pattern) {
  191. continue;
  192. }
  193. *Pattern = 0;
  194. Pattern++;
  195. if (EnumFirstFile (&e, fromExpanded, Pattern)) {
  196. do {
  197. if (!StringIMatch (e.FileName, Pattern)) {
  198. //
  199. // pattern specified
  200. //
  201. toFinalDest = JoinPaths (toExpanded, e.FileName);
  202. } else {
  203. toFinalDest = toExpanded;
  204. }
  205. if (!IsFileMarkedAsHandled (e.FullPath)) {
  206. //
  207. // Remove general operations, then mark for move
  208. //
  209. RemoveOperationsFromPath (
  210. e.FullPath,
  211. OPERATION_FILE_DELETE|
  212. OPERATION_FILE_MOVE|
  213. OPERATION_FILE_MOVE_BY_NT|
  214. OPERATION_FILE_MOVE_SHELL_FOLDER|
  215. OPERATION_CREATE_FILE
  216. );
  217. MarkFileForMove (e.FullPath, toFinalDest);
  218. }
  219. if (toFinalDest != toExpanded) {
  220. FreePathString (toFinalDest);
  221. }
  222. } while (EnumNextFile (&e));
  223. }
  224. --Pattern;
  225. *Pattern = TEXT('\\');
  226. FreeText (toExpanded);
  227. FreeText (fromExpanded);
  228. }
  229. } while (InfFindNextLine(&is));
  230. }
  231. InfCleanUpInfStruct(&is);
  232. return rSuccess;
  233. }
  234. DWORD
  235. MoveStaticFiles (
  236. IN DWORD Request
  237. )
  238. {
  239. switch (Request) {
  240. case REQUEST_QUERYTICKS:
  241. return TICKS_MOVE_STATIC_FILES;
  242. case REQUEST_RUN:
  243. if (!pMoveStaticFiles ()) {
  244. return GetLastError ();
  245. }
  246. else {
  247. return ERROR_SUCCESS;
  248. }
  249. default:
  250. DEBUGMSG ((DBG_ERROR, "Bad parameter in MoveStaticFiles."));
  251. }
  252. return 0;
  253. }
  254. BOOL
  255. pCopyStaticFiles (
  256. VOID
  257. )
  258. {
  259. BOOL rSuccess = TRUE;
  260. INFSTRUCT is = INITINFSTRUCT_POOLHANDLE;
  261. PCTSTR from;
  262. PCTSTR to;
  263. PCTSTR fromExpanded;
  264. PCTSTR toExpanded;
  265. PCTSTR toFinalDest;
  266. PTSTR Pattern;
  267. FILE_ENUM e;
  268. //
  269. // Cycle through all of the entries in the static copy files section.
  270. //
  271. if (InfFindFirstLine(g_Win95UpgInf,S_STATIC_COPY_FILES,NULL,&is)) {
  272. do {
  273. //
  274. // For each entry, check to see if the file exists. If it does,
  275. // add it into the memdb copy file section.
  276. //
  277. from = InfGetStringField(&is,0);
  278. to = InfGetStringField(&is,1);
  279. if (from && to) {
  280. fromExpanded = ExpandEnvironmentText(from);
  281. toExpanded = ExpandEnvironmentText(to);
  282. Pattern = _tcsrchr (fromExpanded, TEXT('\\'));
  283. //
  284. // full path please
  285. //
  286. MYASSERT (Pattern);
  287. if (!Pattern) {
  288. continue;
  289. }
  290. *Pattern = 0;
  291. Pattern++;
  292. if (EnumFirstFile (&e, fromExpanded, Pattern)) {
  293. do {
  294. if (!StringIMatch (e.FileName, Pattern)) {
  295. //
  296. // pattern specified
  297. //
  298. toFinalDest = JoinPaths (toExpanded, e.FileName);
  299. } else {
  300. toFinalDest = toExpanded;
  301. }
  302. if (!IsFileMarkedForOperation (e.FullPath, OPERATION_FILE_DELETE)) {
  303. MarkFileForCopy (e.FullPath, toFinalDest);
  304. }
  305. if (toFinalDest != toExpanded) {
  306. FreePathString (toFinalDest);
  307. }
  308. } while (EnumNextFile (&e));
  309. }
  310. --Pattern;
  311. *Pattern = TEXT('\\');
  312. FreeText (toExpanded);
  313. FreeText (fromExpanded);
  314. }
  315. } while (InfFindNextLine(&is));
  316. }
  317. InfCleanUpInfStruct(&is);
  318. return rSuccess;
  319. }
  320. DWORD
  321. CopyStaticFiles (
  322. IN DWORD Request
  323. )
  324. {
  325. switch (Request) {
  326. case REQUEST_QUERYTICKS:
  327. return TICKS_COPY_STATIC_FILES;
  328. case REQUEST_RUN:
  329. if (!pCopyStaticFiles ()) {
  330. return GetLastError ();
  331. }
  332. else {
  333. return ERROR_SUCCESS;
  334. }
  335. default:
  336. DEBUGMSG ((DBG_ERROR, "Bad parameter in CopyStaticFiles."));
  337. }
  338. return 0;
  339. }
  340. DWORD
  341. PreserveShellIcons (
  342. IN DWORD Request
  343. )
  344. {
  345. switch (Request) {
  346. case REQUEST_QUERYTICKS:
  347. return TICKS_PRESERVE_SHELL_ICONS;
  348. case REQUEST_RUN:
  349. if (!pPreserveShellIcons ()) {
  350. return GetLastError ();
  351. }
  352. else {
  353. return ERROR_SUCCESS;
  354. }
  355. default:
  356. DEBUGMSG ((DBG_ERROR, "Bad parameter in PreserveShellIcons"));
  357. }
  358. return 0;
  359. }
  360. PCTSTR
  361. GetWindowsInfDir(
  362. VOID
  363. )
  364. {
  365. PTSTR WindowsInfDir = NULL;
  366. /*
  367. NTBUG9:419428 - This registry entry is a semi-colon list of INF paths, and
  368. it can contain Win9x source media INFs on OEM machines.
  369. WindowsInfDir = (PTSTR) GetRegData (S_WINDOWS_CURRENTVERSION, S_DEVICEPATH);
  370. */
  371. if (!WindowsInfDir) {
  372. WindowsInfDir = (PTSTR) MemAlloc (g_hHeap, 0, SizeOfString (g_WinDir) + sizeof (S_INF));
  373. StringCopy (WindowsInfDir, g_WinDir);
  374. StringCopy (AppendWack (WindowsInfDir), S_INF);
  375. }
  376. return WindowsInfDir;
  377. }
  378. #ifndef SM_CMONITORS
  379. #define SM_CMONITORS 80
  380. #endif
  381. BOOL
  382. pProcessMiscMessages (
  383. VOID
  384. )
  385. /*++
  386. Routine Description:
  387. pProcessMiscMessages performs runtime tests for items that are
  388. incompatible, and it adds messages when the tests succeed.
  389. Arguments:
  390. None.
  391. Return Value:
  392. Always TRUE.
  393. --*/
  394. {
  395. PCTSTR Group;
  396. PCTSTR Message;
  397. OSVERSIONINFO Version;
  398. WORD CodePage;
  399. LCID Locale;
  400. if (GetSystemMetrics (SM_CMONITORS) > 1) {
  401. //
  402. // On Win95 and OSR2, GetSystemMetrics returns 0.
  403. //
  404. Group = BuildMessageGroup (MSG_INSTALL_NOTES_ROOT, MSG_MULTI_MONITOR_UNSUPPORTED_SUBGROUP, NULL);
  405. Message = GetStringResource (MSG_MULTI_MONITOR_UNSUPPORTED);
  406. if (Message && Group) {
  407. MsgMgr_ObjectMsg_Add (TEXT("*MultiMonitor"), Group, Message);
  408. }
  409. FreeText (Group);
  410. FreeStringResource (Message);
  411. }
  412. pWarnAboutOldDrivers();
  413. //
  414. // Save platform info
  415. //
  416. Version.dwOSVersionInfoSize = sizeof (Version);
  417. GetVersionEx (&Version);
  418. MemDbSetValueEx (
  419. MEMDB_CATEGORY_STATE,
  420. MEMDB_ITEM_MAJOR_VERSION,
  421. NULL,
  422. NULL,
  423. Version.dwMajorVersion,
  424. NULL
  425. );
  426. MemDbSetValueEx (
  427. MEMDB_CATEGORY_STATE,
  428. MEMDB_ITEM_MINOR_VERSION,
  429. NULL,
  430. NULL,
  431. Version.dwMinorVersion,
  432. NULL
  433. );
  434. MemDbSetValueEx (
  435. MEMDB_CATEGORY_STATE,
  436. MEMDB_ITEM_BUILD_NUMBER,
  437. NULL,
  438. NULL,
  439. Version.dwBuildNumber,
  440. NULL
  441. );
  442. MemDbSetValueEx (
  443. MEMDB_CATEGORY_STATE,
  444. MEMDB_ITEM_PLATFORM_ID,
  445. NULL,
  446. NULL,
  447. Version.dwPlatformId,
  448. NULL
  449. );
  450. MemDbSetValueEx (
  451. MEMDB_CATEGORY_STATE,
  452. MEMDB_ITEM_VERSION_TEXT,
  453. NULL,
  454. Version.szCSDVersion,
  455. 0,
  456. NULL
  457. );
  458. GetGlobalCodePage (&CodePage, &Locale);
  459. MemDbSetValueEx (
  460. MEMDB_CATEGORY_STATE,
  461. MEMDB_ITEM_CODE_PAGE,
  462. NULL,
  463. NULL,
  464. CodePage,
  465. NULL
  466. );
  467. MemDbSetValueEx (
  468. MEMDB_CATEGORY_STATE,
  469. MEMDB_ITEM_LOCALE,
  470. NULL,
  471. NULL,
  472. Locale,
  473. NULL
  474. );
  475. //
  476. // Bad hard disk warning
  477. //
  478. if (!g_ConfigOptions.GoodDrive && HwComp_ReportIncompatibleController()) {
  479. //
  480. // Turn on boot loader flag
  481. //
  482. WriteInfKey (WINNT_DATA, WINNT_D_WIN95UNSUPHDC, S_ONE);
  483. }
  484. return TRUE;
  485. }
  486. DWORD
  487. ProcessMiscMessages (
  488. IN DWORD Request
  489. )
  490. {
  491. switch (Request) {
  492. case REQUEST_QUERYTICKS:
  493. return TICKS_MISC_MESSAGES;
  494. case REQUEST_RUN:
  495. if (!pProcessMiscMessages()) {
  496. return GetLastError ();
  497. }
  498. else {
  499. return ERROR_SUCCESS;
  500. }
  501. default:
  502. DEBUGMSG ((DBG_ERROR, "Bad parameter in ProcessSpecialKeys"));
  503. }
  504. return 0;
  505. }
  506. BOOL
  507. pDeleteWinDirWackInf (
  508. VOID
  509. )
  510. {
  511. PCTSTR WindowsInfDir;
  512. FILE_ENUM e;
  513. DWORD count = 0;
  514. //
  515. // Delete all contents of c:\windows\inf.
  516. //
  517. WindowsInfDir = GetWindowsInfDir();
  518. if (!WindowsInfDir) {
  519. return FALSE;
  520. }
  521. if (EnumFirstFile (&e, WindowsInfDir, NULL)) {
  522. do {
  523. MarkFileForDelete (e.FullPath);
  524. count++;
  525. if (!(count % 32)) {
  526. TickProgressBar ();
  527. }
  528. } while (EnumNextFile (&e));
  529. }
  530. MemFree (g_hHeap, 0, WindowsInfDir);
  531. return TRUE;
  532. }
  533. DWORD
  534. DeleteWinDirWackInf (
  535. IN DWORD Request
  536. )
  537. {
  538. switch (Request) {
  539. case REQUEST_QUERYTICKS:
  540. return TICKS_DELETE_WIN_DIR_WACK_INF;
  541. case REQUEST_RUN:
  542. if (!pDeleteWinDirWackInf ()) {
  543. return GetLastError ();
  544. }
  545. else {
  546. return ERROR_SUCCESS;
  547. }
  548. default:
  549. DEBUGMSG ((DBG_ERROR, "Bad parameter in DeleteWinDirWackInf"));
  550. }
  551. return 0;
  552. }
  553. BOOL
  554. pMoveWindowsIniFiles (
  555. VOID
  556. )
  557. {
  558. WIN32_FIND_DATA fd;
  559. HANDLE FindHandle;
  560. TCHAR WinDirPattern[MAX_TCHAR_PATH];
  561. TCHAR FullPath[MAX_TCHAR_PATH];
  562. TCHAR Key[MEMDB_MAX];
  563. INFCONTEXT context;
  564. DWORD result;
  565. BOOL b = FALSE;
  566. //
  567. // build suppression table
  568. //
  569. if (SetupFindFirstLine (g_Win95UpgInf, S_INI_FILES_IGNORE, NULL, &context)) {
  570. do {
  571. if (SetupGetStringField (&context, 0, Key, MEMDB_MAX, NULL)) {
  572. MemDbSetValueEx (
  573. MEMDB_CATEGORY_INIFILES_IGNORE,
  574. Key,
  575. NULL,
  576. NULL,
  577. 0,
  578. NULL
  579. );
  580. }
  581. } while (SetupFindNextLine (&context, &context));
  582. }
  583. //
  584. // Scan %windir% for files
  585. //
  586. wsprintf (WinDirPattern, TEXT("%s\\*.ini"), g_WinDir);
  587. FindHandle = FindFirstFile (WinDirPattern, &fd);
  588. if (FindHandle != INVALID_HANDLE_VALUE) {
  589. __try {
  590. do {
  591. //
  592. // don't move and process specific INI files
  593. //
  594. MemDbBuildKey (Key, MEMDB_CATEGORY_INIFILES_IGNORE, fd.cFileName, NULL, NULL);
  595. if (!MemDbGetValue (Key, &result)) {
  596. wsprintf (FullPath, TEXT("%s\\%s"), g_WinDir, fd.cFileName);
  597. if (CanSetOperation (FullPath, OPERATION_TEMP_PATH)) {
  598. //
  599. // see bug 317646
  600. //
  601. #ifdef DEBUG
  602. if (StringIMatch (fd.cFileName, TEXT("netcfg.ini"))) {
  603. continue;
  604. }
  605. #endif
  606. MarkFileForTemporaryMove (FullPath, FullPath, g_TempDir);
  607. MarkFileForBackup (FullPath);
  608. }
  609. }
  610. ELSE_DEBUGMSG ((DBG_NAUSEA, "Ini File Ignored : %s\\%s", g_WinDir, fd.cFileName));
  611. } while (FindNextFile (FindHandle, &fd));
  612. b = TRUE;
  613. }
  614. __finally {
  615. FindClose (FindHandle);
  616. }
  617. }
  618. return b;
  619. }
  620. DWORD
  621. MoveWindowsIniFiles (
  622. IN DWORD Request
  623. )
  624. {
  625. switch (Request) {
  626. case REQUEST_QUERYTICKS:
  627. return TICKS_MOVE_INI_FILES;
  628. case REQUEST_RUN:
  629. if (!pMoveWindowsIniFiles ()) {
  630. return GetLastError ();
  631. }
  632. else {
  633. return ERROR_SUCCESS;
  634. }
  635. default:
  636. DEBUGMSG ((DBG_ERROR, "Bad parameter in MoveWindowsIniFiles"));
  637. }
  638. return 0;
  639. }
  640. PTSTR
  641. pFindDosFile (
  642. IN PTSTR FileName
  643. )
  644. {
  645. WIN32_FIND_DATA findFileData;
  646. PTSTR fullPathName = NULL;
  647. PTSTR fullFileName = NULL;
  648. HANDLE findHandle;
  649. fullPathName = AllocPathString (MAX_TCHAR_PATH);
  650. fullFileName = AllocPathString (MAX_TCHAR_PATH);
  651. _tcsncpy (fullPathName, g_WinDir, MAX_TCHAR_PATH/sizeof (fullPathName [0]));
  652. fullFileName = JoinPaths (fullPathName, FileName);
  653. findHandle = FindFirstFile (fullFileName, &findFileData);
  654. if (findHandle != INVALID_HANDLE_VALUE) {
  655. FindClose (&findFileData);
  656. FreePathString (fullPathName);
  657. return fullFileName;
  658. }
  659. FreePathString (fullFileName);
  660. StringCat (fullPathName, S_BOOT16_COMMAND_DIR);
  661. fullFileName = JoinPaths (fullPathName, FileName);
  662. findHandle = FindFirstFile (fullFileName, &findFileData);
  663. if (findHandle != INVALID_HANDLE_VALUE) {
  664. FindClose (&findFileData);
  665. FreePathString (fullPathName);
  666. return fullFileName;
  667. }
  668. FreePathString (fullPathName);
  669. FreePathString (fullFileName);
  670. return NULL;
  671. }
  672. BOOL
  673. pSaveDosFile (
  674. IN PTSTR FileName,
  675. IN PTSTR FullFileName,
  676. IN PTSTR TempPath
  677. )
  678. {
  679. PTSTR newFileName = NULL;
  680. newFileName = JoinPaths (TempPath, FileName);
  681. if (!CopyFile (FullFileName, newFileName, FALSE)) {
  682. DEBUGMSG ((DBG_WARNING, "BOOT16 : Cannot copy %s to %s", FullFileName, newFileName));
  683. }
  684. FreePathString (newFileName);
  685. return TRUE;
  686. }
  687. VOID
  688. pReportNoBoot16 (
  689. VOID
  690. )
  691. /*
  692. This function will report that BOOT16 option will not be available because the file system is going
  693. to be converted to NTFS.
  694. */
  695. {
  696. PCTSTR ReportEntry;
  697. PCTSTR ReportTitle;
  698. PCTSTR Message;
  699. PCTSTR Group;
  700. PTSTR argArray[1];
  701. ReportEntry = GetStringResource (MSG_INSTALL_NOTES_ROOT);
  702. if (ReportEntry) {
  703. argArray [0] = g_Win95Name;
  704. ReportTitle = (PCTSTR)ParseMessageID (MSG_NO_BOOT16_WARNING_SUBGROUP, argArray);
  705. if (ReportTitle) {
  706. Message = (PCTSTR)ParseMessageID (MSG_NO_BOOT16_WARNING, argArray);
  707. if (Message) {
  708. Group = JoinPaths (ReportEntry, ReportTitle);
  709. if (Group) {
  710. MsgMgr_ObjectMsg_Add (TEXT("*NoBoot16"), Group, Message);
  711. FreePathString (Group);
  712. }
  713. FreeStringResourcePtrA (&Message);
  714. }
  715. FreeStringResourcePtrA (&ReportTitle);
  716. }
  717. FreeStringResource (ReportEntry);
  718. }
  719. }
  720. #define S_IOFILE TEXT("IO.SYS")
  721. #define S_MSDOSFILE TEXT("MSDOS.SYS")
  722. #define S_CONFIG_SYS TEXT("CONFIG.SYS")
  723. #define S_AUTOEXEC_BAT TEXT("AUTOEXEC.BAT")
  724. VOID
  725. pMarkDosFileForChange (
  726. IN PCTSTR FileName
  727. )
  728. {
  729. pAddNtFile (g_BootDrivePath, FileName, TRUE, TRUE, TRUE);
  730. }
  731. BOOL
  732. pSaveDosFiles (
  733. VOID
  734. )
  735. {
  736. HINF WkstaMigInf = INVALID_HANDLE_VALUE;
  737. PTSTR boot16TempPath = NULL;
  738. INFCONTEXT infContext;
  739. PTSTR fileName = NULL;
  740. PTSTR fullFileName = NULL;
  741. PTSTR wkstaMigSource = NULL;
  742. PTSTR wkstaMigTarget = NULL;
  743. DWORD result;
  744. TCHAR dir[MAX_PATH];
  745. //
  746. // For restore purposes, mark MSDOS environment as a Win9x OS file
  747. //
  748. pMarkDosFileForChange (S_IOFILE);
  749. pMarkDosFileForChange (S_MSDOSFILE);
  750. pMarkDosFileForChange (S_AUTOEXEC_BAT);
  751. pMarkDosFileForChange (S_CONFIG_SYS);
  752. //
  753. // Now create a backup dir
  754. //
  755. if ((*g_Boot16 == BOOT16_YES) && (*g_ForceNTFSConversion)) {
  756. WriteInfKey (S_WIN9XUPGUSEROPTIONS, TEXT("boot16"), S_NO);
  757. //
  758. // We no longer report the no boot16 message.
  759. //
  760. //pReportNoBoot16 ();
  761. //
  762. return TRUE;
  763. }
  764. if (*g_Boot16 == BOOT16_NO) {
  765. WriteInfKey (S_WIN9XUPGUSEROPTIONS, TEXT("boot16"), S_NO);
  766. }
  767. else
  768. if (*g_Boot16 == BOOT16_YES) {
  769. WriteInfKey (S_WIN9XUPGUSEROPTIONS, TEXT("boot16"), S_YES);
  770. }
  771. else {
  772. WriteInfKey (S_WIN9XUPGUSEROPTIONS, TEXT("boot16"), S_BOOT16_AUTOMATIC);
  773. }
  774. __try {
  775. //prepare our temporary directory for saving dos7 files
  776. boot16TempPath = JoinPaths (g_TempDir, S_BOOT16_DOS_DIR);
  777. if (!CreateDirectory (boot16TempPath, NULL) && (GetLastError()!=ERROR_ALREADY_EXISTS)) {
  778. LOG ((LOG_ERROR,"BOOT16 : Unable to create temporary directory %s",boot16TempPath));
  779. __leave;
  780. }
  781. fileName = AllocPathString (MAX_TCHAR_PATH);
  782. //load the files needed for booting in a 16 bit environment. The files are listed
  783. //in wkstamig.inf section [Win95-DOS files]
  784. wkstaMigSource = JoinPaths (SOURCEDIRECTORY(0), S_WKSTAMIG_INF);
  785. wkstaMigTarget = JoinPaths (g_TempDir, S_WKSTAMIG_INF);
  786. result = SetupDecompressOrCopyFile (wkstaMigSource, wkstaMigTarget, 0);
  787. if ((result != ERROR_SUCCESS) && (result != ERROR_ALREADY_EXISTS)) {
  788. LOG ((LOG_ERROR,"BOOT16 : Unable to decompress WKSTAMIG.INF"));
  789. __leave;
  790. }
  791. WkstaMigInf = InfOpenInfFile (wkstaMigTarget);
  792. if (WkstaMigInf == INVALID_HANDLE_VALUE) {
  793. LOG ((LOG_ERROR,"BOOT16 : WKSTAMIG.INF could not be opened"));
  794. __leave;
  795. }
  796. //read the section, for every file we are trying to find it in either %windir% or
  797. //%windir%\command. If we find it, we'll just copy it to a safe place
  798. if (!SetupFindFirstLine (
  799. WkstaMigInf,
  800. S_BOOT16_SECTION,
  801. NULL,
  802. &infContext
  803. )) {
  804. LOG ((LOG_ERROR,"Cannot read from %s section (WKSTAMIG.INF)",S_BOOT16_SECTION));
  805. return TRUE;
  806. }
  807. do {
  808. if (SetupGetStringField (
  809. &infContext,
  810. 0,
  811. fileName,
  812. MAX_TCHAR_PATH/sizeof(fileName[0]),
  813. NULL
  814. )) {
  815. //see if we can find this file either in %windir% or in %windir%\command
  816. fullFileName = pFindDosFile (fileName);
  817. if (fullFileName != NULL) {
  818. pSaveDosFile (fileName, fullFileName, boot16TempPath);
  819. FreePathString (fullFileName);
  820. fullFileName = NULL;
  821. }
  822. }
  823. }
  824. while (SetupFindNextLine (&infContext, &infContext));
  825. //OK, now save io.sys.
  826. fullFileName = AllocPathString (MAX_TCHAR_PATH);
  827. StringCopy (fullFileName, g_BootDrivePath);
  828. StringCat (fullFileName, S_IOFILE);
  829. pSaveDosFile (S_IOFILE, fullFileName, boot16TempPath);
  830. FreePathString (fullFileName);
  831. fullFileName = NULL;
  832. }
  833. __finally {
  834. if (WkstaMigInf != INVALID_HANDLE_VALUE) {
  835. InfCloseInfFile (WkstaMigInf);
  836. }
  837. if (boot16TempPath) {
  838. FreePathString (boot16TempPath);
  839. }
  840. if (wkstaMigSource) {
  841. FreePathString (wkstaMigSource);
  842. }
  843. if (wkstaMigTarget) {
  844. DeleteFile (wkstaMigTarget);
  845. FreePathString (wkstaMigTarget);
  846. }
  847. if (fileName) {
  848. FreePathString (fileName);
  849. }
  850. }
  851. return TRUE;
  852. }
  853. DWORD
  854. SaveDosFiles (
  855. IN DWORD Request
  856. )
  857. {
  858. if (REPORTONLY()) {
  859. return 0;
  860. }
  861. switch (Request) {
  862. case REQUEST_QUERYTICKS:
  863. return TICKS_SAVE_DOS_FILES;
  864. case REQUEST_RUN:
  865. if (!pSaveDosFiles ()) {
  866. return GetLastError ();
  867. }
  868. else {
  869. return ERROR_SUCCESS;
  870. }
  871. default:
  872. DEBUGMSG ((DBG_ERROR, "Bad parameter in SaveDosFiles"));
  873. }
  874. return 0;
  875. }
  876. DWORD
  877. InitWin95Registry (
  878. IN DWORD Request
  879. )
  880. {
  881. switch (Request) {
  882. case REQUEST_QUERYTICKS:
  883. return TICKS_INIT_WIN95_REGISTRY;
  884. case REQUEST_RUN:
  885. return Win95RegInit (g_WinDir, ISMILLENNIUM());
  886. default:
  887. DEBUGMSG ((DBG_ERROR, "Bad parameter in InitWin95Registry"));
  888. }
  889. return 0;
  890. }
  891. PDIRIDMAP
  892. pFindDirId (
  893. IN UINT DirId,
  894. IN PDIRIDMAP BestGuess, OPTIONAL
  895. IN BOOL Create
  896. )
  897. {
  898. PDIRIDMAP map;
  899. MYASSERT (Create || (g_HeadDirId && g_TailDirId));
  900. //
  901. // Find the existing dir ID. Check the caller's best guess first.
  902. //
  903. if (BestGuess && BestGuess->DirId == DirId) {
  904. return BestGuess;
  905. }
  906. map = g_HeadDirId;
  907. while (map) {
  908. if (map->DirId == DirId) {
  909. return map;
  910. }
  911. map = map->Next;
  912. }
  913. if (!Create) {
  914. return NULL;
  915. }
  916. //
  917. // Insert a new dir ID struct at the end of the list
  918. //
  919. map = (PDIRIDMAP) PoolMemGetAlignedMemory (g_DirIdPool, sizeof (DIRIDMAP));
  920. if (g_TailDirId) {
  921. g_TailDirId->Next = map;
  922. } else {
  923. g_HeadDirId = map;
  924. }
  925. g_TailDirId = map;
  926. map->Next = NULL;
  927. map->FirstDirPath = NULL;
  928. map->DirId = DirId;
  929. return map;
  930. }
  931. VOID
  932. pInsertDirIdPath (
  933. IN UINT DirId,
  934. IN PCTSTR DirPath,
  935. IN OUT PDIRIDMAP *BestGuess
  936. )
  937. {
  938. PDIRIDPATH pathStruct;
  939. PDIRIDPATH existingPathStruct;
  940. PDIRIDMAP dirIdMap;
  941. //
  942. // Locate the dir ID structure, then append the DirPath to the
  943. // list of paths for the ID
  944. //
  945. dirIdMap = pFindDirId (DirId, *BestGuess, TRUE);
  946. MYASSERT (dirIdMap);
  947. *BestGuess = dirIdMap;
  948. existingPathStruct = dirIdMap->FirstDirPath;
  949. while (existingPathStruct) {
  950. if (StringIMatch (existingPathStruct->DirPath, DirPath)) {
  951. return;
  952. }
  953. existingPathStruct = existingPathStruct->Next;
  954. }
  955. pathStruct = (PDIRIDPATH) PoolMemGetAlignedMemory (
  956. g_DirIdPool,
  957. sizeof (DIRIDPATH) + SizeOfString (DirPath)
  958. );
  959. pathStruct->Next = dirIdMap->FirstDirPath;
  960. dirIdMap->FirstDirPath = pathStruct;
  961. StringCopy (pathStruct->DirPath, DirPath);
  962. }
  963. BOOL
  964. pConvertFirstDirName (
  965. OUT PDIRNAME_ENUM EnumPtr,
  966. IN PCTSTR DirNameWithId,
  967. OUT PTSTR DirNameWithPath,
  968. IN OUT PDIRIDMAP *LastDirIdMatch,
  969. IN BOOL Convert11To1501
  970. )
  971. {
  972. UINT id;
  973. PDIRIDMAP idToPath;
  974. EnumPtr->ResultBuffer = DirNameWithPath;
  975. EnumPtr->LastMatch = NULL;
  976. //
  977. // Find the dir ID in the list of all dir IDs
  978. //
  979. id = _tcstoul (DirNameWithId, (PTSTR *) (&EnumPtr->SubPath), 10);
  980. if (!id) {
  981. DEBUGMSG ((DBG_WARNING, "Dir ID %s is not valid", DirNameWithId));
  982. return FALSE;
  983. }
  984. DEBUGMSG_IF ((
  985. EnumPtr->SubPath[0] != TEXT('\\') && EnumPtr->SubPath[0],
  986. DBG_WHOOPS,
  987. "Error in filelist.dat: non-numeric characters following LDID: %s",
  988. DirNameWithId
  989. ));
  990. if (Convert11To1501 && id == 11) {
  991. id = 1501;
  992. }
  993. idToPath = pFindDirId (id, *LastDirIdMatch, FALSE);
  994. if (!idToPath || !(idToPath->FirstDirPath)) {
  995. DEBUGMSG ((DBG_WARNING, "Dir ID %s is not in the list and might not exist on the system", DirNameWithId));
  996. return FALSE;
  997. }
  998. *LastDirIdMatch = idToPath;
  999. EnumPtr->LastMatch = idToPath->FirstDirPath;
  1000. wsprintf (EnumPtr->ResultBuffer, TEXT("%s%s"), EnumPtr->LastMatch->DirPath, EnumPtr->SubPath);
  1001. return TRUE;
  1002. }
  1003. BOOL
  1004. pConvertNextDirName (
  1005. IN OUT PDIRNAME_ENUM EnumPtr
  1006. )
  1007. {
  1008. if (EnumPtr->LastMatch) {
  1009. EnumPtr->LastMatch = EnumPtr->LastMatch->Next;
  1010. }
  1011. if (!EnumPtr->LastMatch) {
  1012. return FALSE;
  1013. }
  1014. wsprintf (EnumPtr->ResultBuffer, TEXT("%s%s"), EnumPtr->LastMatch->DirPath, EnumPtr->SubPath);
  1015. return TRUE;
  1016. }
  1017. typedef struct _KNOWN_DIRS {
  1018. PCSTR DirId;
  1019. PCSTR *Translation;
  1020. }
  1021. KNOWN_DIRS, *PKNOWN_DIRS;
  1022. KNOWN_DIRS g_KnownDirs [] = {
  1023. {"10" , &g_WinDir},
  1024. {"11" , &g_System32Dir},
  1025. {"12" , &g_DriversDir},
  1026. {"17" , &g_InfDir},
  1027. {"18" , &g_HelpDir},
  1028. {"20" , &g_FontsDir},
  1029. {"21" , &g_ViewersDir},
  1030. {"23" , &g_ColorDir},
  1031. {"24" , &g_WinDrive},
  1032. {"25" , &g_SharedDir},
  1033. {"30" , &g_BootDrive},
  1034. {"50" , &g_SystemDir},
  1035. {"51" , &g_SpoolDir},
  1036. {"52" , &g_SpoolDriversDir},
  1037. {"53" , &g_ProfileDirNt},
  1038. {"54" , &g_BootDrive},
  1039. {"55" , &g_PrintProcDir},
  1040. {"1501" , &g_SystemDir},
  1041. {"1501" , &g_System32Dir},
  1042. {"7523" , &g_ProfileDir},
  1043. {"7523" , &g_CommonProfileDir},
  1044. {"16422", &g_ProgramFilesDir},
  1045. {"16427", &g_ProgramFilesCommonDir},
  1046. {"66002", &g_System32Dir},
  1047. {"66003", &g_ColorDir},
  1048. {NULL, NULL}
  1049. };
  1050. typedef struct {
  1051. PCSTR ShellFolderName;
  1052. PCSTR DirId;
  1053. } SHELL_TO_DIRS, *PSHELL_TO_DIRS;
  1054. SHELL_TO_DIRS g_ShellToDirs[] = {
  1055. {"Administrative Tools", "7501"},
  1056. {"Common Administrative Tools", "7501"},
  1057. {"AppData", "7502"},
  1058. {"Common AppData", "7502"},
  1059. {"Cache", "7503"},
  1060. {"Cookies", "7504"},
  1061. {"Desktop", "7505"},
  1062. {"Common Desktop", "7505"},
  1063. {"Favorites", "7506"},
  1064. {"Common Favorites", "7506"},
  1065. {"Fonts", "7507"},
  1066. {"History", "7508"},
  1067. {"Local AppData", "7509"},
  1068. {"Local Settings", "7510"},
  1069. {"My Music", "7511"},
  1070. {"CommonMusic", "7511"},
  1071. {"My Pictures", "7512"},
  1072. {"CommonPictures", "7512"},
  1073. {"My Video", "7513"},
  1074. {"CommonVideo", "7513"},
  1075. {"NetHood", "7514"},
  1076. {"Personal", "7515"},
  1077. {"Common Personal", "7515"},
  1078. {"Common Documents", "7515"},
  1079. {"PrintHood", "7516"},
  1080. {"Programs", "7517"},
  1081. {"Common Programs", "7517"},
  1082. {"Recent", "7518"},
  1083. {"SendTo", "7519"},
  1084. {"Start Menu", "7520"},
  1085. {"Common Start Menu", "7520"},
  1086. {"Startup", "7521"},
  1087. {"Common Startup", "7521"},
  1088. {"Templates", "7522"},
  1089. {"Common Templates", "7522"},
  1090. {"Profiles", "7523"},
  1091. {"Common Profiles", "7523"},
  1092. {NULL, NULL}
  1093. };
  1094. VOID
  1095. pAddKnownShellFolder (
  1096. IN PCTSTR ShellFolderName,
  1097. IN PCTSTR SrcPath
  1098. )
  1099. {
  1100. PSHELL_TO_DIRS p;
  1101. //
  1102. // Translate shell folder name into a dir ID
  1103. //
  1104. for (p = g_ShellToDirs ; p->ShellFolderName ; p++) {
  1105. if (StringIMatch (ShellFolderName, p->ShellFolderName)) {
  1106. break;
  1107. }
  1108. }
  1109. if (!p->ShellFolderName) {
  1110. DEBUGMSG ((DBG_ERROR, "This system has an unsupported shell folder tag: %s", ShellFolderName));
  1111. return;
  1112. }
  1113. //
  1114. // Record dir ID to path match in grow list
  1115. //
  1116. pInsertDirIdPath (_tcstoul (p->DirId, NULL, 10), SrcPath, &g_LastIdPtr);
  1117. }
  1118. VOID
  1119. pInitKnownDirs (
  1120. VOID
  1121. )
  1122. {
  1123. USERENUM eUser;
  1124. SF_ENUM e;
  1125. PKNOWN_DIRS p;
  1126. //
  1127. // Add all fixed known dirs to grow lists
  1128. //
  1129. for (p = g_KnownDirs ; p->DirId ; p++) {
  1130. pInsertDirIdPath (_tcstoul (p->DirId, NULL, 10), *(p->Translation), &g_LastIdPtr);
  1131. }
  1132. //
  1133. // Enumerate all users and put their shell folders in a known dirs struct
  1134. //
  1135. if (EnumFirstUser (&eUser, ENUMUSER_ENABLE_NAME_FIX)) {
  1136. do {
  1137. if (!(eUser.AccountType & INVALID_ACCOUNT)) {
  1138. if (eUser.AccountType & NAMED_USER) {
  1139. //
  1140. // Process the shell folders for this migrated user
  1141. //
  1142. if (EnumFirstRegShellFolder (&e, &eUser)) {
  1143. do {
  1144. pAddKnownShellFolder (e.sfName, e.sfPath);
  1145. } while (EnumNextRegShellFolder (&e));
  1146. }
  1147. }
  1148. }
  1149. } while (!CANCELLED() && EnumNextUser (&eUser));
  1150. if (EnumFirstRegShellFolder (&e, NULL)) {
  1151. do {
  1152. pAddKnownShellFolder (e.sfName, e.sfPath);
  1153. } while (!CANCELLED() && EnumNextRegShellFolder (&e));
  1154. }
  1155. }
  1156. }
  1157. VOID
  1158. pCleanUpKnownDirs (
  1159. VOID
  1160. )
  1161. {
  1162. if (g_DirIdPool) {
  1163. PoolMemDestroyPool (g_DirIdPool);
  1164. g_DirIdPool = NULL;
  1165. g_HeadDirId = NULL;
  1166. g_TailDirId = NULL;
  1167. }
  1168. }
  1169. VOID
  1170. pAddNtFile (
  1171. IN PCTSTR Dir, OPTIONAL
  1172. IN PCTSTR FileName, OPTIONAL
  1173. IN BOOL BackupThisFile,
  1174. IN BOOL CleanThisFile,
  1175. IN BOOL OsFile
  1176. )
  1177. {
  1178. TCHAR copyOfFileName[MAX_PATH];
  1179. PTSTR p;
  1180. PCTSTR fullPath;
  1181. BOOL freePath = FALSE;
  1182. DWORD offset;
  1183. TCHAR key[MEMDB_MAX];
  1184. DWORD value;
  1185. if (!Dir || !FileName) {
  1186. if (!Dir) {
  1187. MYASSERT (FileName);
  1188. fullPath = FileName;
  1189. } else {
  1190. fullPath = Dir;
  1191. }
  1192. StringCopy (copyOfFileName, fullPath);
  1193. p = _tcsrchr (copyOfFileName, TEXT('\\'));
  1194. if (p) {
  1195. *p = 0;
  1196. Dir = copyOfFileName;
  1197. FileName = p + 1;
  1198. } else {
  1199. DEBUGMSG ((DBG_WHOOPS, "Incomplete file name passed as NT OS file: %s", fullPath));
  1200. return;
  1201. }
  1202. } else {
  1203. fullPath = NULL;
  1204. }
  1205. MYASSERT (Dir);
  1206. MYASSERT (FileName);
  1207. if (OsFile) {
  1208. MemDbSetValueEx (
  1209. MEMDB_CATEGORY_NT_DIRS,
  1210. Dir,
  1211. NULL,
  1212. NULL,
  1213. 0,
  1214. &offset
  1215. );
  1216. MemDbSetValueEx (
  1217. MEMDB_CATEGORY_NT_FILES,
  1218. FileName,
  1219. NULL,
  1220. NULL,
  1221. offset,
  1222. NULL
  1223. );
  1224. }
  1225. if (BackupThisFile || CleanThisFile) {
  1226. if (!fullPath) {
  1227. fullPath = JoinPaths (Dir, FileName);
  1228. freePath = TRUE;
  1229. }
  1230. if (BackupThisFile) {
  1231. //
  1232. // If the file exists, back it up (and don't clean it)
  1233. //
  1234. if (DoesFileExist (fullPath)) {
  1235. MarkFileForBackup (fullPath);
  1236. CleanThisFile = FALSE;
  1237. }
  1238. }
  1239. if (CleanThisFile) {
  1240. //
  1241. // Clean will cause the NT-installed file to be deleted
  1242. //
  1243. if (!DoesFileExist (fullPath)) {
  1244. MemDbBuildKey (
  1245. key,
  1246. MEMDB_CATEGORY_CLEAN_OUT,
  1247. fullPath,
  1248. NULL,
  1249. NULL
  1250. );
  1251. if (MemDbGetValue (key, &value)) {
  1252. if (value) {
  1253. DEBUGMSG ((
  1254. DBG_WARNING,
  1255. "File %s already in uninstall cleanout list with type %u",
  1256. fullPath,
  1257. value
  1258. ));
  1259. }
  1260. return;
  1261. }
  1262. MemDbSetValue (key, 0);
  1263. }
  1264. }
  1265. if (freePath) {
  1266. FreePathString (fullPath);
  1267. }
  1268. }
  1269. }
  1270. VOID
  1271. pAddNtPath (
  1272. IN PCTSTR DirName,
  1273. IN BOOL ForceAsOsFile,
  1274. IN BOOL WholeTree,
  1275. IN BOOL ForceDirClean,
  1276. IN PCTSTR FilePattern, OPTIONAL
  1277. IN BOOL ForceFileClean OPTIONAL
  1278. )
  1279. {
  1280. TREE_ENUM e;
  1281. TCHAR rootDir[MAX_PATH];
  1282. PTSTR p;
  1283. BOOL b;
  1284. UINT type;
  1285. TCHAR key[MEMDB_MAX];
  1286. DWORD value;
  1287. MYASSERT (!_tcschr (DirName, TEXT('*')));
  1288. if (IsDriveExcluded (DirName)) {
  1289. DEBUGMSG ((DBG_VERBOSE, "Skipping %s because it is excluded", DirName));
  1290. return;
  1291. }
  1292. if (!IsDriveAccessible (DirName)) {
  1293. DEBUGMSG ((DBG_VERBOSE, "Skipping %s because it is not accessible", DirName));
  1294. return;
  1295. }
  1296. if (!WholeTree) {
  1297. b = EnumFirstFileInTreeEx (&e, DirName, FilePattern, FALSE, FALSE, 1);
  1298. } else {
  1299. b = EnumFirstFileInTree (&e, DirName, FilePattern, FALSE);
  1300. }
  1301. if (b) {
  1302. do {
  1303. if (e.Directory) {
  1304. continue;
  1305. }
  1306. StringCopy (rootDir, e.FullPath);
  1307. p = _tcsrchr (rootDir, TEXT('\\'));
  1308. if (p) {
  1309. *p = 0;
  1310. //
  1311. // Limit the file size to 5MB
  1312. //
  1313. if (e.FindData->nFileSizeHigh == 0 &&
  1314. e.FindData->nFileSizeLow <= 5242880
  1315. ) {
  1316. pAddNtFile (rootDir, e.Name, TRUE, ForceFileClean, ForceAsOsFile);
  1317. }
  1318. ELSE_DEBUGMSG ((
  1319. DBG_WARNING,
  1320. "Not backing up big file %s. It is %I64u bytes.",
  1321. e.FullPath,
  1322. (ULONGLONG) e.FindData->nFileSizeHigh << 32 | (ULONGLONG) e.FindData->nFileSizeLow
  1323. ));
  1324. }
  1325. } while (EnumNextFileInTree (&e));
  1326. }
  1327. if (ForceDirClean) {
  1328. type = WholeTree ? BACKUP_AND_CLEAN_TREE : BACKUP_AND_CLEAN_SUBDIR;
  1329. } else if (WholeTree) {
  1330. type = BACKUP_SUBDIRECTORY_TREE;
  1331. } else {
  1332. type = BACKUP_SUBDIRECTORY_FILES;
  1333. }
  1334. MemDbBuildKey (
  1335. key,
  1336. MEMDB_CATEGORY_CLEAN_OUT,
  1337. DirName,
  1338. NULL,
  1339. NULL
  1340. );
  1341. if (MemDbGetValue (key, &value)) {
  1342. if (!value && type) {
  1343. DEBUGMSG ((
  1344. DBG_WARNING,
  1345. "NT File %s already in uninstall cleanout list, overriding with type %u",
  1346. DirName,
  1347. type
  1348. ));
  1349. } else {
  1350. if (value != type) {
  1351. DEBUGMSG ((
  1352. DBG_WARNING,
  1353. "NT File %s already in uninstall cleanout list with type %u",
  1354. DirName,
  1355. value
  1356. ));
  1357. }
  1358. return;
  1359. }
  1360. }
  1361. MemDbSetValue (key, type);
  1362. }
  1363. VOID
  1364. pAddEmptyDirsTree (
  1365. IN PCTSTR RootDir
  1366. )
  1367. {
  1368. TREE_ENUM e;
  1369. DWORD attribs;
  1370. TCHAR key[MEMDB_MAX];
  1371. DWORD value;
  1372. if (IsDriveExcluded (RootDir)) {
  1373. DEBUGMSG ((DBG_VERBOSE, "Skipping empty dir tree of %s because it is excluded", RootDir));
  1374. return;
  1375. }
  1376. if (!IsDriveAccessible (RootDir)) {
  1377. DEBUGMSG ((DBG_VERBOSE, "Skipping empty dir tree of %s because it is not accessible", RootDir));
  1378. return;
  1379. }
  1380. if (DoesFileExist (RootDir)) {
  1381. if (EnumFirstFileInTreeEx (
  1382. &e,
  1383. RootDir,
  1384. NULL,
  1385. FALSE,
  1386. FALSE,
  1387. FILE_ENUM_ALL_LEVELS
  1388. )) {
  1389. do {
  1390. if (e.Directory) {
  1391. AddDirPathToEmptyDirsCategory (e.FullPath, TRUE, FALSE);
  1392. }
  1393. } while (EnumNextFileInTree (&e));
  1394. } else {
  1395. attribs = GetFileAttributes (RootDir);
  1396. if (attribs == FILE_ATTRIBUTE_DIRECTORY ||
  1397. attribs == INVALID_ATTRIBUTES
  1398. ) {
  1399. attribs = 0;
  1400. }
  1401. MemDbBuildKey (
  1402. key,
  1403. MEMDB_CATEGORY_EMPTY_DIRS,
  1404. RootDir,
  1405. NULL,
  1406. NULL
  1407. );
  1408. if (MemDbGetValue (key, &value)) {
  1409. if (value) {
  1410. DEBUGMSG_IF ((
  1411. value != attribs,
  1412. DBG_ERROR,
  1413. "Ignoring conflict in empty dirs for %s",
  1414. RootDir
  1415. ));
  1416. return;
  1417. }
  1418. }
  1419. MemDbSetValue (key, attribs);
  1420. }
  1421. }
  1422. ELSE_DEBUGMSG ((DBG_SYSMIG, "Uninstall: dir does not exist: %s", RootDir));
  1423. }
  1424. BOOL
  1425. ReadNtFilesEx (
  1426. IN PCSTR FileListName, //optional, if null default is opened
  1427. IN BOOL ConvertPath
  1428. )
  1429. {
  1430. PCSTR fileListName = NULL;
  1431. PCSTR fileListTmp = NULL;
  1432. HANDLE fileHandle = NULL;
  1433. HANDLE mapHandle = NULL;
  1434. PCSTR filePointer = NULL;
  1435. PCSTR dirPointer = NULL;
  1436. PCSTR filePtr = NULL;
  1437. DWORD offset;
  1438. DWORD version;
  1439. BOOL result = FALSE;
  1440. CHAR dirName [MEMDB_MAX];
  1441. PSTR p;
  1442. UINT u;
  1443. INFSTRUCT is = INITINFSTRUCT_POOLHANDLE;
  1444. PCTSTR fileName;
  1445. PCTSTR fileLoc;
  1446. PCTSTR dirId;
  1447. PCTSTR field3;
  1448. PCTSTR field4;
  1449. BOOL forceAsOsFile;
  1450. BOOL forceDirClean;
  1451. DIRNAME_ENUM nameEnum;
  1452. BOOL treeMode;
  1453. HINF drvIndex;
  1454. MEMDB_ENUM memdbEnum;
  1455. DWORD fileAttributes;
  1456. PCTSTR fullPath;
  1457. PCTSTR systemPath;
  1458. BOOL b;
  1459. PDIRIDMAP lastMatch = NULL;
  1460. UINT ticks = 0;
  1461. __try {
  1462. pInitKnownDirs();
  1463. //
  1464. // add to this list the dirs listed in [WinntDirectories] section of txtsetup.sif
  1465. //
  1466. if (InfFindFirstLine(g_TxtSetupSif, S_WINNTDIRECTORIES, NULL, &is)) {
  1467. //
  1468. // all locations are relative to %windir%
  1469. // prepare %windir%\
  1470. //
  1471. StringCopy (dirName, g_WinDir);
  1472. p = GetEndOfString (dirName);
  1473. *p++ = TEXT('\\');
  1474. do {
  1475. ticks++;
  1476. if ((ticks & 255) == 0) {
  1477. if (!TickProgressBarDelta (TICKS_READ_NT_FILES / 50)) {
  1478. __leave;
  1479. }
  1480. }
  1481. //
  1482. // For each entry, add the dir in memdb
  1483. //
  1484. fileLoc = InfGetStringField(&is, 1);
  1485. //
  1486. // ignore special entry "\"
  1487. //
  1488. if (fileLoc && !StringMatch(fileLoc, TEXT("\\"))) {
  1489. StringCopy (p, fileLoc);
  1490. MemDbSetValueEx (
  1491. MEMDB_CATEGORY_NT_DIRS,
  1492. dirName,
  1493. NULL,
  1494. NULL,
  1495. 0,
  1496. NULL
  1497. );
  1498. pAddNtFile (NULL, dirName, FALSE, TRUE, FALSE);
  1499. }
  1500. } while (InfFindNextLine(&is));
  1501. }
  1502. if (FileListName != NULL) {
  1503. filePointer = MapFileIntoMemory (FileListName, &fileHandle, &mapHandle);
  1504. }
  1505. else {
  1506. for (u = 0 ; !fileListName && u < SOURCEDIRECTORYCOUNT() ; u++) {
  1507. fileListName = JoinPaths (SOURCEDIRECTORY(u), S_FILELIST_UNCOMPRESSED);
  1508. if (DoesFileExist (fileListName)) {
  1509. break;
  1510. }
  1511. FreePathString (fileListName);
  1512. fileListName = JoinPaths (SOURCEDIRECTORY(u), S_FILELIST_COMPRESSED);
  1513. if (DoesFileExist (fileListName)) {
  1514. fileListTmp = JoinPaths (g_TempDir, S_FILELIST_UNCOMPRESSED);
  1515. if (SetupDecompressOrCopyFile (fileListName, fileListTmp, 0) == NO_ERROR) {
  1516. FreePathString (fileListName);
  1517. fileListName = fileListTmp;
  1518. break;
  1519. }
  1520. DEBUGMSG ((DBG_ERROR, "Can't copy %s to %s", fileListName, fileListTmp));
  1521. __leave;
  1522. }
  1523. FreePathString (fileListName);
  1524. fileListName = NULL;
  1525. }
  1526. if (!fileListName) {
  1527. SetLastError (ERROR_FILE_NOT_FOUND);
  1528. DEBUGMSG ((DBG_ERROR, "Can't find %s", fileListName));
  1529. __leave;
  1530. }
  1531. filePointer = MapFileIntoMemory (fileListName, &fileHandle, &mapHandle);
  1532. if (!fileListTmp) {
  1533. FreePathString (fileListName);
  1534. }
  1535. }
  1536. filePtr = filePointer;
  1537. if (filePointer == NULL) {
  1538. DEBUGMSG ((DBG_ERROR, "Invalid file format: %s", fileListName));
  1539. __leave;
  1540. }
  1541. version = *((PDWORD) filePointer);
  1542. filePointer += sizeof (DWORD);
  1543. __try {
  1544. if (version >= 1) {
  1545. while (*filePointer != 0) {
  1546. ticks++;
  1547. if ((ticks & 255) == 0) {
  1548. if (!TickProgressBarDelta (TICKS_READ_NT_FILES / 50)) {
  1549. __leave;
  1550. }
  1551. }
  1552. dirPointer = filePointer;
  1553. filePointer = GetEndOfString (filePointer) + 1;
  1554. if (ConvertPath) {
  1555. //
  1556. // First loop: add the OS file exactly as it is in filelist.dat
  1557. //
  1558. if (pConvertFirstDirName (&nameEnum, dirPointer, dirName, &lastMatch, FALSE)) {
  1559. do {
  1560. pAddNtFile (dirName, filePointer, FALSE, FALSE, TRUE);
  1561. } while (pConvertNextDirName (&nameEnum));
  1562. }
  1563. //
  1564. // Second loop: add the file for backup, implementing the special system/system32 hack
  1565. //
  1566. if (pConvertFirstDirName (&nameEnum, dirPointer, dirName, &lastMatch, TRUE)) {
  1567. do {
  1568. pAddNtFile (dirName, filePointer, TRUE, FALSE, FALSE);
  1569. } while (pConvertNextDirName (&nameEnum));
  1570. }
  1571. } else {
  1572. pAddNtFile (dirPointer, filePointer, TRUE, FALSE, TRUE);
  1573. }
  1574. filePointer = GetEndOfString (filePointer) + 1;
  1575. }
  1576. if (version >= 2) {
  1577. filePointer ++;
  1578. while (*filePointer != 0) {
  1579. ticks++;
  1580. if ((ticks & 255) == 0) {
  1581. if (!TickProgressBarDelta (TICKS_READ_NT_FILES / 50)) {
  1582. __leave;
  1583. }
  1584. }
  1585. MemDbSetValueEx (
  1586. MEMDB_CATEGORY_NT_FILES_EXCEPT,
  1587. filePointer,
  1588. NULL,
  1589. NULL,
  1590. 0,
  1591. NULL
  1592. );
  1593. filePointer = GetEndOfString (filePointer) + 1;
  1594. }
  1595. if (version >= 3) {
  1596. ticks++;
  1597. if ((ticks & 255) == 0) {
  1598. if (!TickProgressBarDelta (TICKS_READ_NT_FILES / 50)) {
  1599. __leave;
  1600. }
  1601. }
  1602. filePointer ++;
  1603. while (*filePointer != 0) {
  1604. dirPointer = filePointer;
  1605. filePointer = GetEndOfString (filePointer) + 1;
  1606. if (ConvertPath) {
  1607. if (pConvertFirstDirName (&nameEnum, dirPointer, dirName, &lastMatch, TRUE)) {
  1608. do {
  1609. pAddNtFile (dirName, filePointer, TRUE, FALSE, FALSE);
  1610. } while (pConvertNextDirName (&nameEnum));
  1611. }
  1612. } else {
  1613. pAddNtFile (dirPointer, filePointer, TRUE, FALSE, FALSE);
  1614. }
  1615. filePointer = GetEndOfString (filePointer) + 1;
  1616. }
  1617. }
  1618. }
  1619. }
  1620. }
  1621. __except (EXCEPTION_EXECUTE_HANDLER){
  1622. LOG ((LOG_ERROR, "Access violation while reading NT file list."));
  1623. __leave;
  1624. }
  1625. if (CANCELLED()) {
  1626. __leave;
  1627. }
  1628. // so far so good. Let's read static installed section from win95upg.inf
  1629. MYASSERT (g_Win95UpgInf);
  1630. //
  1631. // Cycle through all of the entries in the StaticInstalledFiles section.
  1632. //
  1633. if (InfFindFirstLine(g_Win95UpgInf,S_STATIC_INSTALLED_FILES,NULL,&is)) {
  1634. do {
  1635. ticks++;
  1636. if ((ticks & 255) == 0) {
  1637. if (!TickProgressBarDelta (TICKS_READ_NT_FILES / 50)) {
  1638. __leave;
  1639. }
  1640. }
  1641. //
  1642. // For each entry, add the file with it's location in memdb
  1643. //
  1644. fileName = InfGetStringField(&is,1);
  1645. fileLoc = InfGetStringField(&is,2);
  1646. if (fileName && fileLoc) {
  1647. if (ConvertPath) {
  1648. if (pConvertFirstDirName (&nameEnum, fileLoc, dirName, &lastMatch, FALSE)) {
  1649. do {
  1650. pAddNtFile (dirName, fileName, TRUE, FALSE, TRUE);
  1651. } while (pConvertNextDirName (&nameEnum));
  1652. }
  1653. } else {
  1654. pAddNtFile (fileLoc, fileName, TRUE, FALSE, TRUE);
  1655. }
  1656. }
  1657. } while (InfFindNextLine(&is));
  1658. }
  1659. //
  1660. // Add the files in drvindex.inf
  1661. //
  1662. drvIndex = InfOpenInfInAllSources (TEXT("drvindex.inf"));
  1663. if (drvIndex == INVALID_HANDLE_VALUE) {
  1664. LOG ((LOG_ERROR, "Can't open drvindex.inf."));
  1665. return FALSE;
  1666. }
  1667. if (InfFindFirstLine (drvIndex, TEXT("driver"), NULL, &is)) {
  1668. do {
  1669. ticks++;
  1670. if ((ticks & 255) == 0) {
  1671. if (!TickProgressBarDelta (TICKS_READ_NT_FILES / 50)) {
  1672. __leave;
  1673. }
  1674. }
  1675. fileName = InfGetStringField (&is, 1);
  1676. //
  1677. // Is this drive file already listed in the file list?
  1678. //
  1679. wsprintf (dirName, MEMDB_CATEGORY_NT_FILES TEXT("\\%s"), fileName);
  1680. if (MemDbGetValue (dirName, NULL)) {
  1681. DEBUGMSG ((DBG_SYSMIG, "%s is listed in drivers and in filelist.dat", fileName));
  1682. } else {
  1683. //
  1684. // Add this file
  1685. //
  1686. pAddNtFile (g_DriversDir, fileName, TRUE, TRUE, TRUE);
  1687. }
  1688. } while (InfFindNextLine (&is));
  1689. }
  1690. InfCloseInfFile (drvIndex);
  1691. //
  1692. // This code marks files to be backed up, because they aren't being caught
  1693. // through the regular mechanisms of setup.
  1694. //
  1695. if (InfFindFirstLine (g_Win95UpgInf, TEXT("Backup"), NULL, &is)) {
  1696. do {
  1697. ticks++;
  1698. if ((ticks & 255) == 0) {
  1699. if (!TickProgressBarDelta (TICKS_READ_NT_FILES / 50)) {
  1700. __leave;
  1701. }
  1702. }
  1703. InfResetInfStruct (&is);
  1704. dirId = InfGetStringField (&is, 1);
  1705. fileName = InfGetStringField (&is, 2);
  1706. field3 = InfGetStringField (&is, 3);
  1707. field4 = InfGetStringField (&is, 4);
  1708. if (dirId && *dirId == 0) {
  1709. dirId = NULL;
  1710. }
  1711. if (fileName && *fileName == 0) {
  1712. fileName = NULL;
  1713. }
  1714. if (field3 && *field3 == 0) {
  1715. field3 = NULL;
  1716. }
  1717. if (field4 && *field4 == 0) {
  1718. field4 = NULL;
  1719. }
  1720. if (!dirId) {
  1721. continue;
  1722. }
  1723. #ifdef DEBUG
  1724. if (!fileName) {
  1725. p = _tcsrchr (dirId, TEXT('\\'));
  1726. if (!p) {
  1727. p = (PTSTR) dirId;
  1728. }
  1729. p = _tcschr (p, TEXT('.'));
  1730. if (p) {
  1731. DEBUGMSG ((DBG_WHOOPS, "%s should be a dir spec, but it looks like it has a file.", dirId));
  1732. }
  1733. }
  1734. #endif
  1735. if (field3) {
  1736. forceAsOsFile = _ttoi (field3) != 0;
  1737. } else {
  1738. forceAsOsFile = FALSE;
  1739. }
  1740. if (field4) {
  1741. forceDirClean = _ttoi (field4) != 0;
  1742. } else {
  1743. forceDirClean = FALSE;
  1744. }
  1745. treeMode = FALSE;
  1746. p = _tcsrchr (dirId, TEXT('\\'));
  1747. if (p && p[1] == TEXT('*') && !p[2]) {
  1748. *p = 0;
  1749. treeMode = TRUE;
  1750. } else {
  1751. p = NULL;
  1752. }
  1753. if (ConvertPath) {
  1754. if (pConvertFirstDirName (&nameEnum, dirId, dirName, &lastMatch, FALSE)) {
  1755. do {
  1756. if (fileName && !treeMode) {
  1757. if (_tcsrchr (fileName, TEXT('*')) || _tcsrchr (fileName, TEXT('?'))) {
  1758. //
  1759. //Add files that match "fileName" pattern from "dirName" directory only
  1760. //
  1761. pAddNtPath (dirName, forceAsOsFile, FALSE, FALSE, fileName, TRUE);
  1762. } else {
  1763. //
  1764. //Add only one file "fileName"
  1765. //
  1766. pAddNtFile (dirName, fileName, TRUE, TRUE, forceAsOsFile);
  1767. }
  1768. } else {
  1769. if (INVALID_ATTRIBUTES == GetFileAttributes (dirName)) {
  1770. if (dirName[0] && dirName[1] == TEXT(':')) {
  1771. pAddNtPath (dirName, FALSE, treeMode, forceDirClean, NULL, FALSE);
  1772. }
  1773. } else {
  1774. //
  1775. //Add all files that match "fileName" pattern from whole tree starting from "dirName"
  1776. //
  1777. pAddNtPath (dirName, forceAsOsFile, treeMode, forceDirClean, fileName, FALSE);
  1778. }
  1779. }
  1780. } while (pConvertNextDirName (&nameEnum));
  1781. }
  1782. }
  1783. } while (InfFindNextLine (&is));
  1784. }
  1785. //
  1786. // In some cases, NT components create empty directories for future use.
  1787. // Some of them aren't ever used. Because setup does not know about
  1788. // them, we list the special cases in a win95upg.inf section called
  1789. // [Uninstall.Delete].
  1790. //
  1791. // For each entry, record the files or empty directories that need to be
  1792. // removed in an uninstall. If an directory is specified but is not empty,
  1793. // then it won't be altered during uninstall.
  1794. //
  1795. if (InfFindFirstLine (g_Win95UpgInf, TEXT("Uninstall.Delete"), NULL, &is)) {
  1796. do {
  1797. ticks++;
  1798. if ((ticks & 255) == 0) {
  1799. if (!TickProgressBarDelta (TICKS_READ_NT_FILES / 50)) {
  1800. __leave;
  1801. }
  1802. }
  1803. dirId = InfGetStringField (&is, 1);
  1804. fileName = InfGetStringField (&is, 2);
  1805. if (!dirId || *dirId == 0) {
  1806. continue;
  1807. }
  1808. if (fileName && *fileName == 0) {
  1809. fileName = NULL;
  1810. }
  1811. if (ConvertPath) {
  1812. if (pConvertFirstDirName (&nameEnum, dirId, dirName, &lastMatch, FALSE)) {
  1813. do {
  1814. pAddNtFile (dirName, fileName, FALSE, TRUE, FALSE);
  1815. } while (pConvertNextDirName (&nameEnum));
  1816. }
  1817. }
  1818. } while (InfFindNextLine (&is));
  1819. }
  1820. if (InfFindFirstLine (g_Win95UpgInf, TEXT("Uninstall.KeepEmptyDirs"), NULL, &is)) {
  1821. do {
  1822. ticks++;
  1823. if ((ticks & 255) == 0) {
  1824. if (!TickProgressBarDelta (TICKS_READ_NT_FILES / 50)) {
  1825. __leave;
  1826. }
  1827. }
  1828. dirId = InfGetStringField (&is, 1);
  1829. if (!dirId || *dirId == 0) {
  1830. continue;
  1831. }
  1832. if (ConvertPath) {
  1833. if (pConvertFirstDirName (&nameEnum, dirId, dirName, &lastMatch, FALSE)) {
  1834. do {
  1835. pAddEmptyDirsTree (dirName);
  1836. } while (pConvertNextDirName (&nameEnum));
  1837. }
  1838. }
  1839. } while (InfFindNextLine (&is));
  1840. }
  1841. result = TRUE;
  1842. }
  1843. __finally {
  1844. UnmapFile ((PVOID)filePtr, fileHandle, mapHandle);
  1845. if (fileListTmp) {
  1846. DeleteFile (fileListTmp);
  1847. FreePathString (fileListTmp);
  1848. fileListTmp = NULL;
  1849. }
  1850. InfCleanUpInfStruct(&is);
  1851. pCleanUpKnownDirs();
  1852. }
  1853. return CANCELLED() ? FALSE : result;
  1854. }
  1855. DWORD
  1856. ReadNtFiles (
  1857. IN DWORD Request
  1858. )
  1859. {
  1860. DWORD ticks = 0;
  1861. switch (Request) {
  1862. case REQUEST_QUERYTICKS:
  1863. return TICKS_READ_NT_FILES;
  1864. case REQUEST_RUN:
  1865. ProgressBar_SetComponentById (MSG_PREPARING_LIST);
  1866. ProgressBar_SetSubComponent (NULL);
  1867. if (!ReadNtFilesEx (NULL, TRUE)) {
  1868. return GetLastError ();
  1869. }
  1870. else {
  1871. return ERROR_SUCCESS;
  1872. }
  1873. default:
  1874. DEBUGMSG ((DBG_ERROR, "Bad parameter in ReadNtFiles"));
  1875. }
  1876. return 0;
  1877. }
  1878. BOOL
  1879. pIsDriverKnown (
  1880. IN PCTSTR DriverFileName,
  1881. IN PCTSTR FullPath,
  1882. IN BOOL DeleteMeansKnown
  1883. )
  1884. {
  1885. HANDLE h;
  1886. DWORD Status;
  1887. //
  1888. // Does DriverFileName have an extension? We require one.
  1889. // If no dot exists, then we assume this is something an OEM added.
  1890. //
  1891. if (!_tcschr (DriverFileName, TEXT('.'))) {
  1892. return TRUE;
  1893. }
  1894. //
  1895. // Is this file in migdb?
  1896. //
  1897. if (IsKnownMigDbFile (DriverFileName)) {
  1898. return TRUE;
  1899. }
  1900. //
  1901. // Is it going to be processed?
  1902. //
  1903. Status = GetFileStatusOnNt (FullPath);
  1904. if (Status != FILESTATUS_UNCHANGED) {
  1905. //
  1906. // If marked for delete, and DeleteMeansKnown is FALSE, then
  1907. // we consider the file unknown because it is simply being
  1908. // deleted as a cleanup step.
  1909. //
  1910. // If DeleteMeansKnown is TRUE, then the caller assumes that
  1911. // a file marked for delete is a known driver.
  1912. //
  1913. if (!(Status == FILESTATUS_DELETED) || DeleteMeansKnown) {
  1914. return TRUE;
  1915. }
  1916. }
  1917. //
  1918. // Make sure this is a NE header (or the more common case, the LE
  1919. // header)
  1920. //
  1921. h = OpenNeFile (FullPath);
  1922. if (!h) {
  1923. DEBUGMSG ((DBG_WARNING, "%s is not a NE file", FullPath));
  1924. //
  1925. // Is this a PE file? If so, the last error will be
  1926. // ERROR_BAD_EXE_FORMAT.
  1927. //
  1928. if (GetLastError() == ERROR_BAD_EXE_FORMAT) {
  1929. return FALSE;
  1930. }
  1931. DEBUGMSG ((DBG_WARNING, "%s is not a PE file", FullPath));
  1932. return TRUE;
  1933. }
  1934. CloseNeFile (h);
  1935. return FALSE;
  1936. }
  1937. BOOL
  1938. pWarnAboutOldDrivers (
  1939. VOID
  1940. )
  1941. {
  1942. HINF Inf;
  1943. TCHAR Path[MAX_TCHAR_PATH];
  1944. INFSTRUCT is = INITINFSTRUCT_GROWBUFFER;
  1945. BOOL b = FALSE;
  1946. PCTSTR Data;
  1947. PCTSTR DriverFile;
  1948. BOOL OldDriverFound = FALSE;
  1949. PCTSTR Group;
  1950. PCTSTR Message;
  1951. TCHAR FullPath[MAX_TCHAR_PATH];
  1952. GROWBUFFER FileList = GROWBUF_INIT;
  1953. PTSTR p;
  1954. wsprintf (Path, TEXT("%s\\system.ini"), g_WinDir);
  1955. Inf = InfOpenInfFile (Path);
  1956. if (Inf != INVALID_HANDLE_VALUE) {
  1957. if (InfFindFirstLine (Inf, TEXT("386Enh"), NULL, &is)) {
  1958. do {
  1959. Data = InfGetStringField (&is, 1);
  1960. if (Data) {
  1961. //
  1962. // Determine if device driver is known
  1963. //
  1964. if (_tcsnextc (Data) != TEXT('*')) {
  1965. DriverFile = GetFileNameFromPath (Data);
  1966. if (!_tcschr (Data, TEXT(':'))) {
  1967. if (!SearchPath (
  1968. NULL,
  1969. DriverFile,
  1970. NULL,
  1971. MAX_TCHAR_PATH,
  1972. FullPath,
  1973. NULL
  1974. )) {
  1975. _tcssafecpy (FullPath, Data, MAX_TCHAR_PATH);
  1976. }
  1977. } else {
  1978. _tcssafecpy (FullPath, Data, MAX_TCHAR_PATH);
  1979. }
  1980. if (!pIsDriverKnown (DriverFile, FullPath, TRUE)) {
  1981. //
  1982. // Unidentified driver; log it and turn on
  1983. // incompatibility message.
  1984. //
  1985. p = (PTSTR) GrowBuffer (&FileList, ByteCount (FullPath) + 7 * sizeof (TCHAR));
  1986. if (p) {
  1987. wsprintf (p, TEXT(" %s\r\n"), FullPath);
  1988. FileList.End -= sizeof (TCHAR);
  1989. }
  1990. OldDriverFound = TRUE;
  1991. MsgMgr_LinkObjectWithContext (TEXT("*386ENH"), Data);
  1992. } else {
  1993. DEBUGMSG ((DBG_NAUSEA, "Driver %s is known", Data));
  1994. }
  1995. }
  1996. }
  1997. } while (InfFindNextLine (&is));
  1998. }
  1999. ELSE_DEBUGMSG ((DBG_ERROR, "pWarnAboutOldDrivers: Cannot open %s", Path));
  2000. InfCloseInfFile (Inf);
  2001. InfCleanUpInfStruct (&is);
  2002. b = TRUE;
  2003. }
  2004. /*NTBUG9:155050
  2005. if (OldDriverFound) {
  2006. LOG ((LOG_INFORMATION, (PCSTR)MSG_386ENH_DRIVER_LOG, FileList.Buf));
  2007. Group = BuildMessageGroup (MSG_INCOMPATIBLE_HARDWARE_ROOT, MSG_OLD_DRIVER_FOUND_SUBGROUP, NULL);
  2008. Message = GetStringResource (MSG_OLD_DRIVER_FOUND_MESSAGE);
  2009. if (Message && Group) {
  2010. MsgMgr_ContextMsg_Add (TEXT("*386ENH"), Group, Message);
  2011. }
  2012. FreeText (Group);
  2013. FreeStringResource (Message);
  2014. }
  2015. */
  2016. FreeGrowBuffer (&FileList);
  2017. return b;
  2018. }
  2019. DWORD
  2020. MoveSystemRegistry (
  2021. IN DWORD Request
  2022. )
  2023. {
  2024. PCTSTR path = NULL;
  2025. switch (Request) {
  2026. case REQUEST_QUERYTICKS:
  2027. return TICKS_MOVE_SYSTEMREGISTRY;
  2028. case REQUEST_RUN:
  2029. path = JoinPaths (g_WinDir, S_SYSTEMDAT);
  2030. MarkHiveForTemporaryMove (path, g_TempDir, NULL, TRUE, FALSE);
  2031. FreePathString (path);
  2032. //
  2033. // on Millennium, also save classes.dat hive
  2034. //
  2035. path = JoinPaths (g_WinDir, S_CLASSESDAT);
  2036. MarkHiveForTemporaryMove (path, g_TempDir, NULL, TRUE, FALSE);
  2037. FreePathString (path);
  2038. return ERROR_SUCCESS;
  2039. }
  2040. return 0;
  2041. }
  2042. VOID
  2043. pProcessJoystick (
  2044. PJOYSTICK_ENUM EnumPtr
  2045. )
  2046. {
  2047. PCTSTR Group;
  2048. TCHAR FullPath[MAX_TCHAR_PATH];
  2049. //
  2050. // Is this joystick compatible?
  2051. //
  2052. if (!_tcschr (EnumPtr->JoystickDriver, TEXT('\\'))) {
  2053. if (!SearchPath (NULL, EnumPtr->JoystickDriver, NULL, MAX_TCHAR_PATH, FullPath, NULL)) {
  2054. StringCopy (FullPath, EnumPtr->JoystickDriver);
  2055. }
  2056. } else {
  2057. StringCopy (FullPath, EnumPtr->JoystickDriver);
  2058. }
  2059. if (!pIsDriverKnown (GetFileNameFromPath (FullPath), FullPath, FALSE)) {
  2060. LOG ((
  2061. LOG_INFORMATION,
  2062. "Joystick driver for %s is not known: %s",
  2063. EnumPtr->JoystickName,
  2064. FullPath
  2065. ));
  2066. Group = BuildMessageGroup (
  2067. MSG_INCOMPATIBLE_HARDWARE_ROOT,
  2068. MSG_JOYSTICK_SUBGROUP,
  2069. EnumPtr->JoystickName
  2070. );
  2071. MsgMgr_ObjectMsg_Add (
  2072. FullPath,
  2073. Group,
  2074. NULL
  2075. );
  2076. FreeText (Group);
  2077. }
  2078. }
  2079. DWORD
  2080. ReportIncompatibleJoysticks (
  2081. IN DWORD Request
  2082. )
  2083. {
  2084. JOYSTICK_ENUM e;
  2085. switch (Request) {
  2086. case REQUEST_QUERYTICKS:
  2087. return TICKS_JOYSTICK_DETECTION;
  2088. case REQUEST_RUN:
  2089. if (EnumFirstJoystick (&e)) {
  2090. do {
  2091. pProcessJoystick (&e);
  2092. } while (EnumNextJoystick (&e));
  2093. }
  2094. return ERROR_SUCCESS;
  2095. }
  2096. return 0;
  2097. }
  2098. DWORD
  2099. TwainCheck (
  2100. DWORD Request
  2101. )
  2102. {
  2103. TWAINDATASOURCE_ENUM e;
  2104. PCTSTR Group;
  2105. if (Request == REQUEST_QUERYTICKS) {
  2106. return TICKS_TWAIN;
  2107. } else if (Request != REQUEST_RUN) {
  2108. return 0;
  2109. }
  2110. if (EnumFirstTwainDataSource (&e)) {
  2111. do {
  2112. if (!TreatAsGood (e.DataSourceModule) &&
  2113. !pIsDriverKnown (
  2114. GetFileNameFromPath (e.DataSourceModule),
  2115. e.DataSourceModule,
  2116. FALSE
  2117. )) {
  2118. //
  2119. // Nobody handled the file. Generate a warning.
  2120. //
  2121. Group = BuildMessageGroup (
  2122. MSG_INCOMPATIBLE_HARDWARE_ROOT,
  2123. MSG_TWAIN_SUBGROUP,
  2124. e.DisplayName
  2125. );
  2126. MsgMgr_ObjectMsg_Add (
  2127. e.DataSourceModule,
  2128. Group,
  2129. NULL
  2130. );
  2131. MarkFileForDelete (e.DataSourceModule);
  2132. FreeText (Group);
  2133. }
  2134. } while (EnumNextTwainDataSource (&e));
  2135. }
  2136. return ERROR_SUCCESS;
  2137. }
  2138. DWORD
  2139. ProcessRecycleBins (
  2140. DWORD Request
  2141. )
  2142. {
  2143. ACCESSIBLE_DRIVE_ENUM e;
  2144. TREE_ENUM eFiles;
  2145. BOOL recycleFound;
  2146. UINT filesDeleted;
  2147. TCHAR recycledInfo[] = TEXT("x:\\recycled\\INFO");
  2148. TCHAR recyclerInfo[] = TEXT("x:\\recycler\\INFO");
  2149. TCHAR recycledInfo2[] = TEXT("x:\\recycled\\INFO2");
  2150. TCHAR recyclerInfo2[] = TEXT("x:\\recycler\\INFO2");
  2151. TCHAR recycled[] = TEXT("x:\\recycled");
  2152. TCHAR recycler[] = TEXT("x:\\recycler");
  2153. PTSTR dir;
  2154. PCTSTR args[1];
  2155. PCTSTR message;
  2156. PCTSTR group;
  2157. if (Request == REQUEST_QUERYTICKS) {
  2158. return TICKS_RECYCLEBINS;
  2159. }
  2160. else if (Request != REQUEST_RUN) {
  2161. return 0;
  2162. }
  2163. recycleFound = FALSE;
  2164. filesDeleted = 0;
  2165. //
  2166. // Enumerate through each of the accessible drives looking for
  2167. // a directory called RECYCLED or RECYCLER on the root.
  2168. //
  2169. if (GetFirstAccessibleDriveEx (&e, TRUE)) {
  2170. do {
  2171. dir = NULL;
  2172. //
  2173. // See if there is any recycle information to examine on
  2174. // this drive.
  2175. //
  2176. recycledInfo[0] = *e->Drive;
  2177. recyclerInfo[0] = *e->Drive;
  2178. recycledInfo2[0] = *e->Drive;
  2179. recyclerInfo2[0] = *e->Drive;
  2180. recycler[0] = *e->Drive;
  2181. recycled[0] = *e->Drive;
  2182. if (DoesFileExist (recycledInfo) || DoesFileExist (recycledInfo2)) {
  2183. dir = recycled;
  2184. }
  2185. else if (DoesFileExist(recyclerInfo) || DoesFileExist (recyclerInfo2)) {
  2186. dir = recycler;
  2187. }
  2188. if (dir) {
  2189. if (IsDriveExcluded (dir)) {
  2190. DEBUGMSG ((DBG_VERBOSE, "Skipping recycle dir %s because it is excluded", dir));
  2191. dir = NULL;
  2192. } else if (!IsDriveAccessible (dir)) {
  2193. DEBUGMSG ((DBG_VERBOSE, "Skipping recycle dir %s because it is not accessible", dir));
  2194. dir = NULL;
  2195. }
  2196. }
  2197. if (dir && EnumFirstFileInTree (&eFiles, dir, NULL, FALSE)) {
  2198. //
  2199. // We have work to do, Enumerate the files and mark them for
  2200. // deletion.
  2201. //
  2202. do {
  2203. //
  2204. // Mark the file for deletion, tally up the saved bytes, and free the space on the drive.
  2205. //
  2206. filesDeleted++;
  2207. FreeSpace (eFiles.FullPath,(eFiles.FindData->nFileSizeHigh * MAXDWORD) + eFiles.FindData->nFileSizeLow);
  2208. //
  2209. // only display Recycle Bin warning if there are visible files there
  2210. //
  2211. if (!(eFiles.FindData->dwFileAttributes & FILE_ATTRIBUTE_HIDDEN)) {
  2212. recycleFound = TRUE;
  2213. }
  2214. } while (EnumNextFileInTree (&eFiles));
  2215. //
  2216. // We are going to delete all of this directory.
  2217. //
  2218. MemDbSetValueEx (MEMDB_CATEGORY_FULL_DIR_DELETES, dir, NULL, NULL, 0, NULL);
  2219. }
  2220. } while (GetNextAccessibleDrive (&e));
  2221. }
  2222. if (recycleFound) {
  2223. //
  2224. // We need to provide the user with a message.
  2225. //
  2226. wsprintf(recycled,"%d",filesDeleted);
  2227. args[0] = recycled;
  2228. group = BuildMessageGroup (MSG_INSTALL_NOTES_ROOT, MSG_RECYCLE_BIN_SUBGROUP, NULL);
  2229. message = ParseMessageID (MSG_RECYCLED_FILES_WILL_BE_DELETED, args);
  2230. if (message && group) {
  2231. MsgMgr_ObjectMsg_Add (TEXT("*RECYCLEBIN"), group, message);
  2232. FreeText (group);
  2233. FreeStringResource (message);
  2234. }
  2235. }
  2236. return 0;
  2237. }
  2238. DWORD
  2239. AnswerFileDetection (
  2240. IN DWORD Request
  2241. )
  2242. {
  2243. INFSTRUCT is = INITINFSTRUCT_GROWBUFFER;
  2244. TCHAR KeyStr[MAX_REGISTRY_KEY];
  2245. TCHAR EncodedKeyStr[MAX_ENCODED_RULE];
  2246. TCHAR ValueName[MAX_REGISTRY_VALUE_NAME];
  2247. TCHAR EncodedValueName[MAX_ENCODED_RULE];
  2248. PTSTR ValueDataPattern = NULL;
  2249. PBYTE ValueData = NULL;
  2250. PTSTR ValueDataStr = NULL;
  2251. PCTSTR p;
  2252. PTSTR q;
  2253. HKEY Key = NULL;
  2254. BOOL DefaultValue;
  2255. TCHAR SectionName[MAX_INF_SECTION_NAME];
  2256. TCHAR InfKey[MAX_INF_KEY_NAME];
  2257. TCHAR InfKeyData[MAX_INF_KEY_NAME];
  2258. DWORD Type;
  2259. DWORD Size;
  2260. BOOL Match;
  2261. UINT u;
  2262. switch (Request) {
  2263. case REQUEST_QUERYTICKS:
  2264. return TICKS_ANSWER_FILE_DETECTION;
  2265. case REQUEST_RUN:
  2266. if (InfFindFirstLine (g_Win95UpgInf, S_ANSWER_FILE_DETECTION, NULL, &is)) {
  2267. do {
  2268. __try {
  2269. //
  2270. // The first field has the key and optional value, encoded
  2271. // in the standard usermig.inf and wkstamig.inf syntax
  2272. //
  2273. DefaultValue = FALSE;
  2274. p = InfGetStringField (&is, 1);
  2275. if (!p || *p == 0) {
  2276. continue;
  2277. }
  2278. StackStringCopy (EncodedKeyStr, p);
  2279. q = _tcschr (EncodedKeyStr, TEXT('['));
  2280. if (q) {
  2281. StringCopy (EncodedValueName, SkipSpace (q + 1));
  2282. *q = 0;
  2283. q = _tcschr (EncodedValueName, TEXT(']'));
  2284. if (q) {
  2285. *q = 0;
  2286. }
  2287. ELSE_DEBUGMSG ((
  2288. DBG_WHOOPS,
  2289. "Unmatched square brackets in %s (see [%s])",
  2290. p,
  2291. S_ANSWER_FILE_DETECTION
  2292. ));
  2293. if (*EncodedValueName == 0) {
  2294. DefaultValue = TRUE;
  2295. } else {
  2296. q = (PTSTR) SkipSpaceR (EncodedValueName, NULL);
  2297. if (q) {
  2298. *_mbsinc (q) = 0;
  2299. }
  2300. }
  2301. } else {
  2302. *EncodedValueName = 0;
  2303. }
  2304. q = (PTSTR) SkipSpaceR (EncodedKeyStr, NULL);
  2305. if (q) {
  2306. *_mbsinc (q) = 0;
  2307. }
  2308. DecodeRuleChars (KeyStr, EncodedKeyStr);
  2309. DecodeRuleChars (ValueName, EncodedValueName);
  2310. //
  2311. // The second field has the optional value data. If it
  2312. // is empty, then the value data is not tested.
  2313. //
  2314. p = InfGetStringField (&is, 2);
  2315. if (p && *p) {
  2316. ValueDataPattern = AllocText (CharCount (p) + 1);
  2317. StringCopy (ValueDataPattern, p);
  2318. } else {
  2319. ValueDataPattern = NULL;
  2320. }
  2321. //
  2322. // The third field has the section name
  2323. //
  2324. p = InfGetStringField (&is, 3);
  2325. if (!p || *p == 0) {
  2326. DEBUGMSG ((DBG_WHOOPS, "Section %s lacks a section name", S_ANSWER_FILE_DETECTION));
  2327. continue;
  2328. }
  2329. StackStringCopy (SectionName, p);
  2330. //
  2331. // The fourth field gives the INF key name
  2332. //
  2333. p = InfGetStringField (&is, 4);
  2334. if (!p || *p == 0) {
  2335. DEBUGMSG ((DBG_WHOOPS, "Section %s lacks an INF key", S_ANSWER_FILE_DETECTION));
  2336. continue;
  2337. }
  2338. StackStringCopy (InfKey, p);
  2339. //
  2340. // The fifth field is optional and gives the INF value name.
  2341. // The default is 1.
  2342. //
  2343. p = InfGetStringField (&is, 5);
  2344. if (p && *p != 0) {
  2345. StackStringCopy (InfKeyData, p);
  2346. } else {
  2347. StringCopy (InfKeyData, TEXT("1"));
  2348. }
  2349. //
  2350. // Data is gathered. Now test the rule.
  2351. //
  2352. DEBUGMSG ((
  2353. DBG_NAUSEA,
  2354. "Testing answer file setting.\n"
  2355. "Key: %s\n"
  2356. "Value Name: %s\n"
  2357. "Value Data: %s\n"
  2358. "Section: %s\n"
  2359. "Key: %s\n"
  2360. "Key Value: %s",
  2361. KeyStr,
  2362. *ValueName ? ValueName : DefaultValue ? TEXT("<default>") : TEXT("<unspecified>"),
  2363. ValueDataPattern ? ValueDataPattern : TEXT("<unspecified>"),
  2364. SectionName,
  2365. InfKey,
  2366. InfKeyData
  2367. ));
  2368. Match = FALSE;
  2369. Key = OpenRegKeyStr (KeyStr);
  2370. if (Key) {
  2371. //
  2372. // Test the value name
  2373. //
  2374. if (*ValueName || DefaultValue) {
  2375. if (GetRegValueTypeAndSize (Key, ValueName, &Type, &Size)) {
  2376. //
  2377. // Test the value data
  2378. //
  2379. if (ValueDataPattern) {
  2380. //
  2381. // Get the data
  2382. //
  2383. ValueData = GetRegValueData (Key, ValueName);
  2384. if (!ValueData) {
  2385. MYASSERT (FALSE);
  2386. continue;
  2387. }
  2388. //
  2389. // Create the string
  2390. //
  2391. switch (Type) {
  2392. case REG_SZ:
  2393. case REG_EXPAND_SZ:
  2394. ValueDataStr = DuplicateText ((PCTSTR) ValueData);
  2395. break;
  2396. case REG_DWORD:
  2397. ValueDataStr = AllocText (11);
  2398. wsprintf (ValueDataStr, TEXT("0x%08X"), *((PDWORD) ValueData));
  2399. break;
  2400. default:
  2401. ValueDataStr = AllocText (3 * (max (1, Size)));
  2402. q = ValueDataStr;
  2403. for (u = 0 ; u < Size ; u++) {
  2404. if (u) {
  2405. *q++ = TEXT(' ');
  2406. }
  2407. wsprintf (q, TEXT("%02X"), ValueData[u]);
  2408. q += 2;
  2409. }
  2410. *q = 0;
  2411. break;
  2412. }
  2413. //
  2414. // Pattern-match the string
  2415. //
  2416. if (IsPatternMatch (ValueDataPattern, ValueDataStr)) {
  2417. DEBUGMSG ((DBG_NAUSEA, "Key, value name and value data found"));
  2418. Match = TRUE;
  2419. }
  2420. ELSE_DEBUGMSG ((
  2421. DBG_NAUSEA,
  2422. "Value data %s did not match %s",
  2423. ValueDataStr,
  2424. ValueDataPattern
  2425. ));
  2426. } else {
  2427. DEBUGMSG ((DBG_NAUSEA, "Key and value name found"));
  2428. Match = TRUE;
  2429. }
  2430. }
  2431. ELSE_DEBUGMSG ((DBG_NAUSEA, "Value name not found, rc=%u", GetLastError()));
  2432. } else {
  2433. DEBUGMSG ((DBG_NAUSEA, "Key found"));
  2434. Match = TRUE;
  2435. }
  2436. }
  2437. ELSE_DEBUGMSG ((DBG_NAUSEA, "Key not found, rc=%u", GetLastError()));
  2438. if (Match) {
  2439. WriteInfKey (SectionName, InfKey, InfKeyData);
  2440. }
  2441. }
  2442. __finally {
  2443. if (Key) {
  2444. CloseRegKey (Key);
  2445. Key = NULL;
  2446. }
  2447. FreeText (ValueDataPattern);
  2448. ValueDataPattern = NULL;
  2449. if (ValueData) {
  2450. MemFree (g_hHeap, 0, ValueData);
  2451. ValueData = NULL;
  2452. }
  2453. FreeText (ValueDataStr);
  2454. ValueDataStr = NULL;
  2455. }
  2456. } while (InfFindNextLine (&is));
  2457. }
  2458. InfCleanUpInfStruct (&is);
  2459. return ERROR_SUCCESS;
  2460. }
  2461. return 0;
  2462. }
  2463. VOID
  2464. pAppendIniFiles (
  2465. IN HINF Inf,
  2466. IN PCTSTR Section,
  2467. IN PCTSTR MemDbCategory
  2468. )
  2469. /*++
  2470. Routine Description:
  2471. pAppendIniFiles reads from the specified INF from given section and appends
  2472. INI patterns to the multisz list IniFiles.
  2473. Arguments:
  2474. Inf - Specifies the source INF handle
  2475. Section - Specifies the section in that INF
  2476. MemDbCategory - Specifies the category in which to store INI patterns from that section
  2477. Return Value:
  2478. none
  2479. --*/
  2480. {
  2481. INFCONTEXT ctx;
  2482. TCHAR Field[MEMDB_MAX];
  2483. TCHAR IniPattern[MAX_PATH];
  2484. PTSTR IniPath;
  2485. if (SetupFindFirstLine (Inf, Section, NULL, &ctx)) {
  2486. do {
  2487. //
  2488. // INI file name is in the first value
  2489. //
  2490. if (SetupGetStringField (&ctx, 1, Field, MEMDB_MAX, NULL) && Field[0]) {
  2491. //
  2492. // now convert env vars
  2493. //
  2494. if (ExpandEnvironmentStrings (Field, IniPattern, MAX_PATH) > MAX_PATH) {
  2495. DEBUGMSG ((
  2496. DBG_ERROR,
  2497. "pAppendIniFiles: Invalid INI dir name in wkstamig.inf section [%s]; name too long",
  2498. Section
  2499. ));
  2500. MYASSERT (FALSE);
  2501. continue;
  2502. }
  2503. IniPath = IniPattern;
  2504. //
  2505. // to speed up things while scanning file system, only check filenames
  2506. // with extension .INI; that means this section should only contain
  2507. // filenames with .INI extension (if a file with a different extension
  2508. // is needed, GatherIniFiles needs to be modified together
  2509. // with this function, i.e. to create here a list of extensions to be
  2510. // searched for)
  2511. //
  2512. MYASSERT (StringIMatch(GetDotExtensionFromPath (IniPattern), TEXT(".INI")));
  2513. //
  2514. // check for empty directory name
  2515. //
  2516. if (!_tcschr (IniPattern, TEXT('\\'))) {
  2517. //
  2518. // no dir name provided, assume %windir%
  2519. // reuse Field
  2520. //
  2521. StringCopy (Field, g_WinDir);
  2522. //
  2523. // construct new path
  2524. //
  2525. StringCopy (AppendWack (Field), IniPattern);
  2526. IniPath = Field;
  2527. }
  2528. //
  2529. // append filename to provided grow buffer
  2530. //
  2531. MemDbSetValueEx (MemDbCategory, IniPath, NULL, NULL, 0, NULL);
  2532. }
  2533. } while (SetupFindNextLine (&ctx, &ctx));
  2534. }
  2535. }
  2536. BOOL
  2537. pCreateIniCategories (
  2538. )
  2539. /*++
  2540. Routine Description:
  2541. pCreateIniCategories appends to multisz buffers that will
  2542. hold the patterns of INI files on which actions will be later performed on NT.
  2543. Arguments:
  2544. none
  2545. Return Value:
  2546. TRUE if success, FALSE if failure.
  2547. --*/
  2548. {
  2549. HINF WkstaMigInf = INVALID_HANDLE_VALUE;
  2550. PTSTR wkstaMigSource = NULL;
  2551. PTSTR wkstaMigTarget = NULL;
  2552. DWORD result;
  2553. BOOL b = FALSE;
  2554. __try {
  2555. wkstaMigSource = JoinPaths (SOURCEDIRECTORY(0), S_WKSTAMIG_INF);
  2556. wkstaMigTarget = JoinPaths (g_TempDir, S_WKSTAMIG_INF);
  2557. result = SetupDecompressOrCopyFile (wkstaMigSource, wkstaMigTarget, 0);
  2558. if ((result != ERROR_SUCCESS) && (result != ERROR_ALREADY_EXISTS)) {
  2559. LOG ((LOG_ERROR, "INI ACTIONS: Unable to decompress %s", wkstaMigSource));
  2560. __leave;
  2561. }
  2562. WkstaMigInf = InfOpenInfFile (wkstaMigTarget);
  2563. if (WkstaMigInf == INVALID_HANDLE_VALUE) {
  2564. LOG ((LOG_ERROR, "INI ACTIONS: %s could not be opened", wkstaMigTarget));
  2565. __leave;
  2566. }
  2567. pAppendIniFiles (WkstaMigInf, S_INIFILES_ACTIONS_FIRST, MEMDB_CATEGORY_INIFILES_ACT_FIRST);
  2568. pAppendIniFiles (WkstaMigInf, S_INIFILES_ACTIONS_LAST, MEMDB_CATEGORY_INIFILES_ACT_LAST);
  2569. b = TRUE;
  2570. }
  2571. __finally {
  2572. result = GetLastError ();
  2573. if (WkstaMigInf != INVALID_HANDLE_VALUE) {
  2574. InfCloseInfFile (WkstaMigInf);
  2575. }
  2576. if (wkstaMigTarget) {
  2577. DeleteFile (wkstaMigTarget);
  2578. FreePathString (wkstaMigTarget);
  2579. }
  2580. if (wkstaMigSource) {
  2581. FreePathString (wkstaMigSource);
  2582. }
  2583. SetLastError (result);
  2584. }
  2585. return b;
  2586. }
  2587. DWORD
  2588. InitIniProcessing (
  2589. IN DWORD Request
  2590. )
  2591. {
  2592. switch (Request) {
  2593. case REQUEST_QUERYTICKS:
  2594. return TICKS_INITINIPROCESSING;
  2595. case REQUEST_RUN:
  2596. if (!pCreateIniCategories ()) {
  2597. return GetLastError ();
  2598. }
  2599. return ERROR_SUCCESS;
  2600. }
  2601. return 0;
  2602. }