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.

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