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.

915 lines
22 KiB

  1. /*++
  2. Copyright (c) 1997 Microsoft Corporation
  3. Module Name:
  4. masys32.c
  5. Abstract:
  6. Functions to migrate a Win9x user's system directory to system32.
  7. Author:
  8. Mike Condra (mikeco) 25-Feb-1997
  9. Revision History:
  10. ovidiut 09-Mar-1999 Added support to rename files on Win9x side
  11. jimschm 23-Sep-1998 Updated for new fileops code
  12. jimschm 02-Dec-1997 Removed rename of system32 if it already exists
  13. mikeco 23-Jun-1997 NT-style file- & fn-header comments
  14. --*/
  15. #include "pch.h"
  16. #include "migdbp.h"
  17. #include "migappp.h"
  18. #define DBG_SYS32 "Sys32"
  19. PCTSTR
  20. pGetNewName (
  21. PCTSTR FileName
  22. )
  23. /*++
  24. Routine Description:
  25. This function generates a new name for the file that is going to be renames.
  26. Arguments:
  27. FileName - Original file name
  28. Return Value:
  29. the new name for file
  30. --*/
  31. {
  32. PCTSTR pattern;
  33. PTSTR result ;
  34. UINT count ;
  35. DWORD attrib ;
  36. pattern = JoinText (FileName, TEXT(".%03u"));
  37. result = JoinText (FileName, TEXT("XXXX"));
  38. count = 0;
  39. do {
  40. if (count == 999) {
  41. return result;
  42. }
  43. _stprintf (result, pattern, count);
  44. attrib = GetFileAttributes (result);
  45. count ++;
  46. }
  47. while (attrib != 0xFFFFFFFF);
  48. FreeText (pattern);
  49. return result;
  50. }
  51. BOOL
  52. pRenameSystem32File (
  53. IN PCTSTR NewName,
  54. IN OUT PGROWBUFFER msgBufRename,
  55. OUT PBOOL FileDeleted
  56. )
  57. /*++
  58. Routine Description:
  59. pRenameSystem32File handles the special file %windir%\system32. If it exists and cannot
  60. be automatically renamed, 2 things may happen:
  61. - in unattended mode, the file will be deleted (this will be done by textmode setup)
  62. - otherwise the user is asked to take a decision: either rename the file or cancels
  63. Setup
  64. Arguments:
  65. DirName - name of NT dir to check
  66. msgBufRename - growbuffer to append a Message when renaming a file.
  67. msgBufDelete - growbuffer to append a Message when deleting a file (system32 only).
  68. Return Value:
  69. TRUE if the operation was successful and Setup can continue, FALSE if user cancelled
  70. --*/
  71. {
  72. DWORD attrib;
  73. PCTSTR Message = NULL;
  74. PCTSTR button1 = NULL;
  75. PCTSTR button2 = NULL;
  76. BOOL Quit;
  77. BOOL b = FALSE;
  78. *FileDeleted = FALSE;
  79. while (!b && !((attrib = GetFileAttributes (g_System32Dir)) & FILE_ATTRIBUTE_DIRECTORY)) {
  80. //
  81. // rename this file now
  82. //
  83. if (SetFileAttributes (g_System32Dir, FILE_ATTRIBUTE_NORMAL)) {
  84. if (MoveFile (g_System32Dir, NewName)) {
  85. b = TRUE;
  86. SetFileAttributes (g_System32Dir, attrib);
  87. } else {
  88. DEBUGMSG ((
  89. DBG_SYS32,
  90. "CheckNtDirs: Unable to set normal attributes on file %s",
  91. g_System32Dir
  92. ));
  93. SetFileAttributes (g_System32Dir, attrib);
  94. }
  95. }
  96. if (!b) {
  97. if (!UNATTENDED()) {
  98. //
  99. // ask user to take a decision about this
  100. //
  101. Message = ParseMessageID (MSG_CANNOT_RENAME_FILE, &g_System32Dir);
  102. button1 = GetStringResource (MSG_RETRY_RENAME);
  103. button2 = GetStringResource (MSG_QUIT_SETUP);
  104. Quit = IDBUTTON1 != TwoButtonBox (g_ParentWnd, Message, button1, button2);
  105. FreeStringResource (Message);
  106. FreeStringResource (button1);
  107. FreeStringResource (button2);
  108. if (Quit) {
  109. SetLastError (ERROR_CANCELLED);
  110. DEBUGMSG ((
  111. DBG_SYS32,
  112. "CheckNtDirs: user cancelled Setup on renaming file %s",
  113. g_System32Dir
  114. ));
  115. return FALSE;
  116. }
  117. } else {
  118. //
  119. // suppose the admin would delete the file anyway;
  120. // that's exactly what textmode setup does, so leave it there and
  121. // return success
  122. //
  123. *FileDeleted = TRUE;
  124. b = TRUE;
  125. }
  126. }
  127. }
  128. return GetFileAttributes (g_System32Dir) & FILE_ATTRIBUTE_DIRECTORY;
  129. }
  130. BOOL
  131. pHandleSingleDir (
  132. IN PCTSTR DirName,
  133. IN OUT PGROWBUFFER msgBufRename,
  134. IN OUT PGROWBUFFER msgBufDelete
  135. )
  136. /*++
  137. Routine Description:
  138. This function checks if a file is in one of NT5 dirs way. If so, the file is renamed and
  139. a Message is send to log. If there is a file named %windir%\system32, it is renamed
  140. at this point (special behaviour) and if this fails, Setup is cancelled.
  141. Arguments:
  142. DirName - name of NT dir to check
  143. msgBufRename - growbuffer to append a Message when renaming a file.
  144. msgBufDelete - growbuffer to append a Message when deleting a file (system32 only).
  145. Return Value:
  146. TRUE if the operation was successful and Setup can continue, FALSE if user cancelled
  147. --*/
  148. {
  149. PCTSTR newFileName, FileNamePart;
  150. DWORD attributes;
  151. TCHAR msg[MAX_TCHAR_PATH * 2 + 5];
  152. BOOL FileDeleted;
  153. attributes = GetFileAttributes (DirName);
  154. if (!(attributes & FILE_ATTRIBUTE_DIRECTORY)) {
  155. newFileName = pGetNewName (DirName);
  156. DEBUGMSG ((DBG_SYS32, "CheckNtDirs: Renaming %s to %s", DirName, newFileName));
  157. FileDeleted = FALSE;
  158. //
  159. // special case: if DirName is g_System32Dir, rename the file right now
  160. // because textmode Setup doesn't have a chance to rename it before
  161. // it is already deleted and the System32 dir is created
  162. //
  163. if (StringIMatch (DirName, g_System32Dir)) {
  164. if (!pRenameSystem32File (newFileName, msgBufRename, &FileDeleted)) {
  165. return FALSE;
  166. }
  167. if (!FileDeleted) {
  168. FileNamePart = GetFileNameFromPath (newFileName);
  169. MYASSERT (FileNamePart);
  170. //
  171. // mark this info for undo on cancel
  172. //
  173. MemDbSetValueEx (
  174. MEMDB_CATEGORY_CHG_FILE_PROPS,
  175. DirName,
  176. FileNamePart,
  177. NULL,
  178. attributes,
  179. NULL
  180. );
  181. }
  182. } else {
  183. MemDbSetValueEx (MEMDB_CATEGORY_DIRS_COLLISION, DirName, NULL, NULL, 0, NULL);
  184. }
  185. //
  186. // append to the log
  187. //
  188. if (FileDeleted) {
  189. wsprintf (msg, TEXT("\n\t\t%s"), DirName);
  190. GrowBufAppendString (msgBufDelete, msg);
  191. } else {
  192. wsprintf (msg, TEXT("\n\t\t%s -> %s"), DirName, newFileName);
  193. GrowBufAppendString (msgBufRename, msg);
  194. }
  195. FreeText (newFileName);
  196. }
  197. return TRUE;
  198. }
  199. VOID
  200. pCheckProfilesDir (
  201. IN OUT PGROWBUFFER msgBufRename
  202. )
  203. /*++
  204. Routine Description:
  205. pCheckProfilesDir makes sure that there is no directory named "g_ProfileDirNt". If
  206. there is, it is renamed, all files and folders within are marked for external move
  207. and a message is added to the user report.
  208. Arguments:
  209. msgBufRename - A grow buffer where the rename message will be appended,
  210. if this is the case
  211. Return Value:
  212. none
  213. --*/
  214. {
  215. TCHAR msg[MAX_TCHAR_PATH * 2 + 5];
  216. DWORD attrib;
  217. PCTSTR NewName;
  218. PTSTR p;
  219. TREE_ENUM TreeEnum;
  220. TCHAR NewDest[MAX_MBCHAR_PATH];
  221. PCTSTR Message;
  222. PCTSTR Group;
  223. PCTSTR array[2];
  224. MYASSERT (g_ProfileDirNt);
  225. attrib = GetFileAttributes (g_ProfileDirNt);
  226. if (attrib != INVALID_ATTRIBUTES) {
  227. MemDbSetValueEx (MEMDB_CATEGORY_DIRS_COLLISION, g_ProfileDirNt, NULL, NULL, 0, NULL);
  228. NewName = pGetNewName (g_ProfileDirNt);
  229. DEBUGMSG ((DBG_SYS32, "CheckNtDirs: Renaming %s to %s", g_ProfileDirNt, NewName));
  230. MarkFileForMove (g_ProfileDirNt, NewName);
  231. wsprintf (msg, TEXT("\n\t\t%s -> %s"), g_ProfileDirNt, NewName);
  232. GrowBufAppendString (msgBufRename, msg);
  233. if (attrib & FILE_ATTRIBUTE_DIRECTORY) {
  234. //
  235. // mark all files in the tree for move
  236. //
  237. if (EnumFirstFileInTree (&TreeEnum, g_ProfileDirNt, NULL, TRUE)) {
  238. StringCopy (NewDest, NewName);
  239. p = AppendWack (NewDest);
  240. do {
  241. MYASSERT (*TreeEnum.SubPath != '\\');
  242. StringCopy (p, TreeEnum.SubPath);
  243. if (!TreeEnum.Directory) {
  244. if (CanSetOperation (TreeEnum.FullPath, OPERATION_TEMP_PATH)) {
  245. //
  246. // remove old operation and set a new one
  247. // with the updated final dest
  248. //
  249. MarkFileForTemporaryMove (TreeEnum.FullPath, NewDest, g_TempDir);
  250. } else {
  251. if (CanSetOperation (TreeEnum.FullPath, OPERATION_FILE_MOVE)) {
  252. MarkFileForMove (TreeEnum.FullPath, NewDest);
  253. }
  254. }
  255. } else {
  256. if (CanSetOperation (TreeEnum.FullPath, OPERATION_FILE_MOVE_EXTERNAL)) {
  257. MarkFileForMoveExternal (TreeEnum.FullPath, NewDest);
  258. }
  259. }
  260. } while (EnumNextFileInTree (&TreeEnum));
  261. }
  262. array[0] = g_ProfileDirNt;
  263. array[1] = NewName;
  264. Message = ParseMessageID (MSG_DIRECTORY_COLLISION_SUBCOMPONENT, array);
  265. if (Message) {
  266. Group = BuildMessageGroup (
  267. MSG_INSTALL_NOTES_ROOT,
  268. MSG_DIRECTORY_COLLISION_SUBGROUP,
  269. Message
  270. );
  271. if (Group) {
  272. MsgMgr_ObjectMsg_Add (TEXT("*RenameFolders"), Group, S_EMPTY);
  273. FreeText (Group);
  274. }
  275. FreeStringResource (Message);
  276. }
  277. }
  278. FreeText (NewName);
  279. }
  280. }
  281. BOOL
  282. pCheckNtDirs (
  283. VOID
  284. )
  285. /*++
  286. Routine Description:
  287. This function makes sure that there is no file with the same name as one of
  288. the NT5 directories.
  289. Arguments:
  290. none
  291. Return Value:
  292. TRUE if check was successful; FALSE if Setup was cancelled by the user
  293. --*/
  294. {
  295. MEMDB_ENUM enumDirs;
  296. GROWBUFFER msgBufRename = GROWBUF_INIT;
  297. GROWBUFFER msgBufDelete = GROWBUF_INIT;
  298. BOOL Success = TRUE;
  299. //
  300. // check first for g_ProfileDirNt
  301. //
  302. pCheckProfilesDir (&msgBufRename);
  303. if (MemDbEnumFirstValue (
  304. &enumDirs,
  305. TEXT(MEMDB_CATEGORY_NT_DIRSA)TEXT("\\*"),
  306. MEMDB_ALL_SUBLEVELS,
  307. MEMDB_ENDPOINTS_ONLY
  308. )) {
  309. do {
  310. if (!pHandleSingleDir (enumDirs.szName, &msgBufRename, &msgBufDelete)) {
  311. Success = FALSE;
  312. break;
  313. }
  314. }
  315. while (MemDbEnumNextValue (&enumDirs));
  316. }
  317. if (Success) {
  318. //
  319. // warn user about what will happen
  320. //
  321. if (msgBufDelete.Buf) {
  322. LOG ((LOG_WARNING, (PCSTR)MSG_DIR_COLLISION_DELETE_LOG, msgBufDelete.Buf));
  323. }
  324. if (msgBufRename.Buf) {
  325. LOG ((LOG_WARNING, (PCSTR)MSG_DIR_COLLISION_LOG, msgBufRename.Buf));
  326. }
  327. }
  328. FreeGrowBuffer (&msgBufDelete);
  329. FreeGrowBuffer (&msgBufRename);
  330. return Success;
  331. }
  332. DWORD
  333. CheckNtDirs (
  334. IN DWORD Request
  335. )
  336. {
  337. switch (Request) {
  338. case REQUEST_QUERYTICKS:
  339. return TICKS_CHECK_NT_DIRS;
  340. case REQUEST_RUN:
  341. if (!pCheckNtDirs ()) {
  342. return GetLastError ();
  343. }
  344. else {
  345. return ERROR_SUCCESS;
  346. }
  347. default:
  348. LOG ((LOG_ERROR, "Bad parameter while checking Nt Directories."));
  349. }
  350. return 0;
  351. }
  352. BOOL
  353. pReadSystemFixedFiles (
  354. IN OUT HASHTABLE SystemFixedFiles
  355. )
  356. /*++
  357. Routine Description:
  358. This function reads a section from Win95upg.inf with all modules that must remain in System directory.
  359. Arguments:
  360. none
  361. Return Value:
  362. TRUE if successfull, FALSE otherwise
  363. --*/
  364. {
  365. INFCONTEXT context;
  366. TCHAR fileName[MAX_TCHAR_PATH];
  367. BOOL result = TRUE;
  368. if (g_Win95UpgInf == INVALID_HANDLE_VALUE) {
  369. LOG ((LOG_ERROR, "Unable to read from WIN95UPG.INF"));
  370. SetLastError (ERROR_FILE_NOT_FOUND);
  371. return FALSE;
  372. }
  373. if (SetupFindFirstLine (g_Win95UpgInf, WINDIR_SYSTEM_FIXED_FILES, NULL, &context)) {
  374. do {
  375. if (SetupGetStringField (
  376. &context,
  377. 1,
  378. fileName,
  379. MAX_TCHAR_PATH,
  380. NULL
  381. )) {
  382. HtAddString (SystemFixedFiles, fileName);
  383. }
  384. ELSE_DEBUGMSG ((DBG_ERROR, "File name not found in %s", WINDIR_SYSTEM_FIXED_FILES));
  385. }
  386. while (SetupFindNextLine (&context, &context));
  387. }
  388. return TRUE;
  389. }
  390. BOOL
  391. pReadSystemForcedMoveFiles (
  392. VOID
  393. )
  394. /*++
  395. Routine Description:
  396. This function reads a section from Win95upg.inf with patterns for all modules that should be moved to System32 directory.
  397. Arguments:
  398. none
  399. Return Value:
  400. TRUE if successfull, FALSE otherwise
  401. --*/
  402. {
  403. INFCONTEXT context;
  404. TCHAR filePattern[MAX_TCHAR_PATH];
  405. BOOL result = TRUE;
  406. if (g_Win95UpgInf == INVALID_HANDLE_VALUE) {
  407. LOG ((LOG_ERROR, "Unable to read from WIN95UPG.INF"));
  408. SetLastError (ERROR_FILE_NOT_FOUND);
  409. return FALSE;
  410. }
  411. if (SetupFindFirstLine (g_Win95UpgInf, SYSTEM32_FORCED_MOVE, NULL, &context)) {
  412. do {
  413. if (SetupGetStringField (
  414. &context,
  415. 1,
  416. filePattern,
  417. MAX_TCHAR_PATH,
  418. NULL
  419. )) {
  420. MemDbSetValueEx (
  421. MEMDB_CATEGORY_SYSTEM32_FORCED_MOVE,
  422. filePattern,
  423. NULL,
  424. NULL,
  425. 0,
  426. NULL
  427. );
  428. }
  429. ELSE_DEBUGMSG ((DBG_ERROR, "File name not found in %s", SYSTEM32_FORCED_MOVE));
  430. }
  431. while (SetupFindNextLine (&context, &context));
  432. }
  433. return TRUE;
  434. }
  435. VOID
  436. pMarkFileForSys32Move (
  437. IN PCTSTR FileName,
  438. IN PCTSTR FullFileSpec,
  439. IN PCTSTR MovedFile,
  440. IN BOOL CheckExeType
  441. )
  442. /*++
  443. Routine Description:
  444. pMarkFileForSys32Move marks a file in %windir%\system to be moved to
  445. %windir%\system32. It takes into account all previous processing, so there
  446. is no operation collisions.
  447. Arguments:
  448. FileName - Specifies the src file name or sub-path from %windir%\system.
  449. FullFileSpec - Specifies the full path to the source file (which is
  450. supposed to be in the system dir)
  451. MovedFile - Specifies the destination path (which is supposed to be in
  452. the system32 dir)
  453. CheckExeType - Specifies TRUE if only 32-bit binaries should be moved. If TRUE
  454. and FullFileSpec does not point to a 32-bit binary, then
  455. memdb is queried for non-32-bit binaries that should be moved.
  456. Return Value:
  457. None.
  458. --*/
  459. {
  460. TCHAR key [MEMDB_MAX];
  461. //
  462. // Skip file if we already plan to move or delete it.
  463. //
  464. if (!CanSetOperation (FullFileSpec, OPERATION_FILE_MOVE)) {
  465. DEBUGMSG ((
  466. DBG_SYS32,
  467. "File already flagged for change: %s",
  468. FullFileSpec
  469. ));
  470. return;
  471. }
  472. if (!IsFileMarkedForChange (MovedFile)) {
  473. if (CheckExeType) {
  474. //
  475. // See if Win32 PE
  476. //
  477. if (GetModuleType (FullFileSpec) != W32_MODULE) {
  478. MemDbBuildKey (key, MEMDB_CATEGORY_SYSTEM32_FORCED_MOVE, FileName, NULL, NULL);
  479. if (!MemDbGetPatternValue (key, NULL)) {
  480. return;
  481. }
  482. }
  483. }
  484. } else {
  485. //
  486. // Move file during text mode because we know it is going to be
  487. // created. This allows text mode to compare versions before
  488. // overwriting.
  489. //
  490. // NOTE: We can be certain that the creation isn't from a file copy,
  491. // because we tested the source file above, and there is no
  492. // other reason why a file in system32 will be copied from
  493. // any other location than system or the NT sources.
  494. //
  495. // Also note that migration DLLs have not been processed yet.
  496. //
  497. RemoveOperationsFromPath (MovedFile, ALL_DEST_CHANGE_OPERATIONS);
  498. }
  499. //
  500. // All tests passed -- do the move
  501. //
  502. DEBUGMSG ((DBG_SYS32, "Moving %s to %s", FullFileSpec, MovedFile));
  503. MarkFileForMove (FullFileSpec, MovedFile);
  504. }
  505. BOOL
  506. pMoveSystemDir (
  507. VOID
  508. )
  509. /*++
  510. Routine Description:
  511. MoveSystemDir scans the %windir%\system directory for all 32-bit
  512. executables that are not excluded in win95upg.inf. Any matches are moved
  513. to system32.
  514. Arguments:
  515. none
  516. Return Value:
  517. TRUE if successfull, FALSE otherwise
  518. --*/
  519. {
  520. TCHAR SystemDirPattern[MAX_TCHAR_PATH];
  521. TCHAR FullFileSpec[MAX_TCHAR_PATH];
  522. TCHAR MovedFile[MAX_TCHAR_PATH];
  523. HANDLE hFind;
  524. WIN32_FIND_DATA fd;
  525. TCHAR key [MEMDB_MAX];
  526. TREE_ENUM e;
  527. PTSTR p, q;
  528. PTSTR SubPathEnd;
  529. HASHTABLE systemFixedFiles;
  530. DWORD count = 0;
  531. DEBUGMSG ((DBG_SYS32, "Begining system to system32 processing"));
  532. systemFixedFiles = HtAlloc();
  533. if (!pReadSystemFixedFiles (systemFixedFiles)) {
  534. HtFree (systemFixedFiles);
  535. return FALSE;
  536. }
  537. pReadSystemForcedMoveFiles ();
  538. //
  539. // Build the string %sysdir%\\*.*
  540. //
  541. StringCopy(SystemDirPattern, g_SystemDir);
  542. StringCat(SystemDirPattern, TEXT("\\*.*"));
  543. hFind = FindFirstFile (SystemDirPattern, &fd);
  544. if (INVALID_HANDLE_VALUE != hFind) {
  545. StringCopy (FullFileSpec, g_SystemDir);
  546. p = AppendWack (FullFileSpec);
  547. StringCopy (MovedFile, g_System32Dir);
  548. q = AppendWack (MovedFile);
  549. do {
  550. //
  551. // Reject "." and ".."
  552. //
  553. if (StringMatch(fd.cFileName, _T(".")) ||
  554. StringMatch(fd.cFileName, _T(".."))) {
  555. continue;
  556. }
  557. //
  558. // See if is on list of files that stay in system dir
  559. //
  560. if (HtFindString (systemFixedFiles, fd.cFileName)) {
  561. continue;
  562. }
  563. //
  564. // If it's a directory, see if we should move it, and if so,
  565. // move it!
  566. //
  567. if (fd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) {
  568. MemDbBuildKey (key, MEMDB_CATEGORY_SYSTEM32_FORCED_MOVE, fd.cFileName, NULL, NULL);
  569. if (!MemDbGetPatternValue (key, NULL)) {
  570. continue;
  571. }
  572. //
  573. // To move a subdir, we enumerate all files in the tree, mark
  574. // each of them for move, and then follow the normal code path
  575. // to mark the dir itself to be moved.
  576. //
  577. StringCopy (p, fd.cFileName);
  578. StringCopy (q, fd.cFileName);
  579. SubPathEnd = AppendWack (q);
  580. if (EnumFirstFileInTree (&e, FullFileSpec, NULL, FALSE)) {
  581. do {
  582. StringCopy (SubPathEnd, e.SubPath);
  583. pMarkFileForSys32Move (q, e.FullPath, MovedFile, FALSE);
  584. } while (EnumNextFileInTree (&e));
  585. }
  586. TickProgressBar ();
  587. }
  588. //
  589. // Make full file spec
  590. //
  591. StringCopy (p, fd.cFileName);
  592. StringCopy (q, fd.cFileName);
  593. pMarkFileForSys32Move (fd.cFileName, FullFileSpec, MovedFile, TRUE);
  594. count++;
  595. if (!(count % 128)) {
  596. TickProgressBar ();
  597. }
  598. } while (FindNextFile (hFind, &fd));
  599. FindClose (hFind);
  600. }
  601. HtFree (systemFixedFiles);
  602. DEBUGMSG ((DBG_SYS32, "End of system to system32 processing"));
  603. return TRUE;
  604. }
  605. DWORD
  606. MoveSystemDir (
  607. IN DWORD Request
  608. )
  609. {
  610. switch (Request) {
  611. case REQUEST_QUERYTICKS:
  612. return TICKS_MOVE_SYSTEM_DIR;
  613. case REQUEST_RUN:
  614. if (!pMoveSystemDir ()) {
  615. return GetLastError ();
  616. }
  617. else {
  618. return ERROR_SUCCESS;
  619. }
  620. default:
  621. LOG ((LOG_ERROR, "Bad parameter found while moving system directory."));
  622. }
  623. return 0;
  624. }
  625. BOOL
  626. UndoChangedFileProps (
  627. VOID
  628. )
  629. /*++
  630. Routine Description:
  631. UndoChangedFileProps enumerates all values in MEMDB_CATEGORY_CHG_FILE_PROPS and
  632. restore files to their original state (name, attributes). This function should
  633. be called when the user cancels the upgrade.
  634. Arguments:
  635. none
  636. Return Value:
  637. TRUE if all files were successfully set to their original attributes, FALSE otherwise
  638. --*/
  639. {
  640. MEMDB_ENUM e;
  641. PTSTR FileNamePart, NewName, DirNameEnd;
  642. BOOL b = TRUE;
  643. if (MemDbGetValueEx (
  644. &e,
  645. TEXT(MEMDB_CATEGORY_CHG_FILE_PROPS) TEXT("\\*"),
  646. NULL,
  647. NULL
  648. )) {
  649. do {
  650. FileNamePart = _tcsrchr (e.szName, TEXT('\\'));
  651. MYASSERT(FileNamePart);
  652. *FileNamePart = 0;
  653. FileNamePart++;
  654. DirNameEnd = _tcsrchr (e.szName, TEXT('\\'));
  655. MYASSERT(DirNameEnd);
  656. *DirNameEnd = 0;
  657. NewName = JoinPaths (e.szName, FileNamePart);
  658. *DirNameEnd = TEXT('\\');
  659. if (!SetFileAttributes (NewName, FILE_ATTRIBUTE_NORMAL) ||
  660. !MoveFile (NewName, e.szName) ||
  661. !SetFileAttributes (e.szName, e.dwValue)) {
  662. b = FALSE;
  663. }
  664. FreePathString (NewName);
  665. } while (MemDbEnumNextValue (&e));
  666. }
  667. return b;
  668. }