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.

3294 lines
98 KiB

  1. /*++
  2. Copyright (c) 1996 Microsoft Corporation
  3. Module Name:
  4. filemig.c
  5. Abstract:
  6. Contains utility functions to migrate file system settings.
  7. Author:
  8. Jim Schmidt (jimschm) 12-Jul-1996
  9. Revision History:
  10. jimschm 08-Jul-1999 Added FileSearchAndReplace
  11. jimschm 23-Sep-1998 Changed for new shell.c & progress.c
  12. calinn 29-Jan-1998 Fixed DoFileDel messages
  13. jimschm 21-Nov-1997 PC-98 changes
  14. jimschm 14-Nov-1997 FileCopy now makes the dest dir if it doesn't
  15. exist
  16. jimschm 18-Jul-1997 Now supports FileCopy and FileDel changes
  17. mikeco 09-Apr-1997 Mods to MoveProfileDir
  18. jimschm 18-Dec-1996 Extracted code from miginf
  19. jimschm 23-Oct-1996 Joined ProcessUserInfs and ApplyChanges
  20. mikeco 04-Dec-1996 Enumerate/modify PIF and LNK files
  21. jimschm 02-Oct-1996 Added default user migration
  22. --*/
  23. #include "pch.h"
  24. #include "migmainp.h"
  25. #include "persist.h"
  26. #include "uninstall.h"
  27. #ifndef UNICODE
  28. #error UNICODE reqired
  29. #endif
  30. #define DBG_FILEMIG "FileMig"
  31. #define BACKUP_FILE_NUMBER 2
  32. #define BOOT_FILES_ADDITIONAL_PADDING (1<<20)
  33. #define UNDO_FILES_ADDITIONAL_PADDING (1<<20)
  34. #define MAX_INT_CHAR 11
  35. PERSISTENCE_IMPLEMENTATION(DRIVE_LAYOUT_INFORMATION_EX_PERSISTENCE);
  36. PERSISTENCE_IMPLEMENTATION(DISKINFO_PERSISTENCE);
  37. PERSISTENCE_IMPLEMENTATION(DRIVEINFO_PERSISTENCE);
  38. PERSISTENCE_IMPLEMENTATION(FILEINTEGRITYINFO_PERSISTENCE);
  39. PERSISTENCE_IMPLEMENTATION(BACKUPIMAGEINFO_PERSISTENCE);
  40. GROWLIST g_StartMenuItemsForCleanUpCommon = GROWLIST_INIT;
  41. GROWLIST g_StartMenuItemsForCleanUpPrivate = GROWLIST_INIT;
  42. BOOL
  43. OurMoveFileExA (
  44. IN PCSTR ExistingFile,
  45. IN PCSTR DestinationFile,
  46. IN DWORD Flags
  47. )
  48. {
  49. PCWSTR unicodeExistingFile;
  50. PCWSTR unicodeDestinationFile;
  51. BOOL b;
  52. unicodeExistingFile = ConvertAtoW (ExistingFile);
  53. unicodeDestinationFile = ConvertAtoW (DestinationFile);
  54. b = OurMoveFileExW (unicodeExistingFile, unicodeDestinationFile, Flags);
  55. FreeConvertedStr (unicodeExistingFile);
  56. FreeConvertedStr (unicodeDestinationFile);
  57. return b;
  58. }
  59. BOOL
  60. OurMoveFileExW (
  61. IN PCWSTR ExistingFile,
  62. IN PCWSTR DestinationFile,
  63. IN DWORD Flags
  64. )
  65. {
  66. PCWSTR longExistingFile;
  67. PCWSTR longDestinationFile;
  68. BOOL b;
  69. longExistingFile = JoinPathsW (L"\\\\?", ExistingFile);
  70. longDestinationFile = JoinPathsW (L"\\\\?", DestinationFile);
  71. MakeSurePathExists (longDestinationFile, FALSE);
  72. DEBUGMSG ((DBG_VERBOSE, "Trying to move %s to %s", longExistingFile, longDestinationFile));
  73. b = MoveFileExW (longExistingFile, longDestinationFile, Flags);
  74. FreePathStringW (longExistingFile);
  75. FreePathStringW (longDestinationFile);
  76. return b;
  77. }
  78. BOOL
  79. OurCopyFileW (
  80. IN PCWSTR ExistingFile,
  81. IN PCWSTR DestinationFile
  82. )
  83. {
  84. PCWSTR longExistingFile;
  85. PCWSTR longDestinationFile;
  86. BOOL b;
  87. longExistingFile = JoinPathsW (L"\\\\?", ExistingFile);
  88. longDestinationFile = JoinPathsW (L"\\\\?", DestinationFile);
  89. DEBUGMSG ((DBG_VERBOSE, "Trying to copy %s to %s", longExistingFile, longDestinationFile));
  90. MakeSurePathExists (longDestinationFile, FALSE);
  91. b = CopyFileW (longExistingFile, longDestinationFile, FALSE);
  92. FreePathStringW (longExistingFile);
  93. FreePathStringW (longDestinationFile);
  94. return b;
  95. }
  96. BOOL
  97. pFileSearchAndReplaceWorker (
  98. IN PBYTE MapStart,
  99. IN PBYTE MapEnd,
  100. IN HANDLE OutFile,
  101. IN PTOKENSET TokenSet
  102. );
  103. BOOL
  104. pCopyFileWithVersionCheck (
  105. IN PCTSTR Src,
  106. IN PCTSTR Dest
  107. )
  108. {
  109. DWORD Attributes;
  110. DWORD rc;
  111. Attributes = GetLongPathAttributes (Src);
  112. if (Attributes == INVALID_ATTRIBUTES) {
  113. SetLastError (ERROR_FILE_NOT_FOUND);
  114. LOG ((LOG_ERROR, "Copy File With Version Check: File not found: %s", Src));
  115. return FALSE;
  116. }
  117. MakeSureLongPathExists (Dest, FALSE); // FALSE == not path only
  118. SetLongPathAttributes (Dest, FILE_ATTRIBUTE_NORMAL);
  119. rc = SetupDecompressOrCopyFile (
  120. Src,
  121. Dest,
  122. FILE_COMPRESSION_NONE
  123. );
  124. if (rc != ERROR_SUCCESS) {
  125. SetLastError (rc);
  126. LOG ((LOG_ERROR, "Cannot copy %s to %s", Src, Dest));
  127. return FALSE;
  128. }
  129. SetLongPathAttributes (Dest, Attributes);
  130. return TRUE;
  131. }
  132. BOOL
  133. pCopyTempRelocToDest (
  134. VOID
  135. )
  136. /*++
  137. Routine Description:
  138. pCopyTempRelocToDest enumerates the DirAttribs category and establishes
  139. a path for each directory listed. It then enumerates the RelocTemp
  140. category and copies each file to its one or more destinations.
  141. Arguments:
  142. none
  143. Return Value:
  144. TRUE if copy succeeded, or FALSE if an error occurred.
  145. Call GetLastError() for error code.
  146. --*/
  147. {
  148. FILEOP_ENUM eOp;
  149. FILEOP_PROP_ENUM eOpProp;
  150. TCHAR srcPath [MEMDB_MAX];
  151. PCTSTR extPtr;
  152. if (EnumFirstPathInOperation (&eOp, OPERATION_TEMP_PATH)) {
  153. do {
  154. srcPath [0] = 0;
  155. if (EnumFirstFileOpProperty (&eOpProp, eOp.Sequencer, OPERATION_TEMP_PATH)) {
  156. do {
  157. if (srcPath [0]) {
  158. //
  159. // if the dest file is an INI file,
  160. // don't copy it;
  161. // the merging mechanism will combine them later
  162. //
  163. extPtr = GetFileExtensionFromPath (eOpProp.Property);
  164. if (extPtr && StringIMatch (extPtr, TEXT("INI"))) {
  165. continue;
  166. }
  167. MakeSureLongPathExists (eOpProp.Property, FALSE);
  168. if (!pCopyFileWithVersionCheck (srcPath, eOpProp.Property)) {
  169. //
  170. // don't stop here; continue with remaining files
  171. //
  172. break;
  173. }
  174. } else {
  175. StringCopy (srcPath, eOpProp.Property);
  176. }
  177. } while (EnumNextFileOpProperty (&eOpProp));
  178. }
  179. } while (EnumNextPathInOperation (&eOp));
  180. }
  181. return TRUE;
  182. }
  183. DWORD
  184. DoCopyFile (
  185. DWORD Request
  186. )
  187. /*++
  188. Routine Description:
  189. DoCopyFile performs a file copy for each file listed in the
  190. file copy operation.
  191. Arguments:
  192. Request - Specifies REQUEST_QUERYTICKS if a tick estimate is needed,
  193. or REQUEST_RUN if processing should be preformed.
  194. Return Value:
  195. Tick count (REQUEST_QUERYTICKS), or Win32 status code (REQUEST_RUN).
  196. --*/
  197. {
  198. FILEOP_ENUM OpEnum;
  199. TCHAR DestPath[MAX_TCHAR_PATH];
  200. if (Request == REQUEST_QUERYTICKS) {
  201. return TICKS_COPYFILE;
  202. }
  203. //
  204. // Perform rest of temporary file relocation
  205. //
  206. pCopyTempRelocToDest();
  207. //
  208. // Copy files into directories
  209. //
  210. if (EnumFirstPathInOperation (&OpEnum, OPERATION_FILE_COPY)) {
  211. do {
  212. //
  213. // Get dest
  214. //
  215. if (GetPathProperty (OpEnum.Path, OPERATION_FILE_COPY, 0, DestPath)) {
  216. MakeSureLongPathExists (DestPath, FALSE);
  217. pCopyFileWithVersionCheck (OpEnum.Path, DestPath);
  218. }
  219. } while (EnumNextPathInOperation (&OpEnum));
  220. }
  221. TickProgressBarDelta (TICKS_COPYFILE);
  222. return ERROR_SUCCESS;
  223. }
  224. PCTSTR g_LnkStubDataFile = NULL;
  225. HANDLE g_LnkStubDataHandle = INVALID_HANDLE_VALUE;
  226. BOOL g_LnkStubBadData = FALSE;
  227. VOID
  228. pInitLnkStubData (
  229. VOID
  230. )
  231. {
  232. INT maxSequencer;
  233. DWORD offset = 0;
  234. DWORD bytesWritten;
  235. MemDbGetValue (MEMDB_CATEGORY_LINKSTUB_MAXSEQUENCE, &maxSequencer);
  236. g_LnkStubDataFile = JoinPaths (g_WinDir, S_LNKSTUB_DAT);
  237. g_LnkStubDataHandle = CreateFile (
  238. g_LnkStubDataFile,
  239. GENERIC_READ|GENERIC_WRITE,
  240. 0,
  241. NULL,
  242. CREATE_ALWAYS,
  243. FILE_ATTRIBUTE_NORMAL,
  244. NULL
  245. );
  246. if (g_LnkStubDataHandle != INVALID_HANDLE_VALUE) {
  247. // let's write empty data for all possible sequencers
  248. // there is a DWORD entry for each sequencer (1 based)
  249. while (maxSequencer) {
  250. if (!WriteFile (
  251. g_LnkStubDataHandle,
  252. &offset,
  253. sizeof (DWORD),
  254. &bytesWritten,
  255. NULL
  256. )) {
  257. g_LnkStubBadData = TRUE;
  258. return;
  259. }
  260. maxSequencer--;
  261. }
  262. } else {
  263. g_LnkStubBadData = TRUE;
  264. }
  265. }
  266. VOID
  267. pDoneLnkStubData (
  268. VOID
  269. )
  270. {
  271. CloseHandle (g_LnkStubDataHandle);
  272. g_LnkStubDataHandle = INVALID_HANDLE_VALUE;
  273. if (g_LnkStubBadData) {
  274. DeleteFile (g_LnkStubDataFile);
  275. }
  276. FreePathString (g_LnkStubDataFile);
  277. g_LnkStubDataFile = NULL;
  278. }
  279. VOID
  280. pWriteLnkStubData (
  281. IN PCTSTR NewLinkPath,
  282. IN PCTSTR NewTarget,
  283. IN PCTSTR NewArgs,
  284. IN PCTSTR NewWorkDir,
  285. IN PCTSTR NewIconPath,
  286. IN INT NewIconNr,
  287. IN INT ShowMode,
  288. IN INT Sequencer,
  289. IN DWORD Announcement,
  290. IN DWORD Availability,
  291. IN PGROWBUFFER ReqFilesList
  292. )
  293. {
  294. DWORD offset;
  295. DWORD bytesWritten;
  296. WIN32_FIND_DATA findData;
  297. MULTISZ_ENUM multiSzEnum;
  298. TCHAR stub[]=TEXT("");
  299. PCTSTR reqFilePath = NULL;
  300. PCTSTR oldFileSpec = NULL;
  301. PTSTR oldFilePtr = NULL;
  302. if ((!g_LnkStubBadData) && (Sequencer > 0)) {
  303. if (SetFilePointer (g_LnkStubDataHandle, (Sequencer - 1) * sizeof (DWORD), NULL, FILE_BEGIN) == 0xFFFFFFFF) {
  304. g_LnkStubBadData = TRUE;
  305. return;
  306. }
  307. offset = GetFileSize (g_LnkStubDataHandle, NULL);
  308. if (offset == 0xFFFFFFFF) {
  309. g_LnkStubBadData = TRUE;
  310. return;
  311. }
  312. if (!WriteFile (
  313. g_LnkStubDataHandle,
  314. &offset,
  315. sizeof (DWORD),
  316. &bytesWritten,
  317. NULL
  318. )) {
  319. g_LnkStubBadData = TRUE;
  320. return;
  321. }
  322. if (SetFilePointer (g_LnkStubDataHandle, 0, NULL, FILE_END) == 0xFFFFFFFF) {
  323. g_LnkStubBadData = TRUE;
  324. return;
  325. }
  326. //
  327. // NOTE: Format of lnkstub.dat is below. lnkstub\lnkstub.c must match.
  328. //
  329. if (!WriteFile (g_LnkStubDataHandle, NewLinkPath, SizeOfString (NewLinkPath), &bytesWritten, NULL)) {
  330. g_LnkStubBadData = TRUE;
  331. return;
  332. }
  333. if (!WriteFile (g_LnkStubDataHandle, NewTarget, SizeOfString (NewTarget), &bytesWritten, NULL)) {
  334. g_LnkStubBadData = TRUE;
  335. return;
  336. }
  337. if (!WriteFile (g_LnkStubDataHandle, NewArgs, SizeOfString (NewArgs), &bytesWritten, NULL)) {
  338. g_LnkStubBadData = TRUE;
  339. return;
  340. }
  341. if (!WriteFile (g_LnkStubDataHandle, NewWorkDir, SizeOfString (NewWorkDir), &bytesWritten, NULL)) {
  342. g_LnkStubBadData = TRUE;
  343. return;
  344. }
  345. if (!WriteFile (g_LnkStubDataHandle, NewIconPath, SizeOfString (NewIconPath), &bytesWritten, NULL)) {
  346. g_LnkStubBadData = TRUE;
  347. return;
  348. }
  349. if (!WriteFile (g_LnkStubDataHandle, &NewIconNr, sizeof (INT), &bytesWritten, NULL)) {
  350. g_LnkStubBadData = TRUE;
  351. return;
  352. }
  353. if (!WriteFile (g_LnkStubDataHandle, &ShowMode, sizeof (INT), &bytesWritten, NULL)) {
  354. g_LnkStubBadData = TRUE;
  355. return;
  356. }
  357. if (!WriteFile (g_LnkStubDataHandle, &Announcement, sizeof (DWORD), &bytesWritten, NULL)) {
  358. g_LnkStubBadData = TRUE;
  359. return;
  360. }
  361. if (!WriteFile (g_LnkStubDataHandle, &Availability, sizeof (DWORD), &bytesWritten, NULL)) {
  362. g_LnkStubBadData = TRUE;
  363. return;
  364. }
  365. if (!DoesFileExistEx (NewTarget, &findData)) {
  366. findData.ftLastWriteTime.dwLowDateTime = 0;
  367. findData.ftLastWriteTime.dwHighDateTime = 0;
  368. }
  369. if (!WriteFile (g_LnkStubDataHandle, &findData.ftLastWriteTime.dwLowDateTime, sizeof (DWORD), &bytesWritten, NULL)) {
  370. g_LnkStubBadData = TRUE;
  371. return;
  372. }
  373. if (!WriteFile (g_LnkStubDataHandle, &findData.ftLastWriteTime.dwHighDateTime, sizeof (DWORD), &bytesWritten, NULL)) {
  374. g_LnkStubBadData = TRUE;
  375. return;
  376. }
  377. if (EnumFirstMultiSz (&multiSzEnum, (PTSTR)ReqFilesList->Buf)) {
  378. do {
  379. if (!WriteFile (
  380. g_LnkStubDataHandle,
  381. multiSzEnum.CurrentString,
  382. SizeOfString (multiSzEnum.CurrentString),
  383. &bytesWritten,
  384. NULL
  385. )) {
  386. g_LnkStubBadData = TRUE;
  387. return;
  388. }
  389. oldFileSpec = DuplicatePathString (NewTarget, 0);
  390. oldFilePtr = (PTSTR)GetFileNameFromPath (oldFileSpec);
  391. if (oldFilePtr) {
  392. *oldFilePtr = 0;
  393. }
  394. reqFilePath = JoinPaths (oldFileSpec, multiSzEnum.CurrentString);
  395. if (!DoesFileExistEx (reqFilePath, &findData)) {
  396. findData.ftLastWriteTime.dwLowDateTime = 0;
  397. findData.ftLastWriteTime.dwHighDateTime = 0;
  398. }
  399. if (!WriteFile (g_LnkStubDataHandle, &findData.ftLastWriteTime.dwLowDateTime, sizeof (DWORD), &bytesWritten, NULL)) {
  400. g_LnkStubBadData = TRUE;
  401. return;
  402. }
  403. if (!WriteFile (g_LnkStubDataHandle, &findData.ftLastWriteTime.dwHighDateTime, sizeof (DWORD), &bytesWritten, NULL)) {
  404. g_LnkStubBadData = TRUE;
  405. return;
  406. }
  407. FreePathString (reqFilePath);
  408. FreePathString (oldFileSpec);
  409. } while ((!g_LnkStubBadData) && EnumNextMultiSz (&multiSzEnum));
  410. }
  411. if (!WriteFile (g_LnkStubDataHandle, stub, SizeOfString (stub), &bytesWritten, NULL)) {
  412. g_LnkStubBadData = TRUE;
  413. return;
  414. }
  415. }
  416. }
  417. BOOL
  418. RestoreInfoFromDefaultPif (
  419. IN PCTSTR UserName,
  420. IN HKEY KeyRoot
  421. )
  422. {
  423. TCHAR key [MEMDB_MAX];
  424. MEMDB_ENUM e;
  425. DWORD value1, value2;
  426. HKEY cmdKey;
  427. cmdKey = OpenRegKey (KeyRoot, S_CMDATTRIB_KEY);
  428. if (!cmdKey) {
  429. cmdKey = CreateRegKey (KeyRoot, S_CMDATTRIB_KEY);
  430. }
  431. if (cmdKey) {
  432. MemDbBuildKey (key, MEMDB_CATEGORY_DEFAULT_PIF, MEMDB_CATEGORY_LINKEDIT_FULLSCREEN, TEXT("*"), NULL);
  433. if (MemDbEnumFirstValue (&e, key, MEMDB_ALL_SUBLEVELS, MEMDB_ENDPOINTS_ONLY)) {
  434. value1 = _ttoi (e.szName);
  435. RegSetValueEx (cmdKey, S_CMD_FULLSCREEN, 0, REG_DWORD, (PCBYTE)&value1, sizeof (DWORD));
  436. }
  437. MemDbBuildKey (key, MEMDB_CATEGORY_DEFAULT_PIF, MEMDB_CATEGORY_LINKEDIT_XSIZE, TEXT("*"), NULL);
  438. if (MemDbEnumFirstValue (&e, key, MEMDB_ALL_SUBLEVELS, MEMDB_ENDPOINTS_ONLY)) {
  439. value1 = _ttoi (e.szName);
  440. MemDbBuildKey (key, MEMDB_CATEGORY_DEFAULT_PIF, MEMDB_CATEGORY_LINKEDIT_YSIZE, TEXT("*"), NULL);
  441. if (MemDbEnumFirstValue (&e, key, MEMDB_ALL_SUBLEVELS, MEMDB_ENDPOINTS_ONLY)) {
  442. value2 = _ttoi (e.szName);
  443. value2 = _rotl (value2, sizeof (DWORD) * 8 / 2);
  444. value1 |= value2;
  445. RegSetValueEx (cmdKey, S_CMD_WINDOWSIZE, 0, REG_DWORD, (PCBYTE)&value1, sizeof (DWORD));
  446. }
  447. }
  448. MemDbBuildKey (key, MEMDB_CATEGORY_DEFAULT_PIF, MEMDB_CATEGORY_LINKEDIT_QUICKEDIT, TEXT("*"), NULL);
  449. if (MemDbEnumFirstValue (&e, key, MEMDB_ALL_SUBLEVELS, MEMDB_ENDPOINTS_ONLY)) {
  450. value1 = _ttoi (e.szName);
  451. RegSetValueEx (cmdKey, S_CMD_QUICKEDIT, 0, REG_DWORD, (PCBYTE)&value1, sizeof (DWORD));
  452. }
  453. MemDbBuildKey (key, MEMDB_CATEGORY_DEFAULT_PIF, MEMDB_CATEGORY_LINKEDIT_FONTNAME, TEXT("*"), NULL);
  454. if (MemDbEnumFirstValue (&e, key, MEMDB_ALL_SUBLEVELS, MEMDB_ENDPOINTS_ONLY)) {
  455. RegSetValueEx (cmdKey, S_CMD_FACENAME, 0, REG_SZ, (PCBYTE)e.szName, SizeOfString (e.szName));
  456. }
  457. MemDbBuildKey (key, MEMDB_CATEGORY_DEFAULT_PIF, MEMDB_CATEGORY_LINKEDIT_XFONTSIZE, TEXT("*"), NULL);
  458. if (MemDbEnumFirstValue (&e, key, MEMDB_ALL_SUBLEVELS, MEMDB_ENDPOINTS_ONLY)) {
  459. value1 = _ttoi (e.szName);
  460. MemDbBuildKey (key, MEMDB_CATEGORY_DEFAULT_PIF, MEMDB_CATEGORY_LINKEDIT_YFONTSIZE, TEXT("*"), NULL);
  461. if (MemDbEnumFirstValue (&e, key, MEMDB_ALL_SUBLEVELS, MEMDB_ENDPOINTS_ONLY)) {
  462. value2 = _ttoi (e.szName);
  463. value2 = _rotl (value2, sizeof (DWORD) * 8 / 2);
  464. value1 |= value2;
  465. RegSetValueEx (cmdKey, S_CMD_FONTSIZE, 0, REG_DWORD, (PCBYTE)&value1, sizeof (DWORD));
  466. }
  467. }
  468. MemDbBuildKey (key, MEMDB_CATEGORY_DEFAULT_PIF, MEMDB_CATEGORY_LINKEDIT_FONTWEIGHT, TEXT("*"), NULL);
  469. if (MemDbEnumFirstValue (&e, key, MEMDB_ALL_SUBLEVELS, MEMDB_ENDPOINTS_ONLY)) {
  470. value1 = _ttoi (e.szName);
  471. RegSetValueEx (cmdKey, S_CMD_FONTWEIGHT, 0, REG_DWORD, (PCBYTE)&value1, sizeof (DWORD));
  472. }
  473. MemDbBuildKey (key, MEMDB_CATEGORY_DEFAULT_PIF, MEMDB_CATEGORY_LINKEDIT_FONTFAMILY, TEXT("*"), NULL);
  474. if (MemDbEnumFirstValue (&e, key, MEMDB_ALL_SUBLEVELS, MEMDB_ENDPOINTS_ONLY)) {
  475. value1 = _ttoi (e.szName);
  476. RegSetValueEx (cmdKey, S_CMD_FONTFAMILY, 0, REG_DWORD, (PCBYTE)&value1, sizeof (DWORD));
  477. }
  478. CloseRegKey (cmdKey);
  479. }
  480. return TRUE;
  481. }
  482. BOOL
  483. DoLinkEdit (
  484. VOID
  485. )
  486. /*++
  487. Routine Description:
  488. DoLinkEdit adjusts all PIFs and LNKs that need their targets, working
  489. directories or icon paths changed.
  490. Arguments:
  491. none
  492. Return Value:
  493. TRUE if link editing succeeded, or FALSE if an error occurred.
  494. --*/
  495. {
  496. FILEOP_ENUM eOp;
  497. FILEOP_PROP_ENUM eOpProp;
  498. BOOL forceToShowNormal;
  499. BOOL ConvertToLnk;
  500. PTSTR NewTarget;
  501. PTSTR NewArgs;
  502. PTSTR NewWorkDir;
  503. PTSTR NewIconPath;
  504. PTSTR NewLinkPath;
  505. INT NewIconNr;
  506. INT Sequencer;
  507. DWORD Announcement;
  508. DWORD Availability;
  509. INT ShowMode;
  510. LNK_EXTRA_DATA ExtraData;
  511. CONVERTPATH_RC C_Result;
  512. TCHAR tempArgs[MAX_TCHAR_PATH * sizeof (TCHAR)];
  513. GROWBUFFER reqFilesList = GROWBUF_INIT;
  514. if (EnumFirstPathInOperation (&eOp, OPERATION_LINK_EDIT)) {
  515. do {
  516. DEBUGMSG ((DBG_VERBOSE, "eOp.Path=%s", eOp.Path));
  517. NewTarget = NULL;
  518. NewArgs = NULL;
  519. NewWorkDir = NULL;
  520. NewIconPath = NULL;
  521. NewIconNr = 0;
  522. ConvertToLnk = FALSE;
  523. forceToShowNormal = FALSE;
  524. ZeroMemory (&ExtraData, sizeof (LNK_EXTRA_DATA));
  525. if (EnumFirstFileOpProperty (&eOpProp, eOp.Sequencer, OPERATION_LINK_EDIT)) {
  526. do {
  527. if (StringIMatch (eOpProp.PropertyName, MEMDB_CATEGORY_LINKEDIT_TARGET)) {
  528. NewTarget = DuplicatePathString (eOpProp.Property, 0);
  529. }
  530. if (StringIMatch (eOpProp.PropertyName, MEMDB_CATEGORY_LINKEDIT_ARGS)) {
  531. StringCopyTcharCount (tempArgs, eOpProp.Property, ARRAYSIZE(tempArgs));
  532. C_Result = ConvertWin9xPath (tempArgs);
  533. NewArgs = DuplicatePathString (tempArgs, 0);
  534. }
  535. if (StringIMatch (eOpProp.PropertyName, MEMDB_CATEGORY_LINKEDIT_WORKDIR)) {
  536. NewWorkDir = DuplicatePathString (eOpProp.Property, 0);
  537. }
  538. if (StringIMatch (eOpProp.PropertyName, MEMDB_CATEGORY_LINKEDIT_ICONPATH)) {
  539. NewIconPath = DuplicatePathString (eOpProp.Property, 0);
  540. }
  541. if (StringIMatch (eOpProp.PropertyName, MEMDB_CATEGORY_LINKEDIT_ICONNUMBER)) {
  542. NewIconNr = _tcstoul (eOpProp.Property, NULL, 16);
  543. }
  544. if (StringIMatch (eOpProp.PropertyName, MEMDB_CATEGORY_LINKEDIT_FULLSCREEN)) {
  545. ConvertToLnk = TRUE;
  546. ExtraData.FullScreen = _ttoi (eOpProp.Property);
  547. }
  548. if (StringIMatch (eOpProp.PropertyName, MEMDB_CATEGORY_LINKEDIT_XSIZE)) {
  549. ConvertToLnk = TRUE;
  550. ExtraData.xSize = _ttoi (eOpProp.Property);
  551. }
  552. if (StringIMatch (eOpProp.PropertyName, MEMDB_CATEGORY_LINKEDIT_YSIZE)) {
  553. ConvertToLnk = TRUE;
  554. ExtraData.ySize = _ttoi (eOpProp.Property);
  555. }
  556. if (StringIMatch (eOpProp.PropertyName, MEMDB_CATEGORY_LINKEDIT_QUICKEDIT)) {
  557. ConvertToLnk = TRUE;
  558. ExtraData.QuickEdit = _ttoi (eOpProp.Property);
  559. }
  560. if (StringIMatch (eOpProp.PropertyName, MEMDB_CATEGORY_LINKEDIT_FONTNAME)) {
  561. ConvertToLnk = TRUE;
  562. StringCopy (ExtraData.FontName, eOpProp.Property);
  563. }
  564. if (StringIMatch (eOpProp.PropertyName, MEMDB_CATEGORY_LINKEDIT_XFONTSIZE)) {
  565. ConvertToLnk = TRUE;
  566. ExtraData.xFontSize = _ttoi (eOpProp.Property);
  567. }
  568. if (StringIMatch (eOpProp.PropertyName, MEMDB_CATEGORY_LINKEDIT_YFONTSIZE)) {
  569. ConvertToLnk = TRUE;
  570. ExtraData.yFontSize = _ttoi (eOpProp.Property);
  571. }
  572. if (StringIMatch (eOpProp.PropertyName, MEMDB_CATEGORY_LINKEDIT_FONTWEIGHT)) {
  573. ConvertToLnk = TRUE;
  574. ExtraData.FontWeight = _ttoi (eOpProp.Property);
  575. }
  576. if (StringIMatch (eOpProp.PropertyName, MEMDB_CATEGORY_LINKEDIT_FONTFAMILY)) {
  577. ConvertToLnk = TRUE;
  578. ExtraData.FontFamily = _ttoi (eOpProp.Property);
  579. }
  580. if (StringIMatch (eOpProp.PropertyName, MEMDB_CATEGORY_LINKEDIT_CODEPAGE)) {
  581. ConvertToLnk = TRUE;
  582. ExtraData.CurrentCodePage = (WORD)_ttoi (eOpProp.Property);
  583. }
  584. if (StringIMatch (eOpProp.PropertyName, MEMDB_CATEGORY_LINKEDIT_SHOWNORMAL)) {
  585. ConvertToLnk = TRUE;
  586. forceToShowNormal = TRUE;
  587. }
  588. } while (EnumNextFileOpProperty (&eOpProp));
  589. }
  590. NewLinkPath = GetPathStringOnNt (eOp.Path);
  591. DEBUGMSG ((DBG_VERBOSE, "Editing shell link %s", NewLinkPath));
  592. if (!ModifyShellLink(
  593. NewLinkPath,
  594. NewTarget,
  595. NewArgs,
  596. NewWorkDir,
  597. NewIconPath,
  598. NewIconNr,
  599. ConvertToLnk,
  600. &ExtraData,
  601. forceToShowNormal
  602. )) {
  603. LOG ((LOG_ERROR, "Shell Link %s could not be modified", eOp.Path));
  604. }
  605. FreePathString (NewLinkPath);
  606. } while (EnumNextPathInOperation (&eOp));
  607. }
  608. if (EnumFirstPathInOperation (&eOp, OPERATION_LINK_STUB)) {
  609. pInitLnkStubData ();
  610. do {
  611. NewTarget = NULL;
  612. NewArgs = NULL;
  613. NewWorkDir = NULL;
  614. NewIconPath = NULL;
  615. NewIconNr = 0;
  616. Sequencer = 0;
  617. Announcement = 0;
  618. Availability = 0;
  619. ShowMode = SW_NORMAL;
  620. if (EnumFirstFileOpProperty (&eOpProp, eOp.Sequencer, OPERATION_LINK_STUB)) {
  621. do {
  622. if (StringIMatch (eOpProp.PropertyName, MEMDB_CATEGORY_LINKSTUB_TARGET)) {
  623. NewTarget = DuplicatePathString (eOpProp.Property, 0);
  624. }
  625. if (StringIMatch (eOpProp.PropertyName, MEMDB_CATEGORY_LINKSTUB_ARGS)) {
  626. StringCopyTcharCount (tempArgs, eOpProp.Property, ARRAYSIZE(tempArgs));
  627. C_Result = ConvertWin9xPath (tempArgs);
  628. NewArgs = DuplicatePathString (tempArgs, 0);
  629. }
  630. if (StringIMatch (eOpProp.PropertyName, MEMDB_CATEGORY_LINKSTUB_WORKDIR)) {
  631. NewWorkDir = DuplicatePathString (eOpProp.Property, 0);
  632. }
  633. if (StringIMatch (eOpProp.PropertyName, MEMDB_CATEGORY_LINKSTUB_ICONPATH)) {
  634. NewIconPath = DuplicatePathString (eOpProp.Property, 0);
  635. }
  636. if (StringIMatch (eOpProp.PropertyName, MEMDB_CATEGORY_LINKSTUB_ICONNUMBER)) {
  637. NewIconNr = _tcstoul (eOpProp.Property, NULL, 16);
  638. }
  639. if (StringIMatch (eOpProp.PropertyName, MEMDB_CATEGORY_LINKSTUB_SEQUENCER)) {
  640. Sequencer = _tcstoul (eOpProp.Property, NULL, 16);
  641. }
  642. if (StringIMatch (eOpProp.PropertyName, MEMDB_CATEGORY_LINKSTUB_ANNOUNCEMENT)) {
  643. Announcement = _tcstoul (eOpProp.Property, NULL, 16);
  644. }
  645. if (StringIMatch (eOpProp.PropertyName, MEMDB_CATEGORY_LINKSTUB_REPORTAVAIL)) {
  646. Availability = _tcstoul (eOpProp.Property, NULL, 16);
  647. }
  648. if (StringIMatch (eOpProp.PropertyName, MEMDB_CATEGORY_LINKSTUB_REQFILE)) {
  649. MultiSzAppend (&reqFilesList, eOpProp.Property);
  650. }
  651. if (StringIMatch (eOpProp.PropertyName, MEMDB_CATEGORY_LINKSTUB_SHOWMODE)) {
  652. ShowMode = _tcstoul (eOpProp.Property, NULL, 16);
  653. }
  654. } while (EnumNextFileOpProperty (&eOpProp));
  655. }
  656. NewLinkPath = GetPathStringOnNt (eOp.Path);
  657. pWriteLnkStubData (
  658. NewLinkPath,
  659. NewTarget,
  660. NewArgs,
  661. NewWorkDir,
  662. NewIconPath,
  663. NewIconNr,
  664. ShowMode,
  665. Sequencer,
  666. Announcement,
  667. Availability,
  668. &reqFilesList
  669. );
  670. FreeGrowBuffer (&reqFilesList);
  671. } while (EnumNextPathInOperation (&eOp));
  672. pDoneLnkStubData ();
  673. }
  674. return TRUE;
  675. }
  676. PCTSTR
  677. pGetFileNameFromPath (
  678. PCTSTR FileSpec
  679. )
  680. {
  681. PCTSTR p;
  682. p = _tcsrchr (FileSpec, TEXT('\\'));
  683. if (p) {
  684. p = _tcsinc (p);
  685. } else {
  686. p = _tcsrchr (FileSpec, TEXT(':'));
  687. if (p) {
  688. p = _tcsinc (p);
  689. }
  690. }
  691. if (!p) {
  692. p = FileSpec;
  693. }
  694. return p;
  695. }
  696. BOOL
  697. DoFileDel (
  698. VOID
  699. )
  700. /*++
  701. Routine Description:
  702. DoFileDel deletes all files marked to be deleted by us (not by an external
  703. module).
  704. Arguments:
  705. none
  706. Return Value:
  707. TRUE if the delete operation succeeded, or FALSE if an error occurred.
  708. Call GetLastError() for error code.
  709. --*/
  710. {
  711. FILEOP_ENUM e;
  712. HKEY Key;
  713. PDWORD ValuePtr;
  714. BOOL DoDelete;
  715. PCTSTR SharedFileName;
  716. DWORD attr;
  717. PCTSTR disableName;
  718. PCTSTR newLocation;
  719. GROWLIST disableList = GROWLIST_INIT;
  720. PCTSTR srcPath;
  721. UINT count;
  722. UINT u;
  723. //
  724. // Enumerate each file in filedel. This is used for cleanup purposes, not
  725. // for migration purposes. It is called just before syssetup.dll
  726. // terminates.
  727. //
  728. if (EnumFirstPathInOperation (&e, OPERATION_CLEANUP)) {
  729. do {
  730. //
  731. // Check registry for use count
  732. //
  733. DoDelete = TRUE;
  734. Key = OpenRegKeyStr (S_REG_SHARED_DLLS);
  735. if (Key) {
  736. //
  737. // Test SharedDlls for full path, then file name only
  738. //
  739. SharedFileName = e.Path;
  740. ValuePtr = (PDWORD) GetRegValueDataOfType (Key, e.Path, REG_DWORD);
  741. if (!ValuePtr) {
  742. SharedFileName = pGetFileNameFromPath (e.Path);
  743. ValuePtr = (PDWORD) GetRegValueDataOfType (
  744. Key,
  745. SharedFileName,
  746. REG_DWORD
  747. );
  748. }
  749. //
  750. // Match found. Is use count reasonable and greater than one?
  751. //
  752. if (ValuePtr) {
  753. if (*ValuePtr < 0x10000 && *ValuePtr > 1) {
  754. *ValuePtr -= 1;
  755. RegSetValueEx (
  756. Key,
  757. SharedFileName,
  758. 0,
  759. REG_DWORD,
  760. (PBYTE) ValuePtr,
  761. sizeof (DWORD)
  762. );
  763. DEBUGMSG ((
  764. DBG_FILEMIG,
  765. "%s not deleted; share count decremented to %u",
  766. SharedFileName,
  767. *ValuePtr
  768. ));
  769. } else {
  770. RegDeleteValue (Key, SharedFileName);
  771. }
  772. DoDelete = FALSE;
  773. MemFree (g_hHeap, 0, ValuePtr);
  774. }
  775. CloseRegKey (Key);
  776. }
  777. if (DoDelete) {
  778. attr = GetLongPathAttributes (e.Path);
  779. if (attr != INVALID_ATTRIBUTES) {
  780. DEBUGMSG ((DBG_FILEMIG, "Deleting %s", e.Path));
  781. if (GetLongPathAttributes (e.Path) & FILE_ATTRIBUTE_DIRECTORY) {
  782. SetLongPathAttributes (e.Path, FILE_ATTRIBUTE_DIRECTORY);
  783. DEBUGMSG ((DBG_FILEMIG, "Removing %s", e.Path));
  784. DeleteDirectoryContents (e.Path);
  785. if (!SetLongPathAttributes (e.Path, FILE_ATTRIBUTE_NORMAL) ||
  786. !RemoveLongDirectoryPath (e.Path)
  787. ) {
  788. LOG ((LOG_ERROR, "RemoveDirectory failed for %s", e.Path));
  789. }
  790. } else {
  791. DEBUGMSG ((DBG_FILEMIG, "Deleting %s", e.Path));
  792. if (!SetLongPathAttributes (e.Path, FILE_ATTRIBUTE_NORMAL) ||
  793. !DeleteLongPath (e.Path)
  794. ) {
  795. LOG ((LOG_ERROR, "DeleteFile failed for %s", e.Path));
  796. }
  797. }
  798. DEBUGMSG ((DBG_FILEMIG, "Done deleting %s", e.Path));
  799. }
  800. }
  801. } while (EnumNextPathInOperation (&e));
  802. }
  803. SetLastError (ERROR_SUCCESS);
  804. return TRUE;
  805. }
  806. INT
  807. CALLBACK
  808. pRemoveEmptyDirsProc (
  809. PCTSTR FullFileSpec,
  810. PCTSTR DontCare,
  811. WIN32_FIND_DATA *FindDataPtr,
  812. DWORD EnumTreeID,
  813. PVOID Param,
  814. PDWORD CurrentDirData
  815. )
  816. /*++
  817. Routine Description:
  818. pRemoveEmptyDirsProc is called for every directory in the tree being
  819. enumerated (see pRemoveEmptyDirsInTree below). This enum proc calls
  820. RemoveLongDirectoryPath, regardless if files exist in it or not.
  821. RemoveLongDirectoryPath will fail if it is not empty.
  822. Arguments:
  823. FullFileSpec - The Win32 path and directory name of the item being enumerated
  824. FindDataPtr - A pointer to the WIN32_FIND_DATA structure for the item
  825. EnumTreeID - Unused
  826. Param - A BOOL indicating FALSE if we should only remove empty dirs that we
  827. deleted something from, or TRUE if we should delete the empty
  828. dir in any case.
  829. Return Value:
  830. TRUE if the delete operation succeeded, or FALSE if an error occurred.
  831. Call GetLastError() for error code.
  832. --*/
  833. {
  834. if ((FindDataPtr->dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) == 0) {
  835. return CALLBACK_CONTINUE;
  836. }
  837. //
  838. // Did we delete any files from this directory?
  839. //
  840. if (!Param) {
  841. if (!TestPathsForOperations (FullFileSpec, ALL_DELETE_OPERATIONS)) {
  842. DEBUGMSG ((DBG_NAUSEA, "We did not delete anything from %s", FullFileSpec));
  843. return CALLBACK_CONTINUE;
  844. }
  845. if (IsDirectoryMarkedAsEmpty (FullFileSpec)) {
  846. DEBUGMSG ((DBG_NAUSEA, "This directory was empty to begin with: %s", FullFileSpec));
  847. return CALLBACK_CONTINUE;
  848. }
  849. }
  850. //
  851. // Yes, delete the directory. If it is not empty, RemoveLongDirectoryPath will fail.
  852. //
  853. DEBUGMSG ((DBG_NAUSEA, "Trying to remove empty directory %s", FullFileSpec));
  854. if (!SetLongPathAttributes (FullFileSpec, FILE_ATTRIBUTE_DIRECTORY)) {
  855. return CALLBACK_CONTINUE;
  856. }
  857. if (RemoveLongDirectoryPath (FullFileSpec)) {
  858. DEBUGMSG ((DBG_NAUSEA, "%s was removed", FullFileSpec));
  859. }
  860. else {
  861. DEBUGMSG ((DBG_NAUSEA, "%s was not removed", FullFileSpec));
  862. SetLongPathAttributes (FullFileSpec, FindDataPtr->dwFileAttributes);
  863. }
  864. return CALLBACK_CONTINUE;
  865. }
  866. BOOL
  867. pRemoveEmptyDirsInTree (
  868. PCTSTR TreePath,
  869. BOOL CleanAll
  870. )
  871. /*++
  872. Routine Description:
  873. pRemoveEmptyDirsInTree calls EnumerateTree to scan all directories in
  874. TreePath, deleting those that are empty.
  875. Arguments:
  876. TreePath - A full path to the root of the tree to enumerate. The path
  877. must not have any wildcards.
  878. CleanAll - Specifies TRUE if the empty dir should be cleaned in all cases,
  879. or FALSE if it should be cleaned only if modified by a delete
  880. operation.
  881. Return Value:
  882. TRUE if the delete operation succeeded, or FALSE if an error occurred.
  883. Call GetLastError() for error code.
  884. --*/
  885. {
  886. BOOL b;
  887. b = EnumerateTree (
  888. TreePath, // Starting path
  889. pRemoveEmptyDirsProc, // Enumeration Proc
  890. NULL, // Error-logging proc
  891. 0, // MemDb exclusion node--not used
  892. (PVOID) CleanAll, // EnumProc param
  893. ENUM_ALL_LEVELS, // Level
  894. NULL, // exclusion INF file--not used
  895. FILTER_DIRECTORIES|FILTER_DIRS_LAST // Attributes filter
  896. );
  897. if (!b) {
  898. LOG ((LOG_ERROR, "pRemoveEmptyDirsInTree: EnumerateTree failed"));
  899. }
  900. return b;
  901. }
  902. BOOL
  903. RemoveEmptyDirs (
  904. VOID
  905. )
  906. /*++
  907. Routine Description:
  908. RemoveEmptyDirs sweeps through the directories in CleanUpDirs and blows away
  909. any subdirectory that has no files.
  910. Arguments:
  911. none
  912. Return Value:
  913. Always TRUE.
  914. --*/
  915. {
  916. MEMDB_ENUM e;
  917. if (MemDbGetValueEx (&e, MEMDB_CATEGORY_CLEAN_UP_DIR, NULL, NULL)) {
  918. do {
  919. pRemoveEmptyDirsInTree (e.szName, e.dwValue);
  920. } while (MemDbEnumNextValue (&e));
  921. }
  922. return TRUE;
  923. }
  924. VOID
  925. pFixSelfRelativePtr (
  926. PTOKENSET Base,
  927. PCVOID *Ptr
  928. )
  929. {
  930. if (*Ptr != NULL) {
  931. *Ptr = (PBYTE) *Ptr - TOKEN_BASE_OFFSET + (UINT) Base +
  932. sizeof (TOKENSET) + (Base->ArgCount * sizeof (TOKENARG));
  933. }
  934. }
  935. BOOL
  936. pFileSearchAndReplaceA (
  937. IN PCSTR FilePath,
  938. IN OUT PTOKENSET TokenSet
  939. )
  940. /*++
  941. Routine Description:
  942. pFileSearchAndReplace does all the initialization work necessary to update
  943. the contents of a file. It also converts a self-relative token set into an
  944. absolute token set. That means the offsets in the struct are converted to
  945. pointers. After everything is prepared, pFileSearchAndReplaceWorker is
  946. called to modify the file.
  947. Arguments:
  948. FilePath - Specifies the file to process
  949. TokenSet - Specifies the token set to apply to FilePath. Receives its
  950. pointers updated, if necessary.
  951. Return Value:
  952. TRUE if the file was successfully updated. FALSE otherwise.
  953. --*/
  954. {
  955. HANDLE InFile = INVALID_HANDLE_VALUE;
  956. HANDLE OutFile = INVALID_HANDLE_VALUE;
  957. CHAR TempDir[MAX_MBCHAR_PATH];
  958. CHAR TempPath[MAX_MBCHAR_PATH];
  959. PBYTE MapStart = NULL;
  960. PBYTE MapEnd;
  961. DWORD Attribs;
  962. HANDLE Map = NULL;
  963. BOOL b = FALSE;
  964. UINT u;
  965. __try {
  966. //
  967. // Detect a TokenSet struct that needs its offsets fixed
  968. //
  969. if (TokenSet->SelfRelative) {
  970. pFixSelfRelativePtr (TokenSet, &TokenSet->CharsToIgnore);
  971. for (u = 0 ; u < TokenSet->ArgCount ; u++) {
  972. pFixSelfRelativePtr (TokenSet, &TokenSet->Args[u].DetectPattern);
  973. pFixSelfRelativePtr (TokenSet, &TokenSet->Args[u].SearchList);
  974. pFixSelfRelativePtr (TokenSet, &TokenSet->Args[u].ReplaceWith);
  975. }
  976. TokenSet->SelfRelative = FALSE;
  977. }
  978. DEBUGMSG ((DBG_VERBOSE, "URL mode: %s", TokenSet->UrlMode ? TEXT("YES") : TEXT ("NO")));
  979. //
  980. // Save original attributes
  981. //
  982. Attribs = GetFileAttributesA (FilePath);
  983. if (Attribs == INVALID_ATTRIBUTES) {
  984. DEBUGMSGA ((DBG_ERROR, "Can't get attributes of %s", FilePath));
  985. __leave;
  986. }
  987. //
  988. // Open the source file
  989. //
  990. InFile = CreateFileA (
  991. FilePath,
  992. GENERIC_READ,
  993. 0,
  994. NULL,
  995. OPEN_EXISTING,
  996. FILE_ATTRIBUTE_NORMAL,
  997. NULL
  998. );
  999. if (InFile == INVALID_HANDLE_VALUE) {
  1000. DEBUGMSGA ((DBG_ERROR, "Can't open %s", FilePath));
  1001. __leave;
  1002. }
  1003. //
  1004. // Get a destination file name
  1005. //
  1006. GetTempPathA (ARRAYSIZE(TempDir), TempDir);
  1007. GetTempFileNameA (TempDir, "xx$", 0, TempPath);
  1008. OutFile = CreateFileA (
  1009. TempPath,
  1010. GENERIC_WRITE,
  1011. 0,
  1012. NULL,
  1013. CREATE_ALWAYS,
  1014. FILE_ATTRIBUTE_NORMAL,
  1015. NULL
  1016. );
  1017. if (OutFile == INVALID_HANDLE_VALUE) {
  1018. DEBUGMSGA ((DBG_ERROR, "Can't create %s", TempPath));
  1019. __leave;
  1020. }
  1021. //
  1022. // Create file mapping
  1023. //
  1024. Map = CreateFileMapping (
  1025. InFile,
  1026. NULL,
  1027. PAGE_READONLY,
  1028. 0,
  1029. 0,
  1030. NULL
  1031. );
  1032. if (!Map) {
  1033. DEBUGMSGA ((DBG_ERROR, "Can't create file mapping for %s", FilePath));
  1034. __leave;
  1035. }
  1036. //
  1037. // Map a view of the source file
  1038. //
  1039. MapStart = MapViewOfFile (Map, FILE_MAP_READ, 0, 0, 0);
  1040. if (!MapStart) {
  1041. DEBUGMSGA ((DBG_ERROR, "Can't map view of file for %s", FilePath));
  1042. __leave;
  1043. }
  1044. MapEnd = MapStart + GetFileSize (InFile, NULL);
  1045. //
  1046. // Now do the search and replace
  1047. //
  1048. if (!pFileSearchAndReplaceWorker (
  1049. MapStart,
  1050. MapEnd,
  1051. OutFile,
  1052. TokenSet
  1053. )) {
  1054. __leave;
  1055. }
  1056. //
  1057. // Close the handles
  1058. //
  1059. UnmapViewOfFile (MapStart);
  1060. CloseHandle (Map);
  1061. CloseHandle (OutFile);
  1062. CloseHandle (InFile);
  1063. MapStart = NULL;
  1064. Map = NULL;
  1065. OutFile = INVALID_HANDLE_VALUE;
  1066. InFile = INVALID_HANDLE_VALUE;
  1067. //
  1068. // Remove the original file, and replace it with the new copy
  1069. //
  1070. SetFileAttributesA (FilePath, FILE_ATTRIBUTE_NORMAL);
  1071. //
  1072. // MOVEFILE_REPLACE_EXISTING does not work with non-normal attributes
  1073. //
  1074. if (!OurMoveFileExA (TempPath, FilePath, MOVEFILE_COPY_ALLOWED|MOVEFILE_REPLACE_EXISTING)) {
  1075. DEBUGMSGA ((DBG_ERROR, "Can't move %s to %s", TempPath, FilePath));
  1076. __leave;
  1077. }
  1078. if (!SetFileAttributesA (FilePath, Attribs)) {
  1079. DEBUGMSGA ((DBG_WARNING, "Can't set attributes on %s", FilePath));
  1080. }
  1081. b = TRUE;
  1082. }
  1083. __finally {
  1084. if (MapStart) {
  1085. UnmapViewOfFile (MapStart);
  1086. }
  1087. if (Map) {
  1088. CloseHandle (Map);
  1089. }
  1090. if (OutFile != INVALID_HANDLE_VALUE) {
  1091. CloseHandle (OutFile);
  1092. DeleteFileA (TempPath);
  1093. }
  1094. if (InFile != INVALID_HANDLE_VALUE) {
  1095. CloseHandle (InFile);
  1096. }
  1097. }
  1098. return b;
  1099. }
  1100. VOID
  1101. pConvertUrlToText (
  1102. IN PCSTR Source,
  1103. OUT PSTR Buffer // caller must ensure buffer is able to hold the entire Source
  1104. )
  1105. {
  1106. PSTR dest;
  1107. PCSTR src;
  1108. src = Source;
  1109. dest = Buffer;
  1110. while (*src) {
  1111. if (*src == '%' && GetHexDigit(src[1]) != -1 && GetHexDigit(src[2]) != -1) {
  1112. *dest++ = GetHexDigit(src[1]) << 4 | GetHexDigit(src[2]);
  1113. src += 3;
  1114. } else {
  1115. *dest++ = *src++;
  1116. }
  1117. }
  1118. *dest = 0;
  1119. }
  1120. CHAR
  1121. pMakeHex (
  1122. IN UINT Digit
  1123. )
  1124. {
  1125. MYASSERT (Digit < 16);
  1126. if (Digit < 10) {
  1127. Digit += '0';
  1128. } else {
  1129. Digit += 'A' - 10;
  1130. }
  1131. return (CHAR) Digit;
  1132. }
  1133. UINT
  1134. pConvertTextToUrl (
  1135. IN PCSTR Text,
  1136. OUT PSTR Buffer,
  1137. IN UINT BufferTchars
  1138. )
  1139. {
  1140. PSTR dest;
  1141. PCSTR src;
  1142. PSTR maxDest;
  1143. PCSTR unsafeChars = "<>\"#{}|^~[]'";
  1144. UINT result = 0;
  1145. src = Text;
  1146. dest = Buffer;
  1147. maxDest = Buffer + BufferTchars - 1;
  1148. while (*src && dest < maxDest) {
  1149. if (*src < 0x21 || *src > 0x7e || strchr (unsafeChars, *src)) {
  1150. if (dest + 3 >= maxDest) {
  1151. break;
  1152. }
  1153. *dest++ = '%';
  1154. *dest++ = pMakeHex (((UINT) (*src)) >> 4);
  1155. *dest++ = pMakeHex (((UINT) (*src)) & 0x0F);
  1156. src++;
  1157. } else if (*src == '\\') {
  1158. *dest++ = '/';
  1159. src++;
  1160. } else {
  1161. *dest++ = *src++;
  1162. }
  1163. }
  1164. if (dest <= maxDest) {
  1165. *dest++ = 0;
  1166. result = dest - Buffer;
  1167. } else if (BufferTchars) {
  1168. *maxDest = 0;
  1169. }
  1170. return result;
  1171. }
  1172. BOOL
  1173. pFileSearchAndReplaceWorker (
  1174. IN PBYTE MapStart,
  1175. IN PBYTE MapEnd,
  1176. IN HANDLE OutFile,
  1177. IN PTOKENSET TokenSet
  1178. )
  1179. /*++
  1180. Routine Description:
  1181. pFileSearchAndReplaceWorker implements a general search and replace
  1182. mechanism. It parses a memory mapped file, and writes it to a destination
  1183. file, updating it as necessary.
  1184. After parsing a line, this function strips out the characters to be
  1185. ignored (if any), and then tests the line against each detection
  1186. pattern. If a detection pattern is matched, then the search/replace
  1187. pair(s) are processed, and the paths are updated if specified.
  1188. Arguments:
  1189. MapStart - Specifies the first byte of the memory mapped file
  1190. MapEnd - Specifies one byte after the end of the memory mapped file
  1191. OutFile - Specifies a handle to a file that is open for writing
  1192. TokenSet - Specifies the set of tokens to process. This includes global
  1193. settings, and detect/search/replace sets.
  1194. Return Value:
  1195. TRUE if the function successfully processed the file, FALSE otherwise.
  1196. --*/
  1197. {
  1198. PBYTE Start;
  1199. PBYTE End;
  1200. PBYTE Eol;
  1201. BOOL b = FALSE;
  1202. GROWBUFFER Buf = GROWBUF_INIT;
  1203. GROWBUFFER Dest = GROWBUF_INIT;
  1204. GROWBUFFER quoteless = GROWBUF_INIT;
  1205. GROWBUFFER SpcList = GROWBUF_INIT;
  1206. UINT u;
  1207. UINT Count;
  1208. PSTR p;
  1209. PCSTR q;
  1210. PCSTR SrcBuf;
  1211. BOOL Detected;
  1212. PTOKENARG Arg;
  1213. MULTISZ_ENUMA e;
  1214. PCSTR NewStr;
  1215. PCSTR ReplaceStr;
  1216. PCSTR *Element;
  1217. PSTR EndStr;
  1218. DWORD Status;
  1219. CHAR NewPath[MAX_MBCHAR_PATH];
  1220. UINT Len;
  1221. PBYTE Output;
  1222. UINT OutputBytes;
  1223. DWORD DontCare;
  1224. MBCHAR ch;
  1225. INT i;
  1226. UINT reservedTchars;
  1227. PSTR reservedDest;
  1228. UINT removedDblQuotes;
  1229. PCSTR initialPos;
  1230. UINT inQuotes;
  1231. //
  1232. // Initialize the structure
  1233. //
  1234. for (u = 0 ; u < TokenSet->ArgCount ; u++) {
  1235. Arg = &TokenSet->Args[u];
  1236. Arg->DetectPatternStruct = NULL;
  1237. }
  1238. __try {
  1239. //
  1240. // Parse the detect patterns
  1241. //
  1242. for (u = 0 ; u < TokenSet->ArgCount ; u++) {
  1243. Arg = &TokenSet->Args[u];
  1244. Arg->DetectPatternStruct = CreateParsedPatternA (
  1245. Arg->DetectPattern
  1246. );
  1247. if (!Arg->DetectPatternStruct) {
  1248. DEBUGMSGA ((DBG_ERROR, "File pattern syntax error: %s", Arg->DetectPattern));
  1249. __leave;
  1250. }
  1251. }
  1252. //
  1253. // Identify each line, and then parse the line
  1254. //
  1255. Start = MapStart;
  1256. while (Start < MapEnd) {
  1257. //
  1258. // Find the line
  1259. //
  1260. End = Start;
  1261. while (End < MapEnd && *End && *End != '\r' && *End != '\n') {
  1262. End++;
  1263. }
  1264. Eol = End;
  1265. if (End < MapEnd && *End == '\r') {
  1266. while (End < MapEnd && *End == '\r') {
  1267. End++;
  1268. }
  1269. }
  1270. if (End < MapEnd && *End == '\n') {
  1271. End++;
  1272. }
  1273. if (End > Start) {
  1274. //
  1275. // OK we now have a line. Copy it into Buf, removing
  1276. // the characters we don't care about.
  1277. //
  1278. Buf.End = 0;
  1279. Dest.End = 0;
  1280. Detected = FALSE;
  1281. p = (PSTR) GrowBuffer (&Buf, Eol - Start + sizeof (CHAR));
  1282. if (TokenSet->CharsToIgnore) {
  1283. q = Start;
  1284. while (q < End) {
  1285. if (!_mbschr (TokenSet->CharsToIgnore, _mbsnextc (q))) {
  1286. _copymbchar (p, q);
  1287. p = _mbsinc (p);
  1288. }
  1289. q = _mbsinc (q);
  1290. }
  1291. *p = 0;
  1292. for (u = 0 ; u < TokenSet->ArgCount ; u++) {
  1293. Arg = &TokenSet->Args[u];
  1294. Detected = TestParsedPatternA (
  1295. Arg->DetectPatternStruct,
  1296. (PCSTR) Buf.Buf
  1297. );
  1298. if (Detected) {
  1299. break;
  1300. }
  1301. }
  1302. } else {
  1303. for (u = 0 ; u < TokenSet->ArgCount ; u++) {
  1304. Arg = &TokenSet->Args[u];
  1305. Detected = TestParsedPatternABA (
  1306. Arg->DetectPatternStruct,
  1307. (PCSTR) Start,
  1308. (PCSTR) Eol
  1309. );
  1310. if (Detected) {
  1311. break;
  1312. }
  1313. }
  1314. }
  1315. if (Detected) {
  1316. //
  1317. // Copy the line into a work buffer
  1318. //
  1319. Buf.End = 0;
  1320. p = (PSTR) GrowBuffer (&Buf, (End - Start + 1) * sizeof (CHAR));
  1321. StringCopyABA (p, (PCSTR) Start, (PCSTR) End);
  1322. Output = Buf.Buf;
  1323. OutputBytes = Buf.End - sizeof (CHAR);
  1324. DEBUGMSGA ((DBG_NAUSEA, "Copied line to work buffer: %s", p));
  1325. //
  1326. // Perform search and replace on the line
  1327. //
  1328. if (Arg->SearchList) {
  1329. ReplaceStr = Arg->ReplaceWith;
  1330. if (EnumFirstMultiSzA (&e, Arg->SearchList)) {
  1331. do {
  1332. NewStr = StringSearchAndReplaceA (
  1333. (PCSTR) Buf.Buf,
  1334. e.CurrentString,
  1335. ReplaceStr
  1336. );
  1337. if (NewStr) {
  1338. Buf.End = 0;
  1339. GrowBufCopyStringA (&Buf, NewStr);
  1340. FreePathStringA (NewStr);
  1341. OutputBytes = Buf.End - sizeof (CHAR);
  1342. }
  1343. ReplaceStr = GetEndOfStringA (ReplaceStr) + 1;
  1344. } while (EnumNextMultiSzA (&e));
  1345. }
  1346. }
  1347. //
  1348. // Perform path update
  1349. //
  1350. if (Arg->UpdatePath) {
  1351. DEBUGMSG ((DBG_NAUSEA, "Updating path"));
  1352. Dest.End = 0;
  1353. SrcBuf = (PCSTR) Buf.Buf;
  1354. inQuotes = 0;
  1355. while (*SrcBuf) {
  1356. if ((SrcBuf[1] == ':' && (SrcBuf[2] == '\\' || SrcBuf[2] == '/')) &&
  1357. (SrcBuf[3] != '/' && SrcBuf[3] != '\\')
  1358. ) {
  1359. quoteless.End = 0;
  1360. GrowBuffer (&quoteless, SizeOfStringA (SrcBuf));
  1361. //
  1362. // Convert from URL to file system char set
  1363. //
  1364. if (TokenSet->UrlMode) {
  1365. DEBUGMSGA ((DBG_NAUSEA, "URL conversion input: %s", SrcBuf));
  1366. pConvertUrlToText (SrcBuf, (PSTR) quoteless.Buf);
  1367. q = (PCSTR) quoteless.Buf;
  1368. DEBUGMSGA ((DBG_NAUSEA, "URL conversion result: %s", q));
  1369. } else {
  1370. q = SrcBuf;
  1371. }
  1372. //
  1373. // Remove all dbl quotes from buffer, flip
  1374. // forward slashes into backslashes, stop at
  1375. // first non-file system character
  1376. // or at the first quote if the text
  1377. // is between quotes already
  1378. //
  1379. p = (PSTR) quoteless.Buf;
  1380. initialPos = q;
  1381. DEBUGMSGA ((DBG_NAUSEA, "CMD line cleanup input: %s", q));
  1382. removedDblQuotes = 0;
  1383. while (*q) {
  1384. ch = _mbsnextc (q);
  1385. if (ch == ':' || ch == '|' || ch == '?' || ch == '*' || ch == '<' || ch == '>') {
  1386. if (q != &initialPos[1]) {
  1387. break;
  1388. }
  1389. }
  1390. if (ch != '\"') {
  1391. if (ch != '/') {
  1392. if (IsLeadByte (*q) && q[1]) {
  1393. *p++ = *q++;
  1394. }
  1395. *p++ = *q++;
  1396. } else {
  1397. *p++ = '\\';
  1398. q++;
  1399. }
  1400. } else {
  1401. //
  1402. // check parser's status
  1403. //
  1404. if (inQuotes & 1) {
  1405. //
  1406. // done with the filename
  1407. //
  1408. break;
  1409. }
  1410. q++;
  1411. removedDblQuotes++;
  1412. }
  1413. }
  1414. *p = 0;
  1415. DEBUGMSGA ((DBG_NAUSEA, "CMD line cleanup result: %s", quoteless.Buf));
  1416. //
  1417. // Build a list of spaces
  1418. //
  1419. SpcList.End = 0;
  1420. initialPos = (PCSTR) quoteless.Buf;
  1421. q = quoteless.Buf + 2;
  1422. EndStr = p;
  1423. while (q < EndStr) {
  1424. ch = _mbsnextc (q);
  1425. if (isspace (ch)) {
  1426. Element = (PCSTR *) GrowBuffer (&SpcList, sizeof (PCSTR));
  1427. *Element = q;
  1428. while (q + 1 < EndStr && isspace (_mbsnextc (q + 1))) {
  1429. q++;
  1430. }
  1431. }
  1432. q = _mbsinc (q);
  1433. }
  1434. if (q == EndStr || !SpcList.End) {
  1435. Element = (PCSTR *) GrowBuffer (&SpcList, sizeof (PCSTR));
  1436. *Element = EndStr;
  1437. }
  1438. //
  1439. // Test all paths by using the longest possibility first,
  1440. // and then by truncating the path at the spaces.
  1441. //
  1442. Count = SpcList.End / sizeof (PCSTR);
  1443. MYASSERT (Count > 0);
  1444. Element = (PCSTR *) SpcList.Buf;
  1445. for (i = Count - 1 ; i >= 0 ; i--) {
  1446. p = (PSTR) (Element[i]);
  1447. ch = *p;
  1448. *p = 0;
  1449. DEBUGMSGA ((DBG_NAUSEA, "Testing path: %s", initialPos));
  1450. Status = GetFileInfoOnNtA (initialPos, NewPath, MAX_MBCHAR_PATH);
  1451. DEBUGMSGA ((DBG_NAUSEA, "Results: %x/%s", Status, NewPath));
  1452. *p = (CHAR)ch;
  1453. if (Status != FILESTATUS_UNCHANGED && Status != FILESTATUS_BACKUP) {
  1454. break;
  1455. }
  1456. }
  1457. *EndStr = 0;
  1458. //
  1459. // If there is a new path, update the destination
  1460. //
  1461. if (Status != FILESTATUS_UNCHANGED && Status != FILESTATUS_BACKUP) {
  1462. if (TokenSet->UrlMode) {
  1463. reservedTchars = (TcharCountA (NewPath) * 3) + 1;
  1464. reservedDest = GrowBufferReserve (&Dest, reservedTchars * sizeof (CHAR));
  1465. Dest.End += pConvertTextToUrl (NewPath, reservedDest, reservedTchars) / sizeof (CHAR);
  1466. DEBUGMSGA ((DBG_NAUSEA, "URL conversion output: %s", reservedDest));
  1467. } else {
  1468. GrowBufAppendStringA (&Dest, NewPath);
  1469. }
  1470. SrcBuf += (Element[i] - initialPos) + removedDblQuotes;
  1471. Dest.End -= sizeof (CHAR);
  1472. } else {
  1473. //
  1474. // No changed path here; copy char by char
  1475. //
  1476. if (IsLeadByte (*SrcBuf) && SrcBuf[1]) {
  1477. Len = 2;
  1478. } else {
  1479. Len = 1;
  1480. }
  1481. p = GrowBuffer (&Dest, Len);
  1482. CopyMemory (p, SrcBuf, Len);
  1483. SrcBuf = (PCSTR) ((PBYTE) SrcBuf + Len);
  1484. }
  1485. } else {
  1486. //
  1487. // keep track of quotes
  1488. //
  1489. if (*SrcBuf == '\"') {
  1490. inQuotes++;
  1491. }
  1492. //
  1493. // This is not a path, copy the character to Dest
  1494. //
  1495. if (IsLeadByte (*SrcBuf) && SrcBuf[1]) {
  1496. Len = 2;
  1497. } else {
  1498. Len = 1;
  1499. }
  1500. p = GrowBuffer (&Dest, Len);
  1501. CopyMemory (p, SrcBuf, Len);
  1502. SrcBuf = (PCSTR) ((PBYTE) SrcBuf + Len);
  1503. }
  1504. }
  1505. Output = Dest.Buf;
  1506. OutputBytes = Dest.End;
  1507. }
  1508. } else {
  1509. //
  1510. // The line does not change
  1511. //
  1512. Output = Start;
  1513. OutputBytes = End - Start;
  1514. }
  1515. //
  1516. // Write the line
  1517. //
  1518. if (!WriteFile (OutFile, Output, OutputBytes, &DontCare, NULL)) {
  1519. DEBUGMSG ((DBG_ERROR, "File search/replace: Can't write to output file"));
  1520. __leave;
  1521. }
  1522. //
  1523. // Write a nul if it is found in the file
  1524. //
  1525. if (End < MapEnd && *End == 0) {
  1526. if (!WriteFile (OutFile, End, 1, &DontCare, NULL)) {
  1527. DEBUGMSG ((DBG_ERROR, "File search/replace: Can't write nul to output file"));
  1528. __leave;
  1529. }
  1530. End++;
  1531. }
  1532. } else if (End < MapEnd) {
  1533. DEBUGMSG ((DBG_WHOOPS, "Parse error in pFileSearchAndReplaceWorker"));
  1534. break;
  1535. }
  1536. Start = End;
  1537. }
  1538. b = TRUE;
  1539. }
  1540. __finally {
  1541. FreeGrowBuffer (&Buf);
  1542. FreeGrowBuffer (&Dest);
  1543. FreeGrowBuffer (&SpcList);
  1544. FreeGrowBuffer (&quoteless);
  1545. for (u = 0 ; u < TokenSet->ArgCount ; u++) {
  1546. Arg = &TokenSet->Args[u];
  1547. DestroyParsedPatternA (Arg->DetectPatternStruct);
  1548. }
  1549. }
  1550. return b;
  1551. }
  1552. BOOL
  1553. pIsOkToEdit (
  1554. IN PCSTR AnsiPath,
  1555. OUT PSTR NewPath OPTIONAL
  1556. )
  1557. /*++
  1558. Routine Description:
  1559. pIsOkToEdit checks an ansi file name to see if it is handled by a migration
  1560. DLL, or if it is deleted. If neither of those cases apply, the file can be
  1561. edited. Optionally the function returns the final path for the file.
  1562. Arguments:
  1563. AnsiPath - Specifies the path to test
  1564. NewPath - Receives the final path for the file, which may be the same as
  1565. AnsiPath, or may be different.
  1566. Return Value:
  1567. TRUE if the file can be edited, FALSE otherwise.
  1568. --*/
  1569. {
  1570. DWORD Status;
  1571. //
  1572. // Is this file marked as handled?
  1573. //
  1574. if (IsFileMarkedAsHandledA (AnsiPath)) {
  1575. return FALSE;
  1576. }
  1577. Status = GetFileInfoOnNtA (AnsiPath, NewPath, MEMDB_MAX);
  1578. return !(Status & FILESTATUS_DELETED);
  1579. }
  1580. BOOL
  1581. pProcessFileEdit (
  1582. VOID
  1583. )
  1584. /*++
  1585. Routine Description:
  1586. pProcessFileEdit enumerates all the files that can be edited, and calls
  1587. pFileSearchAndReplace for each, using the token sets created on the Win9x
  1588. side of setup.
  1589. Arguments:
  1590. None.
  1591. Return Value:
  1592. TRUE on success, FALSE on error.
  1593. --*/
  1594. {
  1595. MEMDB_ENUMA e;
  1596. PTOKENSET PathsOnlySet;
  1597. BOOL b = TRUE;
  1598. GROWBUFFER TokenSetCopy = GROWBUF_INIT;
  1599. PTOKENSET Buf;
  1600. CHAR NewPath[MEMDB_MAX];
  1601. DWORD Result;
  1602. Result = GetLastError();
  1603. //
  1604. // Create a set that will update the paths of any file
  1605. //
  1606. PathsOnlySet = (PTOKENSET) MemAlloc (g_hHeap, 0, sizeof (TOKENSET) + sizeof (TOKENARG));
  1607. PathsOnlySet->ArgCount = 1;
  1608. PathsOnlySet->CharsToIgnore = NULL;
  1609. PathsOnlySet->UrlMode = FALSE;
  1610. PathsOnlySet->SelfRelative = FALSE;
  1611. PathsOnlySet->Args[0].DetectPattern = "*";
  1612. PathsOnlySet->Args[0].SearchList = NULL;
  1613. PathsOnlySet->Args[0].ReplaceWith = NULL;
  1614. PathsOnlySet->Args[0].UpdatePath = TRUE;
  1615. if (MemDbGetValueExA (&e, MEMDB_CATEGORY_FILEEDITA, NULL, NULL)) {
  1616. do {
  1617. if (!pIsOkToEdit (e.szName, NewPath)) {
  1618. continue;
  1619. }
  1620. DEBUGMSGA ((DBG_VERBOSE, "Editing %s.", NewPath));
  1621. if (e.bBinary) {
  1622. TokenSetCopy.End = 0;
  1623. Buf = (PTOKENSET) GrowBuffer (&TokenSetCopy, e.BinarySize);
  1624. CopyMemory (Buf, e.BinaryPtr, e.BinarySize);
  1625. if (!pFileSearchAndReplaceA (NewPath, Buf)) {
  1626. DEBUGMSGA ((DBG_ERROR, "Could not edit %s", NewPath));
  1627. b = FALSE;
  1628. Result = GetLastError();
  1629. }
  1630. FreeGrowBuffer (&TokenSetCopy);
  1631. } else {
  1632. if (!pFileSearchAndReplaceA (NewPath, PathsOnlySet)) {
  1633. DEBUGMSGA ((DBG_ERROR, "Could not edit %s", NewPath));
  1634. b = FALSE;
  1635. Result = GetLastError();
  1636. }
  1637. }
  1638. } while (MemDbEnumNextValueA (&e));
  1639. }
  1640. MemFree (g_hHeap, 0, PathsOnlySet);
  1641. SetLastError (Result);
  1642. return b;
  1643. }
  1644. DWORD
  1645. DoFileEdit (
  1646. DWORD Request
  1647. )
  1648. /*++
  1649. Routine Description:
  1650. DoFileEdit is called by the progress bar manager to query ticks or do the
  1651. file editing. If querying ticks, then the function determines how many
  1652. files will be edited, and multiplies that by a constant to get the tick
  1653. size. Otherwise the function edits all the files queued for this operation.
  1654. Arguments:
  1655. Request - Specifies the request being made by the progress bar manager
  1656. Return Value:
  1657. If Request is REQUEST_QUERYTICKS, the return value indicates the number of
  1658. ticks. Otherwise, the return value is a Win32 result code.
  1659. --*/
  1660. {
  1661. MEMDB_ENUMA e;
  1662. UINT u;
  1663. if (Request == REQUEST_QUERYTICKS) {
  1664. u = 0;
  1665. if (MemDbGetValueExA (&e, MEMDB_CATEGORY_FILEEDITA, NULL, NULL)) {
  1666. do {
  1667. if (pIsOkToEdit (e.szName, NULL)) {
  1668. u++;
  1669. }
  1670. } while (MemDbEnumNextValueA (&e));
  1671. }
  1672. return u * TICKS_FILE_EDIT;
  1673. }
  1674. if (Request != REQUEST_RUN) {
  1675. return 0;
  1676. }
  1677. if (!pProcessFileEdit()) {
  1678. return GetLastError();
  1679. }
  1680. return ERROR_SUCCESS;
  1681. }
  1682. VOID
  1683. pWriteLine (
  1684. IN HANDLE Handle,
  1685. IN PCWSTR RootDir, OPTIONAL
  1686. IN PCWSTR String
  1687. )
  1688. {
  1689. DWORD dontCare;
  1690. PCWSTR fullPath;
  1691. if (RootDir) {
  1692. fullPath = JoinPathsW (RootDir, String);
  1693. } else {
  1694. fullPath = String;
  1695. }
  1696. WriteFile (Handle, fullPath, ByteCountW (fullPath), &dontCare, NULL);
  1697. if (fullPath != String) {
  1698. FreePathStringW (fullPath);
  1699. }
  1700. WriteFile (Handle, L"\r\n", 4, &dontCare, NULL);
  1701. }
  1702. DWORD
  1703. RemoveBootIniCancelOption (
  1704. DWORD Request
  1705. )
  1706. {
  1707. HINF inf = INVALID_HANDLE_VALUE;
  1708. PCTSTR bootIni;
  1709. PCTSTR bootIniTmp;
  1710. DWORD result = ERROR_SUCCESS;
  1711. PINFLINE osLine;
  1712. BOOL changed = FALSE;
  1713. DWORD attribs;
  1714. if (Request == REQUEST_QUERYTICKS) {
  1715. return 50;
  1716. }
  1717. if (Request != REQUEST_RUN) {
  1718. return 0;
  1719. }
  1720. bootIni = JoinPaths (g_BootDrivePath, TEXT("boot.ini"));
  1721. __try {
  1722. //
  1723. // Open boot.ini for editing
  1724. //
  1725. inf = OpenInfFile (bootIni);
  1726. if (inf == INVALID_HANDLE_VALUE) {
  1727. DEBUGMSG ((DBG_ERROR, "Can't open %s", bootIni));
  1728. result = GetLastError();
  1729. __leave;
  1730. }
  1731. //
  1732. // Scan boot.ini for a textmode option that has /rollback. Delete it.
  1733. //
  1734. osLine = GetFirstLineInSectionStr (inf, TEXT("Operating Systems"));
  1735. if (!osLine) {
  1736. DEBUGMSG ((DBG_ERROR, "No lines found in [Operating Systems] in %s", bootIni));
  1737. result = ERROR_FILE_NOT_FOUND;
  1738. __leave;
  1739. }
  1740. //
  1741. // Loop until all lines with /rollback are gone
  1742. //
  1743. do {
  1744. do {
  1745. //
  1746. // Check this line for a /rollback option
  1747. //
  1748. if (_tcsistr (osLine->Data, TEXT("/rollback"))) {
  1749. DEBUGMSG ((DBG_FILEMIG, "Found rollback option: %s", osLine->Data));
  1750. break;
  1751. }
  1752. } while (osLine = GetNextLineInSection (osLine));
  1753. if (osLine) {
  1754. if (!DeleteLineInInfSection (inf, osLine)) {
  1755. MYASSERT (FALSE);
  1756. break;
  1757. }
  1758. DEBUGMSG ((DBG_FILEMIG, "Line sucessfully removed"));
  1759. changed = TRUE;
  1760. osLine = GetFirstLineInSectionStr (inf, TEXT("Operating Systems"));
  1761. }
  1762. } while (osLine);
  1763. //
  1764. // If we changed the file, then write it to disk. Keep the original
  1765. // boot.ini file in case we fail to save.
  1766. //
  1767. attribs = GetFileAttributes (bootIni);
  1768. SetFileAttributes (bootIni, FILE_ATTRIBUTE_NORMAL);
  1769. MYASSERT (attribs != INVALID_ATTRIBUTES);
  1770. bootIniTmp = JoinPaths (g_BootDrivePath, TEXT("boot.~t"));
  1771. SetFileAttributes (bootIniTmp, FILE_ATTRIBUTE_NORMAL);
  1772. DeleteFile (bootIniTmp);
  1773. if (!MoveFile (bootIni, bootIniTmp)) {
  1774. LOG ((LOG_ERROR, (PCSTR) MSG_BOOT_INI_MOVE_FAILED, bootIni, bootIniTmp));
  1775. result = GetLastError();
  1776. } else {
  1777. DEBUGMSG ((DBG_FILEMIG, "Moved %s to %s", bootIni, bootIniTmp));
  1778. if (!SaveInfFile (inf, bootIni)) {
  1779. LOG ((LOG_ERROR, (PCSTR) MSG_BOOT_INI_SAVE_FAILED, bootIni));
  1780. result = GetLastError();
  1781. SetFileAttributes (bootIni, FILE_ATTRIBUTE_NORMAL);
  1782. DeleteFile (bootIni);
  1783. if (!MoveFile (bootIniTmp, bootIni)) {
  1784. //
  1785. // This should not happen, because we just successfully
  1786. // moved the original to the tmp; we should be able to
  1787. // move the temp back to the original. If we fail, the pc
  1788. // becomes unbootable. But what can we do?
  1789. //
  1790. LOG ((LOG_ERROR, (PCSTR) MSG_BOOT_INI_MOVE_FAILED, bootIniTmp, bootIni));
  1791. }
  1792. } else {
  1793. //
  1794. // boot.ini was successfully updated. Remove the original copy.
  1795. //
  1796. DeleteFile (bootIniTmp);
  1797. MYASSERT (result == ERROR_SUCCESS);
  1798. DEBUGMSG ((DBG_FILEMIG, "%s was saved", bootIni));
  1799. }
  1800. }
  1801. //
  1802. // restore attributes on original if possible.
  1803. //
  1804. SetFileAttributes (bootIni, attribs);
  1805. FreePathString (bootIniTmp);
  1806. // result already set above
  1807. }
  1808. __finally {
  1809. if (inf != INVALID_HANDLE_VALUE) {
  1810. CloseInfFile (inf);
  1811. }
  1812. FreePathString (bootIni);
  1813. }
  1814. return result;
  1815. }
  1816. ULONGLONG
  1817. pGetFileSize(
  1818. IN PCTSTR FilePath
  1819. )
  1820. {
  1821. ULARGE_INTEGER FileSize = {0, 0};
  1822. GetFileSizeFromFilePath(FilePath, &FileSize);
  1823. return FileSize.QuadPart;
  1824. }
  1825. BOOL
  1826. pMapHiveOfUserDoingTheUpgrade (
  1827. VOID
  1828. )
  1829. {
  1830. MIGRATE_USER_ENUM e;
  1831. PTSTR profilePath;
  1832. TCHAR hiveFile[MAX_TCHAR_PATH];
  1833. LONG rc;
  1834. HKEY newHkcu = NULL;
  1835. TCHAR rootKey[] = TEXT("HKU\\") S_TEMP_USER_KEY;
  1836. BOOL result = FALSE;
  1837. BOOL hiveLoaded = FALSE;
  1838. __try {
  1839. //
  1840. // Find Administrator
  1841. //
  1842. if (EnumFirstUserToMigrate (&e, ENUM_ALL_USERS)) {
  1843. do {
  1844. if (e.UserDoingTheUpgrade) {
  1845. break;
  1846. }
  1847. } while (EnumNextUserToMigrate (&e));
  1848. if (e.UserDoingTheUpgrade) {
  1849. DEBUGMSG ((DBG_VERBOSE, "%s is the user doing the upgrade", e.FixedUserName));
  1850. //
  1851. // Load the hive
  1852. //
  1853. if (-1 == pSetupStringTableLookUpStringEx (
  1854. g_HiveTable,
  1855. e.FixedUserName,
  1856. STRTAB_CASE_INSENSITIVE,
  1857. hiveFile,
  1858. sizeof (hiveFile)
  1859. )) {
  1860. DEBUGMSG ((DBG_WHOOPS, "Can't find NT hive for %s", e.FixedUserName));
  1861. __leave;
  1862. }
  1863. rc = RegUnLoadKey (HKEY_USERS, S_TEMP_USER_KEY);
  1864. if (rc != ERROR_SUCCESS) {
  1865. DumpOpenKeys ();
  1866. SetLastError (rc);
  1867. DEBUGMSG_IF ((
  1868. rc != ERROR_INVALID_PARAMETER,
  1869. DBG_WARNING,
  1870. "Can't unload temp user key"
  1871. ));
  1872. }
  1873. rc = RegLoadKey (HKEY_USERS, S_TEMP_USER_KEY, hiveFile);
  1874. if (rc != ERROR_SUCCESS) {
  1875. LOG ((
  1876. LOG_ERROR,
  1877. "Uninstall: Can't load user hive for %s (%s)",
  1878. e.FixedUserName,
  1879. hiveFile
  1880. ));
  1881. __leave;
  1882. }
  1883. hiveLoaded = TRUE;
  1884. newHkcu = OpenRegKeyStr (rootKey);
  1885. if (newHkcu) {
  1886. rc = RegOverridePredefKey (HKEY_CURRENT_USER, newHkcu);
  1887. if (rc != ERROR_SUCCESS) {
  1888. LOG ((LOG_ERROR, "Uninstall: Can't override HKCU"));
  1889. __leave;
  1890. }
  1891. } else {
  1892. LOG ((
  1893. LOG_ERROR,
  1894. "Uninstall: Can't open user hive for %s (%s)",
  1895. e.FixedUserName,
  1896. hiveFile
  1897. ));
  1898. __leave;
  1899. }
  1900. } else {
  1901. DEBUGMSG ((DBG_ERROR, "Can't find migration user"));
  1902. __leave;
  1903. }
  1904. } else {
  1905. DEBUGMSG ((DBG_WHOOPS, "No users were enumerated"));
  1906. __leave;
  1907. }
  1908. result = TRUE;
  1909. }
  1910. __finally {
  1911. if (newHkcu) {
  1912. CloseRegKey (newHkcu);
  1913. }
  1914. if (hiveLoaded && !result) {
  1915. RegOverridePredefKey (HKEY_CURRENT_USER, NULL);
  1916. RegUnLoadKey (HKEY_USERS, S_TEMP_USER_KEY);
  1917. }
  1918. }
  1919. return result;
  1920. }
  1921. VOID
  1922. pUnmapHiveOfUserDoingTheUpgrade (
  1923. VOID
  1924. )
  1925. {
  1926. RegOverridePredefKey (HKEY_CURRENT_USER, NULL);
  1927. RegUnLoadKey (HKEY_USERS, S_TEMP_USER_KEY);
  1928. }
  1929. BOOL
  1930. pClearPasswordsFromWinntSif(
  1931. PCTSTR WinntSifDir
  1932. )
  1933. {
  1934. TCHAR pathWinntSif[MAX_PATH];
  1935. TCHAR password[MAX_PATH];
  1936. BOOL bResult = TRUE;
  1937. UINT i;
  1938. if(!WinntSifDir ||
  1939. (_tcslen(WinntSifDir) + 1/*'\\'*/ + ARRAYSIZE(WINNT_SIF_FILE)) > ARRAYSIZE(pathWinntSif)){
  1940. MYASSERT(FALSE);
  1941. return FALSE;
  1942. }
  1943. _tcscpy(pathWinntSif, WinntSifDir);
  1944. _tcscat(AppendWack(pathWinntSif), WINNT_SIF_FILE);
  1945. {
  1946. struct{
  1947. PCTSTR Section;
  1948. PCTSTR PasswordKey;
  1949. } passwordList[] = {
  1950. {S_PAGE_IDENTIFICATION, S_DOMAIN_ADMIN_PW}, // DomainAdminPassword
  1951. {WINNT_GUIUNATTENDED, TEXT("AdminPassword")}, // AdminPassword
  1952. {TEXT("Win9xUpg.UserOptions"), TEXT("UserPassword")}, // UserPassword
  1953. {TEXT("Win9xUpg.UserOptions"), S_DEFAULT_PASSWORD_VALUE} // DefaultPassword
  1954. };
  1955. for(i = 0; i < ARRAYSIZE(passwordList); i++){
  1956. if(GetPrivateProfileString(passwordList[i].Section,
  1957. passwordList[i].PasswordKey,
  1958. TEXT(""),
  1959. password,
  1960. ARRAYSIZE(password),
  1961. pathWinntSif) && password[0] != '\0'){
  1962. if(!WritePrivateProfileString(passwordList[i].Section,
  1963. passwordList[i].PasswordKey,
  1964. TEXT(""),
  1965. pathWinntSif)){
  1966. MYASSERT(FALSE);
  1967. bResult = FALSE;
  1968. }
  1969. }
  1970. }
  1971. }
  1972. return bResult;
  1973. }
  1974. DWORD
  1975. WriteBackupInfo (
  1976. DWORD Request
  1977. )
  1978. /*++
  1979. Routine Description:
  1980. WriteBackupInfo outputs files to allow rollback to work properly. It also
  1981. moves the text mode rollback environment into %windir%\undo.
  1982. Arguments:
  1983. Request - Specifies the request being made by the progress bar manager
  1984. Return Value:
  1985. If Request is REQUEST_QUERYTICKS, the return value indicates the number of
  1986. ticks. Otherwise, the return value is a Win32 result code.
  1987. --*/
  1988. {
  1989. UINT u;
  1990. TCHAR src[MAX_PATH];
  1991. TCHAR cabPath[MAX_PATH];
  1992. PCSTR ansiTempDir;
  1993. HKEY key;
  1994. HKEY subKey;
  1995. PCTSTR msg;
  1996. HANDLE delDirsHandle;
  1997. HANDLE delFilesHandle;
  1998. PCTSTR path;
  1999. DWORD dontCare;
  2000. TREE_ENUM treeEnum;
  2001. LONG rc;
  2002. CCABHANDLE cabHandle;
  2003. BOOL res;
  2004. TCHAR pathForFile[MAX_PATH];
  2005. DWORD i;
  2006. WIN32_FILE_ATTRIBUTE_DATA dataOfFile;
  2007. static LPCTSTR arrayOfFilesName[] = {TEXT("boot.cab"), TEXT("backup.cab")};
  2008. PSTR ansiString;
  2009. BOOL validUninstall = TRUE;
  2010. ULARGE_INTEGER AmountOfSpaceForDelFiles;
  2011. ULARGE_INTEGER AmountOfSpaceForBackupFiles;
  2012. INFCONTEXT ic;
  2013. ULARGE_INTEGER tempLargeInteger;
  2014. TCHAR keyPath[MEMDB_MAX];
  2015. DWORD value;
  2016. GROWBUFFER appList = GROWBUF_INIT;
  2017. GROWBUFFER appMultiSz = GROWBUF_INIT;
  2018. PINSTALLEDAPPW installedApp;
  2019. UINT count;
  2020. ULONGLONG *ullPtr;
  2021. BYTE * backupImageInfoPtr = NULL;
  2022. UINT sizeOfbackupImageInfo;
  2023. BACKUPIMAGEINFO backupImageInfo;
  2024. FILEINTEGRITYINFO fileIntegrityInfo[BACKUP_FILE_NUMBER];
  2025. WCHAR fileNameOfFileIntegrityInfo[ARRAYSIZE(fileIntegrityInfo)][MAX_PATH];
  2026. BACKUPIMAGEINFO testbackupImageInfo;
  2027. DRIVEINFO drivesInfo[MAX_DRIVE_NUMBER];
  2028. WCHAR * FileSystemName = NULL;
  2029. WCHAR * VolumeNTPath = NULL;
  2030. BOOL unmapUser;
  2031. if (Request == REQUEST_QUERYTICKS) {
  2032. return 50;
  2033. }
  2034. if (Request != REQUEST_RUN) {
  2035. return 0;
  2036. }
  2037. if (!g_ConfigOptions.EnableBackup) {
  2038. DEBUGMSG ((DBG_ERROR, "Backup is not enabled"));
  2039. return ERROR_SUCCESS;
  2040. }
  2041. ELSE_DEBUGMSG ((DBG_FILEMIG, "Backup is enabled"));
  2042. if(!g_ConfigOptions.PathForBackup) {
  2043. DEBUGMSG ((DBG_ERROR, "Path For Backup does not specified"));
  2044. return ERROR_INVALID_PARAMETER;
  2045. }
  2046. ELSE_DEBUGMSG ((DBG_FILEMIG, "Path For Backup is %s", g_ConfigOptions.PathForBackup));
  2047. FileSystemName = MemAlloc(g_hHeap, 0, MAX_DRIVE_NUMBER * MAX_PATH);
  2048. if(!FileSystemName){
  2049. DEBUGMSG ((DBG_ERROR, "WriteBackupInfo: Can't allocate memory for FileSystemName"));
  2050. return ERROR_NOT_ENOUGH_MEMORY;
  2051. }
  2052. VolumeNTPath = MemAlloc(g_hHeap, 0, MAX_DRIVE_NUMBER * MAX_PATH);
  2053. if(!VolumeNTPath){
  2054. MemFree(g_hHeap, 0, FileSystemName);
  2055. DEBUGMSG ((DBG_ERROR, "WriteBackupInfo: Can't allocate memory for VolumeNTPath"));
  2056. return ERROR_NOT_ENOUGH_MEMORY;
  2057. }
  2058. //
  2059. //Init BACKUPIMAGEINFO structure
  2060. //
  2061. for(i = 0; i < ARRAYSIZE(drivesInfo); i++){
  2062. drivesInfo[i].FileSystemName = &FileSystemName[i * MAX_PATH];
  2063. drivesInfo[i].VolumeNTPath = &VolumeNTPath[i * MAX_PATH];
  2064. }
  2065. backupImageInfo.NumberOfDrives = 0;
  2066. backupImageInfo.DrivesInfo = drivesInfo;
  2067. backupImageInfo.NumberOfFiles = BACKUP_FILE_NUMBER;
  2068. backupImageInfo.FilesInfo = fileIntegrityInfo;
  2069. for(i = 0; i < ARRAYSIZE(fileIntegrityInfo); i++){
  2070. fileIntegrityInfo[i].FileName = fileNameOfFileIntegrityInfo[i];
  2071. }
  2072. //
  2073. // Complete the backup image by writing a list of files that are new with
  2074. // the upgraded OS, or moved in the upgrade process.
  2075. //
  2076. AmountOfSpaceForDelFiles.QuadPart = 0;
  2077. ansiTempDir = CreateDbcs (g_TempDir);
  2078. WriteBackupFilesA (FALSE, ansiTempDir, NULL, NULL, 0, 0, &AmountOfSpaceForDelFiles, NULL);
  2079. DestroyDbcs (ansiTempDir);
  2080. DEBUGMSG((DBG_FILEMIG, "AmountOfSpaceForDelFiles is %d MB", (UINT)AmountOfSpaceForDelFiles.QuadPart>>20));
  2081. AmountOfSpaceForBackupFiles.QuadPart = 0;
  2082. value = 0;
  2083. MemDbBuildKey (keyPath, MEMDB_CATEGORY_STATE, MEMDB_ITEM_ROLLBACK_SPACE, NULL, NULL);
  2084. if(MemDbGetValue (keyPath, &value)){
  2085. AmountOfSpaceForBackupFiles.QuadPart = value;
  2086. AmountOfSpaceForBackupFiles.QuadPart <<= 20;
  2087. }
  2088. ELSE_DEBUGMSG((DBG_FILEMIG, "Can't read MEMDB_ITEM_ROLLBACK_SPACE"));
  2089. DEBUGMSG((DBG_FILEMIG, "AmountOfSpaceForBackupFiles is %d MB", (UINT)AmountOfSpaceForBackupFiles.QuadPart>>20));
  2090. if(AmountOfSpaceForBackupFiles.QuadPart > AmountOfSpaceForDelFiles.QuadPart){
  2091. backupImageInfo.BackupFilesDiskSpace.QuadPart =
  2092. AmountOfSpaceForBackupFiles.QuadPart - AmountOfSpaceForDelFiles.QuadPart;
  2093. }
  2094. else{
  2095. backupImageInfo.BackupFilesDiskSpace.QuadPart = 0;
  2096. }
  2097. //
  2098. // Prepare boot.cab. Some errors are ignored, such as the inability to
  2099. // create a backup dir, or set its attributes. If these cases were to
  2100. // occur, subsequent errors are reported.
  2101. //
  2102. // As serious errors are encountered, we log them and turn off the
  2103. // Add/Remove Programs option. We continue so we can capture all of
  2104. // the possible problems.
  2105. //
  2106. wsprintf (src, TEXT("%s$win_nt$.~bt"), g_BootDrivePath);
  2107. if (!CreateDirectory (g_ConfigOptions.PathForBackup, NULL)) {
  2108. if (GetLastError() != ERROR_ALREADY_EXISTS) {
  2109. LOG ((LOG_ERROR, "WriteBackupInfo: Can't create %s directory", g_ConfigOptions.PathForBackup));
  2110. }
  2111. }
  2112. res = SetFileAttributes (g_ConfigOptions.PathForBackup, FILE_ATTRIBUTE_HIDDEN | FILE_ATTRIBUTE_SYSTEM);
  2113. if(!res) {
  2114. DEBUGMSG ((DBG_ERROR, "Can't set attributes to %s directory", g_ConfigOptions.PathForBackup));
  2115. }
  2116. key = OpenRegKeyStr (S_REGKEY_WIN_SETUP);
  2117. if (key != NULL) {
  2118. if(ERROR_SUCCESS == RegSetValueEx (
  2119. key,
  2120. S_REG_KEY_UNDO_PATH,
  2121. 0,
  2122. REG_SZ,
  2123. (PBYTE)g_ConfigOptions.PathForBackup,
  2124. SizeOfString (g_ConfigOptions.PathForBackup))){
  2125. res = TRUE;
  2126. }
  2127. else {
  2128. res = FALSE;
  2129. }
  2130. CloseRegKey (key);
  2131. } else {
  2132. res = FALSE;
  2133. }
  2134. if (!res) {
  2135. LOG ((LOG_ERROR, "WriteBackupInfo:Can't set %s value to %s key in registry, uninstall will be disabled", S_REG_KEY_UNDO_PATH, S_REGKEY_WIN_SETUP));
  2136. validUninstall = FALSE;
  2137. }
  2138. if(!pClearPasswordsFromWinntSif(src)){
  2139. DEBUGMSG ((DBG_ERROR, "WriteBackupInfo:pClearPasswordsFromWinntSif failed"));
  2140. }
  2141. if (validUninstall) {
  2142. PCTSTR pathBootCab = JoinPaths (g_ConfigOptions.PathForBackup, TEXT("boot.cab"));
  2143. DeleteFile(pathBootCab);
  2144. FreePathString(pathBootCab);
  2145. cabHandle = CabCreateCabinet (g_ConfigOptions.PathForBackup, TEXT("boot.cab"), TEXT("dontcare"), 0);
  2146. } else {
  2147. cabHandle = NULL;
  2148. }
  2149. backupImageInfo.BootFilesDiskSpace.QuadPart = 0;
  2150. backupImageInfo.UndoFilesDiskSpace.QuadPart = 0;
  2151. if (!cabHandle) {
  2152. LOG ((LOG_ERROR, "WriteBackupInfo:Can't create CAB file for ~bt in %s, uninstall will be disabled", g_ConfigOptions.PathForBackup));
  2153. validUninstall = FALSE;
  2154. } else {
  2155. if (EnumFirstFileInTree (&treeEnum, src, NULL, FALSE)) {
  2156. do {
  2157. if (treeEnum.Directory) {
  2158. continue;
  2159. }
  2160. tempLargeInteger.LowPart = treeEnum.FindData->nFileSizeLow;
  2161. tempLargeInteger.HighPart = treeEnum.FindData->nFileSizeHigh;
  2162. backupImageInfo.BootFilesDiskSpace.QuadPart += tempLargeInteger.QuadPart;
  2163. if (!CabAddFileToCabinet (cabHandle, treeEnum.FullPath, treeEnum.FullPath)) {
  2164. LOG ((LOG_ERROR, "WriteBackupInfo:Can't add %s to boot.cab, uninstall will be disabled", src));
  2165. validUninstall = FALSE;
  2166. }
  2167. } while (EnumNextFileInTree (&treeEnum));
  2168. }
  2169. wsprintf (src, TEXT("%s\\uninstall\\moved.txt"), g_TempDir);
  2170. wsprintf (cabPath, TEXT("%s\\moved.txt"), g_ConfigOptions.PathForBackup);
  2171. if (!CabAddFileToCabinet (cabHandle, src, cabPath)) {
  2172. LOG ((LOG_ERROR, "WriteBackupInfo:Can't add %s to boot.cab, uninstall will be disabled", src));
  2173. validUninstall = FALSE;
  2174. }
  2175. backupImageInfo.UndoFilesDiskSpace.QuadPart += pGetFileSize(src);
  2176. wsprintf (src, TEXT("%s\\uninstall\\delfiles.txt"), g_TempDir);
  2177. wsprintf (cabPath, TEXT("%s\\delfiles.txt"), g_ConfigOptions.PathForBackup);
  2178. if (!CabAddFileToCabinet (cabHandle, src, cabPath)) {
  2179. LOG ((LOG_ERROR, "WriteBackupInfo:Can't add %s to boot.cab, uninstall will be disabled", src));
  2180. validUninstall = FALSE;
  2181. }
  2182. backupImageInfo.UndoFilesDiskSpace.QuadPart += pGetFileSize(src);
  2183. wsprintf (src, TEXT("%s\\uninstall\\deldirs.txt"), g_TempDir);
  2184. wsprintf (cabPath, TEXT("%s\\deldirs.txt"), g_ConfigOptions.PathForBackup);
  2185. if (!CabAddFileToCabinet (cabHandle, src, cabPath)) {
  2186. LOG ((LOG_ERROR, "WriteBackupInfo:Can't add %s to boot.cab, uninstall will be disabled", src));
  2187. validUninstall = FALSE;
  2188. }
  2189. backupImageInfo.UndoFilesDiskSpace.QuadPart += pGetFileSize(src);
  2190. wsprintf (src, TEXT("%s\\uninstall\\mkdirs.txt"), g_TempDir);
  2191. wsprintf (cabPath, TEXT("%s\\mkdirs.txt"), g_ConfigOptions.PathForBackup);
  2192. if (!CabAddFileToCabinet (cabHandle, src, cabPath)) {
  2193. LOG ((LOG_ERROR, "WriteBackupInfo:Can't add %s to boot.cab, uninstall will be disabled", src));
  2194. validUninstall = FALSE;
  2195. }
  2196. backupImageInfo.UndoFilesDiskSpace.QuadPart += pGetFileSize(src);
  2197. //wsprintf (src, TEXT("%s\\uninstall\\boot.ini"), g_TempDir);
  2198. //wsprintf (cabPath, TEXT("%sboot.ini"), g_BootDrivePath);
  2199. //if (!CabAddFileToCabinet (cabHandle, src, cabPath)) {
  2200. // DEBUGMSG ((DBG_ERROR, "Can't add %s to boot.cab", src));
  2201. // validUninstall = FALSE;
  2202. //}
  2203. //backupImageInfo.BootFilesDiskSpace.QuadPart += pGetFileSize(src);
  2204. wsprintf (src, TEXT("%s\\uninstall\\$ldr$"), g_TempDir);
  2205. wsprintf (cabPath, TEXT("%s$ldr$"), g_BootDrivePath);
  2206. if (!CabAddFileToCabinet (cabHandle, src, cabPath)) {
  2207. LOG ((LOG_ERROR, "WriteBackupInfo:Can't add %s to boot.cab, uninstall will be disabled", src));
  2208. validUninstall = FALSE;
  2209. }
  2210. backupImageInfo.BootFilesDiskSpace.QuadPart += pGetFileSize(src);
  2211. wsprintf (src, TEXT("%s\\system32\\autochk.exe"), g_WinDir);
  2212. wsprintf (cabPath, TEXT("%s$win_nt$.~bt\\i386\\autochk.exe"), g_BootDrivePath);
  2213. if (!CabAddFileToCabinet (cabHandle, src, cabPath)) {
  2214. //
  2215. // This is only a warning, because text mode will prompt for the
  2216. // CD when autochk.exe can't be found.
  2217. //
  2218. LOG ((LOG_WARNING, "WriteBackupInfo:Can't add %s to boot.cab, uninstall will be disabled", src));
  2219. }
  2220. backupImageInfo.BootFilesDiskSpace.QuadPart += pGetFileSize(src);
  2221. backupImageInfo.BootFilesDiskSpace.QuadPart += BOOT_FILES_ADDITIONAL_PADDING;
  2222. backupImageInfo.UndoFilesDiskSpace.QuadPart +=
  2223. backupImageInfo.BootFilesDiskSpace.QuadPart + UNDO_FILES_ADDITIONAL_PADDING;
  2224. if (!CabFlushAndCloseCabinet (cabHandle)) {
  2225. LOG ((LOG_ERROR, "WriteBackupInfo:Can't write CAB file for ~bt, uninstall will be disabled"));
  2226. validUninstall = FALSE;
  2227. }
  2228. }
  2229. //
  2230. // Create and write undo integrity info to registry
  2231. //
  2232. if (validUninstall) {
  2233. backupImageInfo.FilesInfo[0].IsCab = TRUE;
  2234. GetIntegrityInfo(TEXT("boot.cab"), g_ConfigOptions.PathForBackup, &backupImageInfo.FilesInfo[0]);
  2235. backupImageInfo.FilesInfo[1].IsCab = TRUE;
  2236. GetIntegrityInfo(TEXT("backup.cab"), g_ConfigOptions.PathForBackup, &backupImageInfo.FilesInfo[1]);
  2237. if(GetUndoDrivesInfo(drivesInfo,
  2238. &backupImageInfo.NumberOfDrives,
  2239. g_BootDrivePath[0],
  2240. g_WinDir[0],
  2241. g_ConfigOptions.PathForBackup[0])){
  2242. if(GetDisksInfo(&backupImageInfo.DisksInfo, &backupImageInfo.NumberOfDisks)){
  2243. if(Persist_Success == PERSIST_STORE(&backupImageInfoPtr,
  2244. &sizeOfbackupImageInfo,
  2245. BACKUPIMAGEINFO,
  2246. BACKUPIMAGEINFO_VERSION,
  2247. &backupImageInfo)){
  2248. key = OpenRegKeyStr (S_REGKEY_WIN_SETUP);
  2249. if (key) {
  2250. RegSetValueEx (
  2251. key,
  2252. S_REG_KEY_UNDO_INTEGRITY,
  2253. 0,
  2254. REG_BINARY,
  2255. (PBYTE)backupImageInfoPtr,
  2256. sizeOfbackupImageInfo
  2257. );
  2258. DEBUGMSG((
  2259. DBG_VERBOSE,
  2260. "Boot files size is %d KB, Undo file size is %d KB, Backup files size is %d KB",
  2261. (DWORD)backupImageInfo.BootFilesDiskSpace.QuadPart>>10,
  2262. (DWORD)backupImageInfo.UndoFilesDiskSpace.QuadPart>>10,
  2263. (DWORD)backupImageInfo.BackupFilesDiskSpace.QuadPart>>10));
  2264. CloseRegKey (key);
  2265. }
  2266. else {
  2267. LOG((LOG_ERROR, "WriteBackupInfo:Could not write to registry, uninstall will be disabled"));
  2268. validUninstall = FALSE;
  2269. }
  2270. PERSIST_RELEASE_BUFFER(backupImageInfoPtr);
  2271. }
  2272. else{
  2273. LOG((LOG_ERROR, "WriteBackupInfo:Could not marshall BACKUPIMAGEINFO structure, GetLastError() == %d, uninstall will be disabled", GetLastError()));
  2274. validUninstall = FALSE;
  2275. }
  2276. } else {
  2277. LOG((LOG_ERROR, "WriteBackupInfo:GetDisksInfo failed, uninstall will be disabled"));
  2278. validUninstall = FALSE;
  2279. }
  2280. }
  2281. else{
  2282. LOG ((LOG_ERROR, "WriteBackupInfo:GetUndoDrivesInfo failed, uninstall will be disabled"));
  2283. validUninstall = FALSE;
  2284. }
  2285. if(backupImageInfo.DisksInfo){
  2286. FreeDisksInfo(backupImageInfo.DisksInfo, backupImageInfo.NumberOfDisks);
  2287. }
  2288. }
  2289. //
  2290. // Establish Add/Remove Programs entry
  2291. //
  2292. if (validUninstall) {
  2293. key = CreateRegKeyStr (TEXT("HKLM\\Software\\Microsoft\\Windows\\CurrentVersion\\Uninstall"));
  2294. if (key) {
  2295. subKey = CreateRegKey (key, TEXT("Windows"));
  2296. CloseRegKey (key);
  2297. if (subKey) {
  2298. msg = GetStringResource (MSG_UNINSTALL_DISPLAY_STRING);
  2299. RegSetValueEx (subKey, TEXT("DisplayName"), 0, REG_SZ, (PBYTE) msg, SizeOfString (msg));
  2300. FreeStringResource (msg);
  2301. msg = TEXT("%SYSTEMROOT%\\system32\\osuninst.exe");
  2302. rc = RegSetValueEx (subKey, TEXT("UninstallString"), 0, REG_EXPAND_SZ, (PBYTE) msg, SizeOfString (msg));
  2303. SetLastError (rc);
  2304. rc = RegSetValueEx (subKey, TEXT("DisplayIcon"), 0, REG_EXPAND_SZ, (PBYTE) msg, SizeOfString (msg));
  2305. SetLastError (rc);
  2306. rc = RegSetValueEx (
  2307. subKey,
  2308. TEXT("InstallLocation"),
  2309. 0,
  2310. REG_EXPAND_SZ,
  2311. (PBYTE) g_ConfigOptions.PathForBackup,
  2312. SizeOfString (g_ConfigOptions.PathForBackup));
  2313. SetLastError (rc);
  2314. DEBUGMSG_IF ((rc != ERROR_SUCCESS, DBG_ERROR, "Can't create Add/Remove Programs value"));
  2315. CloseRegKey (subKey);
  2316. } else {
  2317. LOG ((LOG_ERROR, "Can't create Add/Remove Programs subkey"));
  2318. validUninstall = FALSE;
  2319. }
  2320. } else {
  2321. validUninstall = FALSE;
  2322. LOG ((LOG_ERROR, "Can't create Add/Remove Programs subkey"));
  2323. }
  2324. }
  2325. if(VolumeNTPath){
  2326. MemFree(g_hHeap, 0, VolumeNTPath);
  2327. }
  2328. if(FileSystemName){
  2329. MemFree(g_hHeap, 0, FileSystemName);
  2330. }
  2331. //
  2332. // Save progress text to the registry
  2333. //
  2334. if (validUninstall) {
  2335. key = CreateRegKeyStr (S_WIN9XUPG_KEY);
  2336. if (key) {
  2337. msg = GetStringResource (MSG_OLEREG);
  2338. RegSetValueEx (key, S_UNINSTALL_DISP_STR, 0, REG_SZ, (PBYTE) msg, SizeOfString (msg));
  2339. FreeStringResource (msg);
  2340. CloseRegKey (key);
  2341. }
  2342. }
  2343. //
  2344. // Write list of installed apps to the registry
  2345. //
  2346. if (validUninstall) {
  2347. CoInitialize (NULL);
  2348. //
  2349. // Map in the default user's hive. Use this for HKCU.
  2350. //
  2351. unmapUser = pMapHiveOfUserDoingTheUpgrade();
  2352. //
  2353. // Get the installed apps.
  2354. //
  2355. installedApp = GetInstalledAppsW (&appList, &count);
  2356. //
  2357. // Unmap the hive.
  2358. //
  2359. if (unmapUser) {
  2360. pUnmapHiveOfUserDoingTheUpgrade();
  2361. }
  2362. //
  2363. // Record the apps in the registry.
  2364. //
  2365. if (installedApp) {
  2366. for (u = 0 ; u < count ; u++) {
  2367. DEBUGMSG ((
  2368. DBG_FILEMIG,
  2369. "App previously installed: %ws (%I64X)",
  2370. installedApp->DisplayName,
  2371. installedApp->Checksum
  2372. ));
  2373. GrowBufCopyStringW (&appMultiSz, installedApp->DisplayName);
  2374. ullPtr = (ULONGLONG *) GrowBuffer (&appMultiSz, sizeof (ULONGLONG));
  2375. *ullPtr = installedApp->Checksum;
  2376. installedApp++;
  2377. }
  2378. GrowBufCopyStringW (&appMultiSz, L"");
  2379. key = OpenRegKeyStr (S_REGKEY_WIN_SETUP);
  2380. if (key) {
  2381. rc = RegSetValueEx (
  2382. key,
  2383. S_REG_KEY_UNDO_APP_LIST,
  2384. 0,
  2385. REG_BINARY,
  2386. appMultiSz.Buf,
  2387. appMultiSz.End
  2388. );
  2389. if (rc != ERROR_SUCCESS) {
  2390. SetLastError (rc);
  2391. DEBUGMSG ((DBG_ERROR, "Can't write list of installed apps to registry value"));
  2392. }
  2393. CloseRegKey (key);
  2394. }
  2395. ELSE_DEBUGMSG ((DBG_ERROR, "Can't write list of installed apps to registry"));
  2396. }
  2397. ELSE_DEBUGMSG ((DBG_ERROR, "Can't get list of installed apps."));
  2398. }
  2399. FreeGrowBuffer (&appList);
  2400. FreeGrowBuffer (&appMultiSz);
  2401. DEBUGMSG_IF ((!validUninstall, DBG_ERROR, "Uninstall is not available because of a previous error"));
  2402. return ERROR_SUCCESS;
  2403. }
  2404. DWORD
  2405. DisableFiles (
  2406. DWORD Request
  2407. )
  2408. /*++
  2409. Routine Description:
  2410. DisableFiles runs code to ensure a Win9x file is removed from processing,
  2411. usually because it is suspected of causing problems.
  2412. This function renames all files marked for OPERATION_FILE_DISABLED adding a
  2413. .disabled at the end.
  2414. Arguments:
  2415. Request - Specifies the progress bar request, which is either
  2416. REQUEST_QUERYTICKS or REQUEST_RUN.
  2417. Return Value:
  2418. The number of ticks (REQUEST_QUERYTICKS) or the status code (REQUEST_RUN).
  2419. --*/
  2420. {
  2421. FILEOP_ENUM e;
  2422. DWORD attr;
  2423. PCTSTR disableName;
  2424. PCTSTR newLocation;
  2425. GROWLIST disableList = GROWLIST_INIT;
  2426. PCTSTR srcPath;
  2427. UINT count;
  2428. UINT u;
  2429. if (Request == REQUEST_QUERYTICKS) {
  2430. return 50;
  2431. }
  2432. if (Request != REQUEST_RUN) {
  2433. return 0;
  2434. }
  2435. //
  2436. // Enumerate each file in OPERATION_FILE_DISABLED and put it in a grow
  2437. // list, because we will then modify the operations so that uninstall
  2438. // works properly.
  2439. //
  2440. if (EnumFirstPathInOperation (&e, OPERATION_FILE_DISABLED)) {
  2441. do {
  2442. GrowListAppendString (&disableList, e.Path);
  2443. } while (EnumNextPathInOperation (&e));
  2444. }
  2445. //
  2446. // Now process each file
  2447. //
  2448. count = GrowListGetSize (&disableList);
  2449. for (u = 0 ; u < count ; u++) {
  2450. srcPath = GrowListGetString (&disableList, u);
  2451. newLocation = GetPathStringOnNt (srcPath);
  2452. attr = GetLongPathAttributes (newLocation);
  2453. if (attr != INVALID_ATTRIBUTES) {
  2454. SetLongPathAttributes (newLocation, FILE_ATTRIBUTE_NORMAL);
  2455. disableName = JoinText (newLocation, TEXT(".disabled"));
  2456. RemoveOperationsFromPath (srcPath, ALL_MOVE_OPERATIONS|ALL_DELETE_OPERATIONS);
  2457. MarkFileForMoveByNt (srcPath, disableName);
  2458. if (!OurMoveFile (newLocation, disableName)) {
  2459. if (GetLastError() == ERROR_ALREADY_EXISTS) {
  2460. //
  2461. // Restart case -- we already moved this file
  2462. //
  2463. SetLongPathAttributes (newLocation, FILE_ATTRIBUTE_NORMAL);
  2464. DeleteLongPath (newLocation);
  2465. }
  2466. ELSE_DEBUGMSG ((DBG_ERROR, "Cannot rename %s to %s", newLocation, disableName));
  2467. }
  2468. FreeText (disableName);
  2469. SetLongPathAttributes (newLocation, attr);
  2470. }
  2471. FreePathString (newLocation);
  2472. }
  2473. FreeGrowList (&disableList);
  2474. return ERROR_SUCCESS;
  2475. }
  2476. VOID
  2477. pUninstallStartMenuCleanupPreparation (
  2478. VOID
  2479. )
  2480. {
  2481. INFSTRUCT is = INITINFSTRUCT_POOLHANDLE;
  2482. INFSTRUCT isLinks = INITINFSTRUCT_POOLHANDLE;
  2483. PCTSTR temp;
  2484. BOOL isCommonGroup;
  2485. TCHAR itemFullPath[MAX_PATH];
  2486. PCTSTR itemGroupPtr;
  2487. TCHAR itemGroupPath[MAX_PATH];
  2488. HINF InfSysSetupHandle;
  2489. PINFSECTION sectionWkstaMigInf = NULL;
  2490. PINFSECTION sectionUserMigInf = NULL;
  2491. InfSysSetupHandle = InfOpenInfFile (TEXT("syssetup.inf"));
  2492. if(!InfSysSetupHandle){
  2493. LOG((LOG_ERROR,"Can't open syssetup.inf for UninstallStartMenuCleanupPreparation."));
  2494. MYASSERT(FALSE);
  2495. return;
  2496. }
  2497. //
  2498. //[StartMenu.StartMenuItems]
  2499. //
  2500. if (InfFindFirstLine (InfSysSetupHandle, TEXT("StartMenu.StartMenuItems"), NULL, &is)) {
  2501. do {
  2502. StringCopy(itemFullPath, TEXT("7520"));
  2503. temp = InfGetStringField (&isLinks, 0);
  2504. if (!temp || *temp == 0) {
  2505. continue;
  2506. }
  2507. StringCat(AppendWack(itemFullPath), temp);
  2508. StringCat(itemFullPath, TEXT(".lnk"));
  2509. GrowListAppendString (&g_StartMenuItemsForCleanUpCommon, itemFullPath);
  2510. GrowListAppendString (&g_StartMenuItemsForCleanUpPrivate, itemFullPath);
  2511. DEBUGMSG ((DBG_VERBOSE,"UninstallStartMenuCleanupPreparation: %s", itemFullPath));
  2512. } while (InfFindNextLine (&is));
  2513. }
  2514. //
  2515. //[StartMenuGroups]
  2516. //
  2517. if (InfFindFirstLine (InfSysSetupHandle, TEXT("StartMenuGroups"), NULL, &is)) {
  2518. do {
  2519. itemGroupPtr = InfGetStringField (&is, 1);
  2520. if (!itemGroupPtr || *itemGroupPtr == 0) {
  2521. continue;
  2522. }
  2523. temp = InfGetStringField (&is, 2);
  2524. if (!temp || *temp == 0) {
  2525. continue;
  2526. }
  2527. if('0' == temp[0]){
  2528. isCommonGroup = TRUE;
  2529. }
  2530. else{
  2531. isCommonGroup = FALSE;
  2532. }
  2533. temp = InfGetStringField (&is, 0);
  2534. if (!temp || *temp == 0) {
  2535. continue;
  2536. }
  2537. StringCopy(itemGroupPath, TEXT("7517"));
  2538. StringCat(AppendWack(itemGroupPath), itemGroupPtr);
  2539. if (InfFindFirstLine (InfSysSetupHandle, temp, NULL, &isLinks)) {
  2540. do {
  2541. StringCopy(itemFullPath, itemGroupPath);
  2542. temp = InfGetStringField (&isLinks, 0);
  2543. if (!temp || *temp == 0) {
  2544. continue;
  2545. }
  2546. StringCat(AppendWack(itemFullPath), temp);
  2547. StringCat(itemFullPath, TEXT(".lnk"));
  2548. GrowListAppendString (&g_StartMenuItemsForCleanUpCommon, itemFullPath);
  2549. if(!isCommonGroup){
  2550. GrowListAppendString (&g_StartMenuItemsForCleanUpPrivate, itemFullPath);
  2551. }
  2552. DEBUGMSG ((DBG_VERBOSE,"UninstallStartMenuCleanupPreparation: %s", itemFullPath));
  2553. } while (InfFindNextLine (&isLinks));
  2554. }
  2555. } while (InfFindNextLine (&is));
  2556. }
  2557. InfCleanUpInfStruct (&is);
  2558. InfCleanUpInfStruct (&isLinks);
  2559. InfCloseInfFile (InfSysSetupHandle);
  2560. }
  2561. DWORD
  2562. UninstallStartMenuCleanupPreparation(
  2563. DWORD Request
  2564. )
  2565. /*++
  2566. Routine Description:
  2567. UninstallStartMenuCleanupPreparation mark files from Start Menu
  2568. sections from syssetup.inf to clean up.
  2569. Arguments:
  2570. Request - Specifies the request being made by the progress bar manager
  2571. Return Value:
  2572. If Request is REQUEST_QUERYTICKS, the return value indicates the number of
  2573. ticks. Otherwise, the return value is a Win32 result code.
  2574. --*/
  2575. {
  2576. if (Request == REQUEST_QUERYTICKS) {
  2577. return 3;
  2578. }
  2579. if (Request != REQUEST_RUN) {
  2580. return 0;
  2581. }
  2582. pUninstallStartMenuCleanupPreparation();
  2583. return ERROR_SUCCESS;
  2584. }