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.

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