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.

5865 lines
140 KiB

  1. /*++
  2. Copyright (c) 1997 Microsoft Corporation
  3. Module Name:
  4. fileops.c
  5. Abstract:
  6. This file implements routines that manage the operations on files. Callers
  7. can set and remove operations on any path. The operations can have optional
  8. properties. The operation combinations and the number of properties are
  9. well-defined, so that potential collisions can be found during testing.
  10. Author:
  11. Jim Schmidt (jimschm) 18-Jul-1997
  12. Revision History:
  13. jimschm 26-Aug-1998 Redesigned!! Consolidated functionality into generic
  14. linkage: path<->operation(s)->attrib(s)
  15. jimschm 24-Aug-1998 Added shell folder support
  16. jimschm 01-May-1998 Added handled directory to GetFileStatusOnNt
  17. calinn 21-Apr-1998 added AddCompatibleShell, AddCompatibleRunKey and AddCompatibleDos
  18. calinn 02-Apr-1998 added DeclareTemporaryFile
  19. calinn 18-Jan-1998 added MigrationPhase_AddCompatibleFile
  20. turned off warning in MigrationPhase_CreateFile
  21. modified MigrationPhase_DeleteFile and MigrationPhase_MoveFile
  22. modified GetFileInfoOnNt for short file names
  23. calinn 05-Jan-1998 added IsFileMarkedForAnnounce, AnnounceFileInReport,
  24. GetFileInfoOnNt, GetFileStatusOnNt, GetPathStringOnNt
  25. --*/
  26. #include "pch.h"
  27. #define DBG_MEMDB "MemDb"
  28. #define FO_ENUM_BEGIN 0
  29. #define FO_ENUM_BEGIN_PATH_ENUM 1
  30. #define FO_ENUM_BEGIN_PROP_ENUM 2
  31. #define FO_ENUM_RETURN_PATH 3
  32. #define FO_ENUM_RETURN_DATA 4
  33. #define FO_ENUM_NEXT_PROP 5
  34. #define FO_ENUM_NEXT_PATH 6
  35. #define FO_ENUM_END 7
  36. //
  37. //140 - header for compresion file, 10 + 2 timestamp +
  38. //MAX_PATH file name in Unicode
  39. //
  40. #define STARTUP_INFORMATION_BYTES_NUMBER (140 + (sizeof(WCHAR) * MAX_PATH) + 26)
  41. #define COMPRESSION_RATE_DEFAULT 70
  42. #define BACKUP_DISK_SPACE_PADDING_DEFAULT (5<<20)
  43. #define UNKNOWN_DRIVE '?'
  44. PCWSTR g_CurrentUser = NULL;
  45. BOOL
  46. pGetPathPropertyW (
  47. IN PCWSTR FileSpec,
  48. IN DWORD Operations,
  49. IN DWORD Property,
  50. OUT PWSTR PropertyBuf OPTIONAL
  51. );
  52. BOOL
  53. pIsFileMarkedForOperationW (
  54. IN PCWSTR FileSpec,
  55. IN DWORD Operations
  56. );
  57. UINT
  58. pAddOperationToPathW (
  59. IN PCWSTR FileSpec,
  60. IN OPERATION Operation,
  61. IN BOOL Force,
  62. IN BOOL AlreadyLong
  63. );
  64. VOID
  65. pFileOpsSetPathTypeW (
  66. IN PCWSTR LongFileSpec
  67. )
  68. {
  69. WCHAR ShortFileSpec[MAX_WCHAR_PATH];
  70. WCHAR LongFileSpecCopy[MAX_WCHAR_PATH];
  71. WCHAR MixedFileSpec[MAX_WCHAR_PATH];
  72. PWSTR p;
  73. PWSTR LongStart, LongEnd;
  74. PWSTR ShortStart, ShortEnd;
  75. PWSTR MixedFileName;
  76. WCHAR ch;
  77. //
  78. // Make sure the file spec is marked as a long path
  79. //
  80. if (!pIsFileMarkedForOperationW (LongFileSpec, OPERATION_LONG_FILE_NAME)) {
  81. pAddOperationToPathW (LongFileSpec, OPERATION_LONG_FILE_NAME, FALSE, TRUE);
  82. //
  83. // Obtain the short path, and if it is different than the
  84. // long path, add an operation for it.
  85. //
  86. if (OurGetShortPathNameW (LongFileSpec, ShortFileSpec, MAX_WCHAR_PATH)) {
  87. if (!StringIMatchW (LongFileSpec, ShortFileSpec)) {
  88. //
  89. // The short and long paths differ, so record the short path.
  90. //
  91. if (!pIsFileMarkedForOperationW (ShortFileSpec, OPERATION_SHORT_FILE_NAME)) {
  92. AssociatePropertyWithPathW (
  93. ShortFileSpec,
  94. OPERATION_SHORT_FILE_NAME,
  95. LongFileSpec
  96. );
  97. }
  98. //
  99. // Make sure each short piece of the file spec is added. This
  100. // allows us to support mixed short and long paths. It is
  101. // critical that we have the long path with a short file name.
  102. //
  103. _wcssafecpy (LongFileSpecCopy, LongFileSpec, sizeof (LongFileSpecCopy));
  104. LongStart = LongFileSpecCopy;
  105. ShortStart = ShortFileSpec;
  106. MixedFileName = MixedFileSpec;
  107. while (*LongStart && *ShortStart) {
  108. LongEnd = wcschr (LongStart, L'\\');
  109. if (!LongEnd) {
  110. LongEnd = GetEndOfStringW (LongStart);
  111. }
  112. ShortEnd = wcschr (ShortStart, L'\\');
  113. if (!ShortEnd) {
  114. ShortEnd = GetEndOfStringW (ShortStart);
  115. }
  116. StringCopyABW (MixedFileName, ShortStart, ShortEnd);
  117. if (!StringIMatchABW (MixedFileName, LongStart, LongEnd)) {
  118. if (!pIsFileMarkedForOperationW (MixedFileSpec, OPERATION_SHORT_FILE_NAME)) {
  119. ch = *LongEnd;
  120. *LongEnd = 0;
  121. AssociatePropertyWithPathW (
  122. MixedFileSpec,
  123. OPERATION_SHORT_FILE_NAME,
  124. LongFileSpecCopy
  125. );
  126. *LongEnd = ch;
  127. }
  128. StringCopyABW (MixedFileName, LongStart, LongEnd);
  129. }
  130. p = MixedFileName + (LongEnd - LongStart);
  131. *p = L'\\';
  132. MixedFileName = p + 1;
  133. LongStart = LongEnd;
  134. if (*LongStart) {
  135. LongStart++;
  136. }
  137. // skip paths that have double-wacks
  138. while (*LongStart == L'\\') {
  139. LongStart++;
  140. }
  141. ShortStart = ShortEnd;
  142. if (*ShortStart) {
  143. ShortStart++;
  144. }
  145. }
  146. MYASSERT (!*LongStart && !*ShortStart);
  147. }
  148. }
  149. }
  150. }
  151. VOID
  152. pFileOpsGetLongPathW (
  153. IN PCWSTR FileSpec,
  154. OUT PWSTR LongFileSpec
  155. )
  156. {
  157. WCHAR Replacement[MEMDB_MAX];
  158. PCWSTR MixedStart, MixedEnd;
  159. PWSTR OutStr;
  160. UINT u;
  161. //
  162. // Get the short property from the long property
  163. //
  164. if (!pIsFileMarkedForOperationW (FileSpec, OPERATION_LONG_FILE_NAME)) {
  165. if (!pGetPathPropertyW (FileSpec, OPERATION_SHORT_FILE_NAME, 0, LongFileSpec)) {
  166. //
  167. // The short and long properties aren't there. Try each piece.
  168. //
  169. MixedStart = FileSpec;
  170. OutStr = LongFileSpec;
  171. while (*MixedStart) {
  172. MixedEnd = wcschr (MixedStart, L'\\');
  173. if (!MixedEnd) {
  174. MixedEnd = GetEndOfStringW (MixedStart);
  175. }
  176. if (OutStr != LongFileSpec) {
  177. *OutStr++ = L'\\';
  178. }
  179. StringCopyABW (OutStr, MixedStart, MixedEnd);
  180. if (pGetPathPropertyW (LongFileSpec, OPERATION_SHORT_FILE_NAME, 0, Replacement)) {
  181. u = OutStr - LongFileSpec;
  182. MYASSERT (StringIMatchTcharCountW (LongFileSpec, Replacement, u));
  183. StringCopyW (LongFileSpec + u, Replacement + u);
  184. }
  185. OutStr = GetEndOfStringW (OutStr);
  186. MixedStart = MixedEnd;
  187. if (*MixedStart) {
  188. MixedStart++;
  189. }
  190. }
  191. *OutStr = 0;
  192. }
  193. } else {
  194. StringCopyW (LongFileSpec, FileSpec);
  195. }
  196. }
  197. PCSTR
  198. GetSourceFileLongNameA (
  199. IN PCSTR ShortName
  200. )
  201. {
  202. PCWSTR UShortName;
  203. PCWSTR ULongName;
  204. PCSTR ALongName;
  205. PCSTR LongName;
  206. UShortName = ConvertAtoW (ShortName);
  207. ULongName = GetSourceFileLongNameW (UShortName);
  208. ALongName = ConvertWtoA (ULongName);
  209. LongName = DuplicatePathStringA (ALongName, 0);
  210. FreeConvertedStr (ALongName);
  211. FreePathString (ULongName);
  212. FreeConvertedStr (UShortName);
  213. return LongName;
  214. }
  215. PCWSTR
  216. GetSourceFileLongNameW (
  217. IN PCWSTR ShortName
  218. )
  219. {
  220. WCHAR LongName[MEMDB_MAX];
  221. pFileOpsGetLongPathW (ShortName, LongName);
  222. return (DuplicatePathStringW (LongName, 0));
  223. }
  224. PCWSTR
  225. SetCurrentUserW (
  226. PCWSTR User
  227. )
  228. {
  229. PCWSTR tempUser = g_CurrentUser;
  230. g_CurrentUser = User;
  231. return tempUser;
  232. }
  233. DWORD g_MasterSequencer = 0;
  234. #define ONEBITSET(x) ((x) && !((x) & ((x) - 1)))
  235. typedef struct {
  236. DWORD Bit;
  237. PCSTR Name;
  238. DWORD SharedOps;
  239. UINT MaxProps;
  240. } OPERATIONFLAGS, *POPERATIONFLAGS;
  241. #define UNLIMITED 0xffffffff
  242. #define DEFMAC(bit,name,memdbname,maxattribs) {bit,#memdbname,0,maxattribs},
  243. OPERATIONFLAGS g_OperationFlags[] = {
  244. PATH_OPERATIONS /* , */
  245. {0, NULL, 0, 0}
  246. };
  247. #undef DEFMAC
  248. UINT
  249. pWhichBitIsSet (
  250. OPERATION Value
  251. )
  252. {
  253. UINT Bit = 0;
  254. MYASSERT (ONEBITSET(Value));
  255. while (Value /= 2) {
  256. Bit++;
  257. }
  258. MYASSERT (Bit < 24);
  259. return Bit;
  260. }
  261. VOID
  262. pProhibitOperationCombination (
  263. IN DWORD SourceOperations,
  264. IN DWORD ProhibitedOperations
  265. )
  266. {
  267. DWORD w1, w2;
  268. OPERATION OperationA;
  269. OPERATION OperationB;
  270. for (w1 = SourceOperations ; w1 ; w1 ^= OperationA) {
  271. OperationA = w1 & (~(w1 - 1));
  272. g_OperationFlags[pWhichBitIsSet (OperationA)].SharedOps &= ~ProhibitedOperations;
  273. for (w2 = ProhibitedOperations ; w2 ; w2 ^= OperationB) {
  274. OperationB = w2 & (~(w2 - 1));
  275. g_OperationFlags[pWhichBitIsSet (OperationB)].SharedOps &= ~OperationA;
  276. }
  277. }
  278. }
  279. VOID
  280. InitOperationTable (
  281. VOID
  282. )
  283. /*++
  284. Routine Description:
  285. InitOperationsTable sets the prohibited operation mask for each operation.
  286. When an operation combination is prohibited, both operations involved have
  287. the corresponding bit cleared.
  288. Arguments:
  289. None.
  290. Return Value:
  291. None.
  292. --*/
  293. {
  294. POPERATIONFLAGS p;
  295. for (p = g_OperationFlags ; p->Name ; p++) {
  296. p->SharedOps = ALL_OPERATIONS;
  297. }
  298. //
  299. // Please try to keep this in the same order as the
  300. // macro expansion list in fileops.h. The list of
  301. // prohibited operations should get smaller as
  302. // we go.
  303. //
  304. pProhibitOperationCombination (
  305. OPERATION_FILE_DELETE,
  306. OPERATION_TEMP_PATH
  307. );
  308. pProhibitOperationCombination (
  309. OPERATION_FILE_DELETE,
  310. OPERATION_FILE_MOVE|
  311. OPERATION_FILE_MOVE_EXTERNAL|
  312. OPERATION_FILE_MOVE_SHELL_FOLDER|
  313. OPERATION_FILE_COPY|
  314. OPERATION_CLEANUP|
  315. OPERATION_MIGDLL_HANDLED|
  316. OPERATION_LINK_EDIT|
  317. OPERATION_LINK_STUB
  318. );
  319. pProhibitOperationCombination (
  320. OPERATION_FILE_DELETE_EXTERNAL,
  321. OPERATION_FILE_MOVE|
  322. OPERATION_FILE_MOVE_EXTERNAL|
  323. OPERATION_FILE_MOVE_SHELL_FOLDER|
  324. OPERATION_FILE_COPY|
  325. OPERATION_CLEANUP|
  326. OPERATION_LINK_EDIT|
  327. OPERATION_LINK_STUB
  328. );
  329. pProhibitOperationCombination (
  330. OPERATION_FILE_MOVE,
  331. OPERATION_FILE_MOVE|
  332. OPERATION_FILE_COPY|
  333. OPERATION_FILE_MOVE_EXTERNAL|
  334. OPERATION_FILE_MOVE_SHELL_FOLDER|
  335. OPERATION_FILE_MOVE_BY_NT|
  336. OPERATION_CLEANUP|
  337. OPERATION_MIGDLL_HANDLED|
  338. OPERATION_CREATE_FILE|
  339. OPERATION_TEMP_PATH
  340. );
  341. pProhibitOperationCombination (
  342. OPERATION_FILE_COPY,
  343. OPERATION_FILE_COPY|
  344. OPERATION_FILE_MOVE_EXTERNAL|
  345. OPERATION_FILE_MOVE_SHELL_FOLDER|
  346. OPERATION_CLEANUP|
  347. OPERATION_MIGDLL_HANDLED
  348. );
  349. pProhibitOperationCombination (
  350. OPERATION_FILE_MOVE_EXTERNAL,
  351. OPERATION_FILE_MOVE_EXTERNAL|
  352. OPERATION_FILE_MOVE_SHELL_FOLDER|
  353. OPERATION_FILE_MOVE_BY_NT|
  354. OPERATION_CLEANUP
  355. );
  356. pProhibitOperationCombination (
  357. OPERATION_FILE_MOVE_SHELL_FOLDER,
  358. OPERATION_FILE_MOVE_SHELL_FOLDER|
  359. OPERATION_FILE_MOVE_BY_NT|
  360. OPERATION_CLEANUP|
  361. OPERATION_MIGDLL_HANDLED|
  362. OPERATION_CREATE_FILE|
  363. OPERATION_TEMP_PATH
  364. );
  365. pProhibitOperationCombination (
  366. OPERATION_FILE_MOVE_BY_NT,
  367. OPERATION_FILE_MOVE_BY_NT
  368. );
  369. pProhibitOperationCombination (
  370. OPERATION_CLEANUP,
  371. OPERATION_MIGDLL_HANDLED|
  372. OPERATION_CREATE_FILE|
  373. OPERATION_LINK_EDIT|
  374. OPERATION_LINK_STUB
  375. );
  376. pProhibitOperationCombination (
  377. OPERATION_MIGDLL_HANDLED,
  378. OPERATION_MIGDLL_HANDLED|
  379. OPERATION_CREATE_FILE|
  380. OPERATION_LINK_EDIT|
  381. OPERATION_LINK_STUB
  382. );
  383. pProhibitOperationCombination (
  384. OPERATION_LINK_EDIT,
  385. OPERATION_LINK_EDIT
  386. );
  387. pProhibitOperationCombination (
  388. OPERATION_LINK_STUB,
  389. OPERATION_LINK_STUB
  390. );
  391. pProhibitOperationCombination (
  392. OPERATION_SHELL_FOLDER,
  393. OPERATION_SHELL_FOLDER
  394. );
  395. pProhibitOperationCombination (
  396. OPERATION_SHORT_FILE_NAME,
  397. OPERATION_SHORT_FILE_NAME
  398. );
  399. }
  400. VOID
  401. pBuildOperationCategory (
  402. IN PWSTR Node,
  403. IN UINT OperationNum
  404. )
  405. {
  406. // IMPORTANT: wsprintfW is buggy and does not always work with %hs, the use of
  407. // swprintf is intentional
  408. swprintf (Node, L"%hs", g_OperationFlags[OperationNum].Name);
  409. }
  410. VOID
  411. pBuildOperationKey (
  412. IN PWSTR Node,
  413. IN UINT OperationNum,
  414. IN UINT Sequencer
  415. )
  416. {
  417. // IMPORTANT: wsprintfW is buggy and does not always work with %hs, the use of
  418. // swprintf is intentional
  419. swprintf (Node, L"%hs\\%x", g_OperationFlags[OperationNum].Name, Sequencer);
  420. }
  421. VOID
  422. pBuildPropertyKey (
  423. IN PWSTR Node,
  424. IN UINT OperationNum,
  425. IN UINT Sequencer,
  426. IN DWORD Property
  427. )
  428. {
  429. // IMPORTANT: wsprintfW is buggy and does not always work with %hs, the use of
  430. // swprintf is intentional
  431. swprintf (Node, L"%hs\\%x\\%x", g_OperationFlags[OperationNum].Name, Sequencer, Property);
  432. }
  433. BOOL
  434. CanSetOperationA (
  435. IN PCSTR FileSpec,
  436. IN OPERATION Operation
  437. )
  438. {
  439. PCWSTR UnicodeFileSpec;
  440. BOOL result;
  441. UnicodeFileSpec = ConvertAtoW (FileSpec);
  442. result = CanSetOperationW (UnicodeFileSpec, Operation);
  443. FreeConvertedStr (UnicodeFileSpec);
  444. return result;
  445. }
  446. BOOL
  447. CanSetOperationW (
  448. IN PCWSTR FileSpec,
  449. IN OPERATION Operation
  450. )
  451. {
  452. WCHAR LongFileSpec[MEMDB_MAX];
  453. WCHAR Node[MEMDB_MAX];
  454. DWORD Flags;
  455. UINT SetBitNum;
  456. MYASSERT (ONEBITSET (Operation));
  457. pFileOpsGetLongPathW (FileSpec, LongFileSpec);
  458. //
  459. // Get existing sequencer and flags, if they exist
  460. //
  461. MemDbBuildKeyW (Node, MEMDB_CATEGORY_PATHROOTW, LongFileSpec, NULL, NULL);
  462. if (!MemDbGetValueAndFlagsW (Node, NULL, &Flags)) {
  463. return TRUE;
  464. }
  465. SetBitNum = pWhichBitIsSet (Operation);
  466. return ((Flags & g_OperationFlags[SetBitNum].SharedOps) == Flags);
  467. }
  468. BOOL
  469. pSetPathOperationW (
  470. IN PCWSTR FileSpec,
  471. OUT PDWORD Offset,
  472. OUT PUINT SequencerPtr,
  473. IN OPERATION SetBit,
  474. IN OPERATION ClrBit,
  475. IN BOOL Force
  476. )
  477. /*++
  478. Routine Description:
  479. pSetPathOperation adds the operation bit to the specified path. It also
  480. verifies that the operation combination is legal.
  481. Arguments:
  482. FileSpec - Specifies the path the operation applies to.
  483. Offset - Receives the offset of the memdb key created for the path.
  484. SequencePtr - Receives the operation sequence number, used for property
  485. linkage.
  486. SetBit - Specifies one operation bit to set.
  487. ClrBit - Specifies one operation bit to clear. Either SetBit or
  488. ClrBit can be used, but not both.
  489. Return Value:
  490. TRUE if the operation was set, FALSE otherwise.
  491. --*/
  492. {
  493. DWORD Sequencer;
  494. WCHAR Node[MEMDB_MAX];
  495. DWORD Flags;
  496. UINT SetBitNum;
  497. MYASSERT ((SetBit && !ClrBit) || (ClrBit && !SetBit));
  498. MYASSERT (ONEBITSET (SetBit | ClrBit));
  499. //
  500. // Get existing sequencer and flags, if they exist
  501. //
  502. MemDbBuildKeyW (Node, MEMDB_CATEGORY_PATHROOTW, FileSpec, NULL, NULL);
  503. if (!MemDbGetValueAndFlagsW (Node, &Sequencer, &Flags) || !Flags) {
  504. Flags = 0;
  505. if (!g_MasterSequencer && ISNT()) {
  506. if (!MemDbGetValue (
  507. MEMDB_CATEGORY_STATE TEXT("\\") MEMDB_ITEM_MASTER_SEQUENCER,
  508. &g_MasterSequencer
  509. )) {
  510. g_MasterSequencer = 1 << 24;
  511. }
  512. }
  513. g_MasterSequencer++;
  514. Sequencer = g_MasterSequencer;
  515. MYASSERT (Sequencer);
  516. }
  517. //
  518. // Is bit adjustment legal?
  519. //
  520. if (SetBit) {
  521. SetBitNum = pWhichBitIsSet (SetBit);
  522. #ifdef DEBUG
  523. {
  524. PSTR p;
  525. PCSTR DebugInfPath;
  526. CHAR DbgBuf[32];
  527. BOOL Break = FALSE;
  528. PCSTR AnsiFileSpec;
  529. DebugInfPath = JoinPathsA (g_BootDrivePathA, "debug.inf");
  530. AnsiFileSpec = ConvertWtoA (FileSpec);
  531. p = _mbsrchr (AnsiFileSpec, L'\\');
  532. p++;
  533. if (GetPrivateProfileStringA ("FileOps", AnsiFileSpec, "", DbgBuf, 32, DebugInfPath)) {
  534. Break = TRUE;
  535. } else if (GetPrivateProfileStringA ("FileOps", p, "", DbgBuf, 32, DebugInfPath)) {
  536. Break = TRUE;
  537. }
  538. if (Break) {
  539. if ((SetBit & strtoul (DbgBuf, NULL, 16)) == 0) {
  540. Break = FALSE;
  541. }
  542. }
  543. if (Break) {
  544. DEBUGMSG ((
  545. DBG_WHOOPS,
  546. "File %ls now being marked for operation %hs",
  547. FileSpec,
  548. g_OperationFlags[SetBitNum].Name
  549. ));
  550. }
  551. FreePathStringA (DebugInfPath);
  552. FreeConvertedStr (AnsiFileSpec);
  553. }
  554. #endif
  555. if (!Force) {
  556. if ((Flags & g_OperationFlags[SetBitNum].SharedOps) != Flags) {
  557. DEBUGMSG ((
  558. DBG_WHOOPS,
  559. "File %ls already marked, %hs cannot be combined with 0x%04X",
  560. FileSpec,
  561. g_OperationFlags[SetBitNum].Name,
  562. Flags
  563. ));
  564. return FALSE;
  565. }
  566. }
  567. }
  568. //
  569. // Adjust the bits
  570. //
  571. Flags |= SetBit;
  572. Flags &= ~ClrBit;
  573. //
  574. // Save
  575. //
  576. MemDbSetValueAndFlagsW (Node, Sequencer, Flags, 0);
  577. MemDbGetOffsetW (Node, Offset);
  578. *SequencerPtr = Sequencer;
  579. return TRUE;
  580. }
  581. UINT
  582. pAddOperationToPathW (
  583. IN PCWSTR FileSpec,
  584. IN OPERATION Operation,
  585. IN BOOL Force,
  586. IN BOOL AlreadyLong
  587. )
  588. /*++
  589. Routine Description:
  590. pAddOperationToPath adds an operation to a path. The caller receives a
  591. sequencer so additional properties can be added.
  592. Arguments:
  593. FileSpec - Specifies the path to add the operation to
  594. Operation - Specifies the operation to add
  595. Force - Specifies TRUE if the operation combinations should be
  596. ignored. This is only for special-case use.
  597. AlreadyLong - Specifies TRUE if FileSpec is a long path, FALSE otherwise.
  598. Return Value:
  599. A sequencer that can be used to add properties, or INVALID_SEQUENCER if an
  600. error occured.
  601. --*/
  602. {
  603. UINT OperationNum;
  604. UINT Sequencer;
  605. WCHAR Node[MEMDB_MAX];
  606. DWORD Offset;
  607. WCHAR LongFileSpec[MAX_WCHAR_PATH];
  608. if (!FileSpec || FileSpec[0] == 0) {
  609. return INVALID_SEQUENCER;
  610. }
  611. //
  612. // Make sure FileSpec is in long format and is recorded in memdb
  613. //
  614. if (Operation != OPERATION_SHORT_FILE_NAME &&
  615. Operation != OPERATION_LONG_FILE_NAME
  616. ) {
  617. if (!AlreadyLong) {
  618. MYASSERT (ISNT());
  619. if (FileSpec[0] && (FileSpec[1]==L':')) {
  620. if (OurGetLongPathNameW (FileSpec, LongFileSpec, MAX_WCHAR_PATH)) {
  621. FileSpec = LongFileSpec;
  622. }
  623. }
  624. }
  625. pFileOpsSetPathTypeW (FileSpec);
  626. }
  627. //
  628. // Create the path sequencer and set the operation bit
  629. //
  630. MYASSERT (ONEBITSET(Operation));
  631. #ifdef DEBUG
  632. Offset = INVALID_OFFSET;
  633. #endif
  634. if (!pSetPathOperationW (FileSpec, &Offset, &Sequencer, Operation, 0, Force)) {
  635. return INVALID_SEQUENCER;
  636. }
  637. MYASSERT (Offset != INVALID_OFFSET);
  638. //
  639. // Add the opereration
  640. //
  641. OperationNum = pWhichBitIsSet (Operation);
  642. pBuildOperationKey (Node, OperationNum, Sequencer);
  643. if (!MemDbGetValueW (Node, NULL)) {
  644. MemDbSetValueW (Node, Offset);
  645. }
  646. return Sequencer;
  647. }
  648. UINT
  649. AddOperationToPathA (
  650. IN PCSTR FileSpec,
  651. IN OPERATION Operation
  652. )
  653. {
  654. PCWSTR UnicodeFileSpec;
  655. UINT u;
  656. CHAR longFileSpec[MAX_MBCHAR_PATH];
  657. CopyFileSpecToLongA (FileSpec, longFileSpec);
  658. UnicodeFileSpec = ConvertAtoW (longFileSpec);
  659. u = pAddOperationToPathW (UnicodeFileSpec, Operation, FALSE, TRUE);
  660. FreeConvertedStr (UnicodeFileSpec);
  661. return u;
  662. }
  663. UINT
  664. AddOperationToPathW (
  665. IN PCWSTR FileSpec,
  666. IN OPERATION Operation
  667. )
  668. {
  669. if (!ISNT()) {
  670. #ifdef DEBUG
  671. //
  672. // If we are calling the W version on Win9x, then we know
  673. // that the path is long. Otherwise the caller must call
  674. // the A version.
  675. //
  676. {
  677. PCSTR ansiFileSpec;
  678. CHAR longFileSpec[MAX_MBCHAR_PATH];
  679. PCWSTR unicodeFileSpec;
  680. ansiFileSpec = ConvertWtoA (FileSpec);
  681. CopyFileSpecToLongA (ansiFileSpec, longFileSpec);
  682. FreeConvertedStr (ansiFileSpec);
  683. unicodeFileSpec = ConvertAtoW (longFileSpec);
  684. MYASSERT (StringIMatchW (FileSpec, unicodeFileSpec));
  685. FreeConvertedStr (unicodeFileSpec);
  686. }
  687. #endif
  688. return pAddOperationToPathW (FileSpec, Operation, FALSE, TRUE);
  689. }
  690. return pAddOperationToPathW (FileSpec, Operation, FALSE, FALSE);
  691. }
  692. UINT
  693. ForceOperationOnPathA (
  694. IN PCSTR FileSpec,
  695. IN OPERATION Operation
  696. )
  697. {
  698. PCWSTR UnicodeFileSpec;
  699. UINT u;
  700. CHAR longFileSpec[MAX_MBCHAR_PATH];
  701. CopyFileSpecToLongA (FileSpec, longFileSpec);
  702. UnicodeFileSpec = ConvertAtoW (longFileSpec);
  703. u = pAddOperationToPathW (UnicodeFileSpec, Operation, TRUE, TRUE);
  704. FreeConvertedStr (UnicodeFileSpec);
  705. return u;
  706. }
  707. UINT
  708. ForceOperationOnPathW (
  709. IN PCWSTR FileSpec,
  710. IN OPERATION Operation
  711. )
  712. /*++
  713. Routine Description:
  714. ForceOperationOnPath is used only in special cases where the caller knows
  715. that a normally prohibited operation combination is OK. This is usually
  716. because Path was somehow changed from its original state, yet the
  717. operations cannot be removed via RemoveOperationsFromPath.
  718. This function should only be used if absolutely necessary.
  719. Arguments:
  720. FileSpec - Specifies the path to add the operation to.
  721. Operation - Specifies the single operation to add to the path.
  722. Return Value:
  723. A sequencer that can be used to add properties to the path.
  724. --*/
  725. {
  726. return pAddOperationToPathW (FileSpec, Operation, TRUE, FALSE);
  727. }
  728. BOOL
  729. AddPropertyToPathExA (
  730. IN UINT Sequencer,
  731. IN OPERATION Operation,
  732. IN PCSTR Property,
  733. IN PCSTR AlternateDataSection OPTIONAL
  734. )
  735. {
  736. PCWSTR UnicodeProperty;
  737. PCWSTR UnicodeAlternateDataSection;
  738. BOOL b;
  739. UnicodeProperty = ConvertAtoW (Property);
  740. UnicodeAlternateDataSection = ConvertAtoW (AlternateDataSection);
  741. b = AddPropertyToPathExW (
  742. Sequencer,
  743. Operation,
  744. UnicodeProperty,
  745. UnicodeAlternateDataSection
  746. );
  747. FreeConvertedStr (UnicodeProperty);
  748. FreeConvertedStr (UnicodeAlternateDataSection);
  749. return b;
  750. }
  751. BOOL
  752. AddPropertyToPathExW (
  753. IN UINT Sequencer,
  754. IN OPERATION Operation,
  755. IN PCWSTR Property,
  756. IN PCWSTR AlternateDataSection OPTIONAL
  757. )
  758. {
  759. /*++
  760. Routine Description:
  761. AddPropertyToPathEx adds an operation to a path, and then adds a property.
  762. The caller can also specify an alternate data section (for special-case
  763. uses).
  764. Arguments:
  765. Sequencer - Specifies the sequencer of the path to add
  766. operations and properties to
  767. Operation - Specifies the operation to add
  768. Property - Specfieis the property data to add
  769. AlternateDataSection - Specifies an alternate memdb root for the property
  770. data
  771. Return Value:
  772. TRUE if the operation was added, FALSE otherwise.
  773. --*/
  774. DWORD DataOffset;
  775. WCHAR Node[MEMDB_MAX];
  776. UINT OperationNum;
  777. DWORD UniqueId;
  778. DWORD PathOffset;
  779. DWORD DataValue;
  780. DWORD DataFlags;
  781. //
  782. // Verify the sequencer and operation are valid
  783. //
  784. OperationNum = pWhichBitIsSet (Operation);
  785. pBuildOperationKey (Node, OperationNum, Sequencer);
  786. if (!MemDbGetValueAndFlagsW (Node, &PathOffset, &UniqueId)) {
  787. DEBUGMSG ((DBG_WHOOPS, "Can't set property on non-existent operation"));
  788. return FALSE;
  789. }
  790. //
  791. // Can this operation have another property?
  792. //
  793. if (UniqueId == g_OperationFlags[OperationNum].MaxProps) {
  794. DEBUGMSG ((
  795. DBG_WHOOPS,
  796. "Maximum properties specified for %hs (property %ls)",
  797. g_OperationFlags[OperationNum].Name,
  798. Property
  799. ));
  800. return FALSE;
  801. }
  802. //
  803. // Increment the unique ID
  804. //
  805. MemDbSetValueAndFlagsW (Node, PathOffset, (DWORD) (UniqueId + 1), 0);
  806. //
  807. // Get the existing data value and flags, preserving them
  808. // if they exist
  809. //
  810. if (!AlternateDataSection) {
  811. AlternateDataSection = MEMDB_CATEGORY_DATAW;
  812. }
  813. swprintf (Node, L"%s\\%s", AlternateDataSection, Property);
  814. if (!MemDbGetValueAndFlagsW (Node, &DataValue, &DataFlags)) {
  815. DataValue = 0;
  816. DataFlags = 0;
  817. }
  818. //
  819. // Write the data section node and get the offset
  820. //
  821. MemDbSetValueAndFlagsW (Node, DataValue, DataFlags, 0);
  822. MemDbGetOffsetW (Node, &DataOffset);
  823. //
  824. // Write the operation node
  825. //
  826. pBuildPropertyKey (Node, OperationNum, Sequencer, UniqueId);
  827. MemDbSetValueW (Node, DataOffset);
  828. return TRUE;
  829. }
  830. BOOL
  831. pAssociatePropertyWithPathW (
  832. IN PCWSTR FileSpec,
  833. IN OPERATION Operation,
  834. IN PCWSTR Property,
  835. IN BOOL AlreadyLong
  836. )
  837. /*++
  838. Routine Description:
  839. AssociatePropertyWithPath adds a property to a path operation. The maximum
  840. property count is enforced.
  841. Arguments:
  842. FileSpec - Specifies the path to add an operation and property
  843. Operation - Specifies the operation to add
  844. Property - Specifies the property data to associate with FileSpec
  845. AlreadyLong - Specifies TRUE if FileSpec is a long path name, FALSE otherwise
  846. Return Value:
  847. TRUE if the operation and property was added, FALSE otherwise. It is possible
  848. that the operation will be added but the property will not.
  849. --*/
  850. {
  851. UINT Sequencer;
  852. Sequencer = pAddOperationToPathW (FileSpec, Operation, FALSE, AlreadyLong);
  853. if (Sequencer == INVALID_SEQUENCER) {
  854. DEBUGMSG ((DBG_WHOOPS, "Can't associate %s with %s", Property, FileSpec));
  855. return FALSE;
  856. }
  857. //
  858. // BUGBUG - When the below fails, we need to reverse the pAddOperationToPathW
  859. // call above
  860. //
  861. return AddPropertyToPathExW (Sequencer, Operation, Property, NULL);
  862. }
  863. BOOL
  864. AssociatePropertyWithPathA (
  865. IN PCSTR FileSpec,
  866. IN OPERATION Operation,
  867. IN PCSTR Property
  868. )
  869. {
  870. PCWSTR UnicodeFileSpec;
  871. PCWSTR UnicodeProperty;
  872. BOOL b;
  873. CHAR longFileSpec[MAX_MBCHAR_PATH];
  874. CopyFileSpecToLongA (FileSpec, longFileSpec);
  875. UnicodeFileSpec = ConvertAtoW (longFileSpec);
  876. UnicodeProperty = ConvertAtoW (Property);
  877. b = pAssociatePropertyWithPathW (UnicodeFileSpec, Operation, UnicodeProperty, TRUE);
  878. FreeConvertedStr (UnicodeFileSpec);
  879. FreeConvertedStr (UnicodeProperty);
  880. return b;
  881. }
  882. BOOL
  883. AssociatePropertyWithPathW (
  884. IN PCWSTR FileSpec,
  885. IN OPERATION Operation,
  886. IN PCWSTR Property
  887. )
  888. {
  889. return pAssociatePropertyWithPathW (FileSpec, Operation, Property, FALSE);
  890. }
  891. UINT
  892. GetSequencerFromPathA (
  893. IN PCSTR FileSpec
  894. )
  895. {
  896. PCWSTR UnicodeFileSpec;
  897. UINT u;
  898. UnicodeFileSpec = ConvertAtoW (FileSpec);
  899. u = GetSequencerFromPathW (UnicodeFileSpec);
  900. FreeConvertedStr (UnicodeFileSpec);
  901. return u;
  902. }
  903. UINT
  904. GetSequencerFromPathW (
  905. IN PCWSTR FileSpec
  906. )
  907. /*++
  908. Routine Description:
  909. GetSequencerFromPath returns the sequencer for a particular path. The path
  910. must have at least one operation.
  911. Arguments:
  912. FileSpec - Specifies the path to get the sequencer for.
  913. Return Value:
  914. The sequencer for the path, or INVALID_SEQUENCER if there are no operationf
  915. for the path.
  916. --*/
  917. {
  918. WCHAR LongFileSpec[MEMDB_MAX];
  919. WCHAR Node[MEMDB_MAX];
  920. DWORD Sequencer;
  921. pFileOpsGetLongPathW (FileSpec, LongFileSpec);
  922. MemDbBuildKeyW (Node, MEMDB_CATEGORY_PATHROOTW, LongFileSpec, NULL, NULL);
  923. if (!MemDbGetValueW (Node, &Sequencer)) {
  924. return INVALID_SEQUENCER;
  925. }
  926. return (UINT) Sequencer;
  927. }
  928. BOOL
  929. GetPathFromSequencerA (
  930. IN UINT Sequencer,
  931. OUT PSTR PathBuf
  932. )
  933. {
  934. WCHAR UnicodePathBuf[MAX_WCHAR_PATH];
  935. BOOL b;
  936. b = GetPathFromSequencerW (Sequencer, UnicodePathBuf);
  937. if (b) {
  938. KnownSizeWtoA (PathBuf, UnicodePathBuf);
  939. }
  940. return b;
  941. }
  942. BOOL
  943. GetPathFromSequencerW (
  944. IN UINT Sequencer,
  945. OUT PWSTR PathBuf
  946. )
  947. /*++
  948. Routine Description:
  949. GetPathFromSequencer returns the path from the specified sequencer.
  950. Arguments:
  951. Sequencer - Specifies the sequencer of the path.
  952. PathBuf - Receives the path. The caller must make sure the buffer is big
  953. enough for the path.
  954. Return Value:
  955. TRUE if the path was copied to PathBuf, FALSE otherwise.
  956. --*/
  957. {
  958. WCHAR Node[MEMDB_MAX];
  959. DWORD PathOffset = 0;
  960. DWORD w;
  961. UINT u;
  962. BOOL b = FALSE;
  963. //
  964. // Search all operations for sequencer
  965. //
  966. for (w = 1, u = 0 ; g_OperationFlags[u].Name ; w <<= 1, u++) {
  967. pBuildOperationKey (Node, u, Sequencer);
  968. if (MemDbGetValueW (Node, &PathOffset)) {
  969. break;
  970. }
  971. }
  972. //
  973. // For the first match found, use the offset to find the path
  974. //
  975. if (w) {
  976. b = MemDbBuildKeyFromOffsetW (PathOffset, PathBuf, 1, NULL);
  977. }
  978. return b;
  979. }
  980. VOID
  981. RemoveOperationsFromSequencer (
  982. IN UINT Sequencer,
  983. IN DWORD Operations
  984. )
  985. /*++
  986. Routine Description:
  987. RemoveOperationsFromSequencer removes all operation bits from the specified
  988. path. It does not however remove the properties; they become abandoned.
  989. Arguments:
  990. Sequencer - Specifies the sequencer for the path to remove operations from
  991. Operations - Specifies one or more operations to remove
  992. Return Value:
  993. None.
  994. --*/
  995. {
  996. WCHAR Node[MEMDB_MAX];
  997. UINT u;
  998. DWORD PathOffset;
  999. DWORD PathSequencer;
  1000. for (u = 0 ; g_OperationFlags[u].Name ; u++) {
  1001. if (!(Operations & g_OperationFlags[u].Bit)) {
  1002. continue;
  1003. }
  1004. pBuildOperationKey (Node, u, Sequencer);
  1005. if (MemDbGetValueW (Node, &PathOffset)) {
  1006. //
  1007. // Delete linkage from operation to properties
  1008. //
  1009. MemDbDeleteTreeW (Node);
  1010. //
  1011. // Remove operation bits
  1012. //
  1013. MemDbBuildKeyFromOffsetExW (
  1014. PathOffset,
  1015. Node,
  1016. NULL,
  1017. 0,
  1018. &PathSequencer,
  1019. NULL
  1020. );
  1021. MYASSERT (PathSequencer == Sequencer);
  1022. MemDbSetValueAndFlagsW (Node, PathSequencer, 0, Operations);
  1023. }
  1024. }
  1025. }
  1026. VOID
  1027. RemoveOperationsFromPathA (
  1028. IN PCSTR FileSpec,
  1029. IN DWORD Operations
  1030. )
  1031. {
  1032. PCWSTR UnicodeFileSpec;
  1033. UnicodeFileSpec = ConvertAtoW (FileSpec);
  1034. RemoveOperationsFromPathW (UnicodeFileSpec, Operations);
  1035. FreeConvertedStr (UnicodeFileSpec);
  1036. }
  1037. VOID
  1038. RemoveOperationsFromPathW (
  1039. IN PCWSTR FileSpec,
  1040. IN DWORD Operations
  1041. )
  1042. {
  1043. UINT Sequencer;
  1044. Sequencer = GetSequencerFromPathW (FileSpec);
  1045. if (Sequencer != INVALID_SEQUENCER) {
  1046. RemoveOperationsFromSequencer (Sequencer, Operations);
  1047. }
  1048. }
  1049. BOOL
  1050. IsFileMarkedForOperationA (
  1051. IN PCSTR FileSpec,
  1052. IN DWORD Operations
  1053. )
  1054. {
  1055. PCWSTR UnicodeFileSpec;
  1056. BOOL b;
  1057. UnicodeFileSpec = ConvertAtoW (FileSpec);
  1058. b = IsFileMarkedForOperationW (UnicodeFileSpec, Operations);
  1059. FreeConvertedStr (UnicodeFileSpec);
  1060. return b;
  1061. }
  1062. BOOL
  1063. IsFileMarkedForOperationW (
  1064. IN PCWSTR FileSpec,
  1065. IN DWORD Operations
  1066. )
  1067. /*++
  1068. Routine Description:
  1069. IsFileMarkedForOperation tests a path for one or more operations.
  1070. Arguments:
  1071. FileSpec - Specifies the path to test
  1072. Operations - Specifies one or more operations to test for.
  1073. Return Value:
  1074. TRUE if at least one operation from Operations is set on FileSpec, FALSE
  1075. otherwise.
  1076. --*/
  1077. {
  1078. WCHAR LongFileSpec [MEMDB_MAX];
  1079. DWORD Flags;
  1080. WCHAR Node[MEMDB_MAX];
  1081. pFileOpsGetLongPathW (FileSpec, LongFileSpec);
  1082. MemDbBuildKeyW (Node, MEMDB_CATEGORY_PATHROOTW, LongFileSpec, NULL, NULL);
  1083. if (MemDbGetValueAndFlagsW (Node, NULL, &Flags)) {
  1084. return (Flags & Operations) != 0;
  1085. }
  1086. return FALSE;
  1087. }
  1088. BOOL
  1089. pIsFileMarkedForOperationW (
  1090. IN PCWSTR FileSpec,
  1091. IN DWORD Operations
  1092. )
  1093. /*++
  1094. Routine Description:
  1095. pIsFileMarkedForOperation tests a path for one or more operations.
  1096. It does not convert short paths to long paths
  1097. Arguments:
  1098. FileSpec - Specifies the path to test
  1099. Operations - Specifies one or more operations to test for.
  1100. Return Value:
  1101. TRUE if at least one operation from Operations is set on FileSpec, FALSE
  1102. otherwise.
  1103. --*/
  1104. {
  1105. DWORD Flags;
  1106. WCHAR Node[MEMDB_MAX];
  1107. MemDbBuildKeyW (Node, MEMDB_CATEGORY_PATHROOTW, FileSpec, NULL, NULL);
  1108. if (MemDbGetValueAndFlagsW (Node, NULL, &Flags)) {
  1109. return (Flags & Operations) != 0;
  1110. }
  1111. return FALSE;
  1112. }
  1113. BOOL
  1114. IsFileMarkedInDataA (
  1115. IN PCSTR FileSpec
  1116. )
  1117. {
  1118. PCWSTR UnicodeFileSpec;
  1119. BOOL b;
  1120. UnicodeFileSpec = ConvertAtoW (FileSpec);
  1121. b = IsFileMarkedInDataW (UnicodeFileSpec);
  1122. FreeConvertedStr (UnicodeFileSpec);
  1123. return b;
  1124. }
  1125. BOOL
  1126. IsFileMarkedInDataW (
  1127. IN PCWSTR FileSpec
  1128. )
  1129. /*++
  1130. Routine Description:
  1131. IsFileMarkedInData tests the common property data section for FileSpec.
  1132. Arguments:
  1133. FileSpec - Specifies the path to test. This may also be any arbitrary
  1134. property value.
  1135. Return Value:
  1136. TRUE if FileSpec is a property of some operation, FALSE otherwise.
  1137. --*/
  1138. {
  1139. WCHAR Node[MEMDB_MAX];
  1140. MemDbBuildKeyW (Node, MEMDB_CATEGORY_DATAW, FileSpec, NULL, NULL);
  1141. return MemDbGetValueW (Node, NULL);
  1142. }
  1143. DWORD
  1144. GetPathPropertyOffset (
  1145. IN UINT Sequencer,
  1146. IN OPERATION Operation,
  1147. IN DWORD Property
  1148. )
  1149. /*++
  1150. Routine Description:
  1151. GetPathPropertyOffset returns the MemDb offset to the specified property.
  1152. Arguments:
  1153. Sequencer - Specifies the path sequencer
  1154. Operation - Specifies the operation the property is associated with
  1155. Property - Specifies the property index
  1156. Return Value:
  1157. The MemDb offset to the property data, or INVALID_OFFSET.
  1158. --*/
  1159. {
  1160. WCHAR Node[MEMDB_MAX];
  1161. DWORD Offset;
  1162. UINT OperationNum;
  1163. OperationNum = pWhichBitIsSet (Operation);
  1164. pBuildPropertyKey (Node, OperationNum, Sequencer, Property);
  1165. if (MemDbGetValueW (Node, &Offset)) {
  1166. return Offset;
  1167. }
  1168. return INVALID_OFFSET;
  1169. }
  1170. DWORD
  1171. GetOperationsOnPathA (
  1172. IN PCSTR FileSpec
  1173. )
  1174. {
  1175. PCWSTR UnicodeFileSpec;
  1176. DWORD w;
  1177. UnicodeFileSpec = ConvertAtoW (FileSpec);
  1178. w = GetOperationsOnPathW (UnicodeFileSpec);
  1179. FreeConvertedStr (UnicodeFileSpec);
  1180. return w;
  1181. }
  1182. DWORD
  1183. GetOperationsOnPathW (
  1184. IN PCWSTR FileSpec
  1185. )
  1186. /*++
  1187. Routine Description:
  1188. GetOperationsOnPath returns the operation flags for a path.
  1189. Arguments:
  1190. FileSpec - Specifies the path to return operations for
  1191. Return Value:
  1192. The operation bits for FileSpec
  1193. --*/
  1194. {
  1195. WCHAR LongFileSpec [MEMDB_MAX];
  1196. DWORD Operations;
  1197. WCHAR Node[MEMDB_MAX];
  1198. pFileOpsGetLongPathW (FileSpec, LongFileSpec);
  1199. MemDbBuildKeyW (Node, MEMDB_CATEGORY_PATHROOTW, LongFileSpec, NULL, NULL);
  1200. if (MemDbGetValueAndFlagsW (Node, NULL, &Operations)) {
  1201. return Operations;
  1202. }
  1203. return 0;
  1204. }
  1205. BOOL
  1206. GetPathPropertyA (
  1207. IN PCSTR FileSpec,
  1208. IN DWORD Operations,
  1209. IN DWORD Property,
  1210. OUT PSTR PropertyBuf OPTIONAL
  1211. )
  1212. {
  1213. PCWSTR UnicodeFileSpec;
  1214. BOOL b;
  1215. WCHAR UnicodeProperty[MEMDB_MAX];
  1216. UnicodeFileSpec = ConvertAtoW (FileSpec);
  1217. b = GetPathPropertyW (
  1218. UnicodeFileSpec,
  1219. Operations,
  1220. Property,
  1221. PropertyBuf ? UnicodeProperty : NULL
  1222. );
  1223. FreeConvertedStr (UnicodeFileSpec);
  1224. if (b && PropertyBuf) {
  1225. KnownSizeWtoA (PropertyBuf, UnicodeProperty);
  1226. }
  1227. return b;
  1228. }
  1229. BOOL
  1230. pGetPathPropertyW (
  1231. IN PCWSTR FileSpec,
  1232. IN DWORD Operations,
  1233. IN DWORD Property,
  1234. OUT PWSTR PropertyBuf OPTIONAL
  1235. )
  1236. /*++
  1237. Routine Description:
  1238. pGetPathProperty obtains a specific property for a path.
  1239. Arguments:
  1240. FileSpec - Specifies the path the property is associated with
  1241. Operations - Specifies the operation flags to search. The function will
  1242. return the first property to match.
  1243. Property - Specifies the property index
  1244. ProperyBuf - Receives the property data
  1245. Return Value:
  1246. TRUE if a property was copied to PropertyBuf, FALSE otherwise.
  1247. --*/
  1248. {
  1249. WCHAR Node[MEMDB_MAX];
  1250. DWORD Sequencer;
  1251. DWORD Flags;
  1252. DWORD Operation;
  1253. DWORD PropertyOffset;
  1254. BOOL b = FALSE;
  1255. //
  1256. // Make sure operation is specified for FileSpec, then return
  1257. // the property requested.
  1258. //
  1259. MemDbBuildKeyW (Node, MEMDB_CATEGORY_PATHROOTW, FileSpec, NULL, NULL);
  1260. if (MemDbGetValueAndFlagsW (Node, &Sequencer, &Flags)) {
  1261. Flags &= Operations;
  1262. if (Flags) {
  1263. Operation = Flags & (~(Flags - 1));
  1264. MYASSERT (ONEBITSET (Operation));
  1265. PropertyOffset = GetPathPropertyOffset (Sequencer, Operation, Property);
  1266. if (PropertyOffset != INVALID_OFFSET) {
  1267. if (PropertyBuf) {
  1268. b = MemDbBuildKeyFromOffsetW (PropertyOffset, PropertyBuf, 1, NULL);
  1269. } else {
  1270. b = TRUE;
  1271. }
  1272. }
  1273. }
  1274. }
  1275. return b;
  1276. }
  1277. BOOL
  1278. GetPathPropertyW (
  1279. IN PCWSTR FileSpec,
  1280. IN DWORD Operations,
  1281. IN DWORD Property,
  1282. OUT PWSTR PropertyBuf OPTIONAL
  1283. )
  1284. /*++
  1285. Routine Description:
  1286. GetPathProperty obtains a specific property for a path.
  1287. Arguments:
  1288. FileSpec - Specifies the path the property is associated with
  1289. Operations - Specifies the operation flags to search. The function will
  1290. return the first property to match.
  1291. Property - Specifies the property index
  1292. ProperyBuf - Receives the property data
  1293. Return Value:
  1294. TRUE if a property was copied to PropertyBuf, FALSE otherwise.
  1295. --*/
  1296. {
  1297. WCHAR LongFileSpec[MEMDB_MAX];
  1298. MYASSERT (!(Operations & OPERATION_SHORT_FILE_NAME));
  1299. pFileOpsGetLongPathW (FileSpec, LongFileSpec);
  1300. return pGetPathPropertyW (LongFileSpec, Operations, Property, PropertyBuf);
  1301. }
  1302. BOOL
  1303. pEnumFirstPathInOperationWorker (
  1304. IN OUT PMEMDB_ENUMW EnumPtr,
  1305. OUT PWSTR EnumPath,
  1306. OUT PDWORD Sequencer,
  1307. IN OPERATION Operation
  1308. )
  1309. {
  1310. WCHAR Node[MEMDB_MAX];
  1311. UINT OperationNum;
  1312. BOOL b;
  1313. OperationNum = pWhichBitIsSet (Operation);
  1314. pBuildOperationCategory (Node, OperationNum);
  1315. StringCopyW (AppendWack (Node), L"*");
  1316. b = MemDbEnumFirstValueW (EnumPtr, Node, MEMDB_THIS_LEVEL_ONLY, MEMDB_ENDPOINTS_ONLY);
  1317. if (b) {
  1318. MemDbBuildKeyFromOffsetW (EnumPtr->dwValue, EnumPath, 1, Sequencer);
  1319. }
  1320. return b;
  1321. }
  1322. BOOL
  1323. pEnumNextFileOpOrProperty (
  1324. IN OUT PMEMDB_ENUMW EnumPtr,
  1325. OUT PWSTR EnumPathOrData,
  1326. OUT PWSTR PropertyName, OPTIONAL
  1327. OUT PDWORD Sequencer OPTIONAL
  1328. )
  1329. {
  1330. BOOL b;
  1331. WCHAR Temp[MEMDB_MAX];
  1332. PWSTR p;
  1333. b = MemDbEnumNextValueW (EnumPtr);
  1334. if (b) {
  1335. if (PropertyName) {
  1336. MemDbBuildKeyFromOffsetW (EnumPtr->dwValue, Temp, 0, Sequencer);
  1337. p = wcschr (Temp, L'\\');
  1338. if (!p) {
  1339. p = GetEndOfStringW (Temp);
  1340. }
  1341. StringCopyABW (PropertyName, Temp, p);
  1342. if (*p) {
  1343. p++;
  1344. }
  1345. StringCopyW (EnumPathOrData, p);
  1346. } else {
  1347. MemDbBuildKeyFromOffsetW (EnumPtr->dwValue, EnumPathOrData, 1, Sequencer);
  1348. }
  1349. }
  1350. return b;
  1351. }
  1352. BOOL
  1353. EnumFirstPathInOperationA (
  1354. OUT PFILEOP_ENUMA EnumPtr,
  1355. IN OPERATION Operation
  1356. )
  1357. {
  1358. BOOL b;
  1359. WCHAR EnumPath[MAX_WCHAR_PATH];
  1360. ZeroMemory (EnumPtr, sizeof (FILEOP_ENUMA));
  1361. b = pEnumFirstPathInOperationWorker (
  1362. &EnumPtr->MemDbEnum,
  1363. EnumPath,
  1364. &EnumPtr->Sequencer,
  1365. Operation
  1366. );
  1367. if (b) {
  1368. KnownSizeWtoA (EnumPtr->Path, EnumPath);
  1369. }
  1370. return b;
  1371. }
  1372. BOOL
  1373. EnumFirstPathInOperationW (
  1374. OUT PFILEOP_ENUMW EnumPtr,
  1375. IN OPERATION Operation
  1376. )
  1377. /*++
  1378. Routine Description:
  1379. EnumFirstPathInOperation begins an enumeration of all paths for a
  1380. particular operation.
  1381. Arguments:
  1382. EnumPtr - Receives the first enumerated item.
  1383. Operation - Specifies the operation to enumerate.
  1384. Return Value:
  1385. TRUE if a path was enumerated, or FALSE if the operation is not applied to
  1386. any path.
  1387. --*/
  1388. {
  1389. ZeroMemory (EnumPtr, sizeof (FILEOP_ENUMW));
  1390. return pEnumFirstPathInOperationWorker (
  1391. &EnumPtr->MemDbEnum,
  1392. EnumPtr->Path,
  1393. &EnumPtr->Sequencer,
  1394. Operation
  1395. );
  1396. }
  1397. BOOL
  1398. EnumNextPathInOperationA (
  1399. IN OUT PFILEOP_ENUMA EnumPtr
  1400. )
  1401. {
  1402. BOOL b;
  1403. WCHAR EnumPath[MAX_WCHAR_PATH];
  1404. b = pEnumNextFileOpOrProperty (
  1405. &EnumPtr->MemDbEnum,
  1406. EnumPath,
  1407. NULL,
  1408. &EnumPtr->Sequencer
  1409. );
  1410. if (b) {
  1411. KnownSizeWtoA (EnumPtr->Path, EnumPath);
  1412. }
  1413. return b;
  1414. }
  1415. BOOL
  1416. EnumNextPathInOperationW (
  1417. IN OUT PFILEOP_ENUMW EnumPtr
  1418. )
  1419. {
  1420. return pEnumNextFileOpOrProperty (
  1421. &EnumPtr->MemDbEnum,
  1422. EnumPtr->Path,
  1423. NULL,
  1424. &EnumPtr->Sequencer
  1425. );
  1426. }
  1427. BOOL
  1428. pEnumFirstPropertyWorker (
  1429. IN OUT PMEMDB_ENUMW EnumPtr,
  1430. OUT PWSTR EnumData,
  1431. OUT PWSTR PropertyName,
  1432. IN UINT Sequencer,
  1433. IN OPERATION Operation
  1434. )
  1435. {
  1436. WCHAR Node[MEMDB_MAX];
  1437. PWSTR p;
  1438. UINT OperationNum;
  1439. BOOL b;
  1440. OperationNum = pWhichBitIsSet (Operation);
  1441. pBuildOperationKey (Node, OperationNum, Sequencer);
  1442. StringCopyW (AppendWack (Node), L"*");
  1443. b = MemDbEnumFirstValueW (EnumPtr, Node, MEMDB_THIS_LEVEL_ONLY, MEMDB_ENDPOINTS_ONLY);
  1444. if (b) {
  1445. MemDbBuildKeyFromOffsetW (EnumPtr->dwValue, Node, 0, NULL);
  1446. p = wcschr (Node, L'\\');
  1447. if (!p) {
  1448. p = GetEndOfStringW (Node);
  1449. }
  1450. StringCopyABW (PropertyName, Node, p);
  1451. if (*p) {
  1452. p++;
  1453. }
  1454. StringCopyW (EnumData, p);
  1455. }
  1456. return b;
  1457. }
  1458. BOOL
  1459. EnumFirstFileOpPropertyA (
  1460. OUT PFILEOP_PROP_ENUMA EnumPtr,
  1461. IN UINT Sequencer,
  1462. IN OPERATION Operation
  1463. )
  1464. {
  1465. BOOL b;
  1466. WCHAR EnumData[MEMDB_MAX];
  1467. WCHAR PropertyName[MEMDB_MAX];
  1468. ZeroMemory (EnumPtr, sizeof (FILEOP_PROP_ENUMA));
  1469. b = pEnumFirstPropertyWorker (
  1470. &EnumPtr->MemDbEnum,
  1471. EnumData,
  1472. PropertyName,
  1473. Sequencer,
  1474. Operation
  1475. );
  1476. if (b) {
  1477. KnownSizeWtoA (EnumPtr->Property, EnumData);
  1478. KnownSizeWtoA (EnumPtr->PropertyName, PropertyName);
  1479. }
  1480. return b;
  1481. }
  1482. BOOL
  1483. EnumFirstFileOpPropertyW (
  1484. OUT PFILEOP_PROP_ENUMW EnumPtr,
  1485. IN UINT Sequencer,
  1486. IN OPERATION Operation
  1487. )
  1488. /*++
  1489. Routine Description:
  1490. EnumFirstFileOpProperty enumerates the first property associated with an
  1491. operation on a specific path.
  1492. Arguments:
  1493. EnumPtr - Receives the enumerated item data
  1494. Sequencer - Specifies the sequencer of the path to enumerate
  1495. Operation - Specifies the operation to enumerate
  1496. Return Value:
  1497. TRUE if a property was enumerated, or FALSE if the path and operation does
  1498. not have any properties.
  1499. --*/
  1500. {
  1501. ZeroMemory (EnumPtr, sizeof (FILEOP_PROP_ENUMW));
  1502. return pEnumFirstPropertyWorker (
  1503. &EnumPtr->MemDbEnum,
  1504. EnumPtr->Property,
  1505. EnumPtr->PropertyName,
  1506. Sequencer,
  1507. Operation
  1508. );
  1509. }
  1510. BOOL
  1511. EnumNextFileOpPropertyA (
  1512. IN OUT PFILEOP_PROP_ENUMA EnumPtr
  1513. )
  1514. {
  1515. BOOL b;
  1516. WCHAR EnumData[MEMDB_MAX];
  1517. WCHAR PropertyName[MEMDB_MAX];
  1518. b = pEnumNextFileOpOrProperty (
  1519. &EnumPtr->MemDbEnum,
  1520. EnumData,
  1521. PropertyName,
  1522. NULL
  1523. );
  1524. if (b) {
  1525. KnownSizeWtoA (EnumPtr->Property, EnumData);
  1526. KnownSizeWtoA (EnumPtr->PropertyName, PropertyName);
  1527. }
  1528. return b;
  1529. }
  1530. BOOL
  1531. EnumNextFileOpPropertyW (
  1532. IN OUT PFILEOP_PROP_ENUMW EnumPtr
  1533. )
  1534. {
  1535. return pEnumNextFileOpOrProperty (
  1536. &EnumPtr->MemDbEnum,
  1537. EnumPtr->Property,
  1538. EnumPtr->PropertyName,
  1539. NULL
  1540. );
  1541. }
  1542. BOOL
  1543. pEnumFileOpWorkerA (
  1544. IN OUT PALL_FILEOPS_ENUMA EnumPtr
  1545. )
  1546. {
  1547. //
  1548. // Transfer UNICODE results to enum struct
  1549. //
  1550. KnownSizeWtoA (EnumPtr->Path, EnumPtr->Enum.Path);
  1551. KnownSizeWtoA (EnumPtr->Property, EnumPtr->Enum.Property);
  1552. EnumPtr->Sequencer = EnumPtr->Enum.Sequencer;
  1553. EnumPtr->PropertyNum = EnumPtr->Enum.PropertyNum;
  1554. EnumPtr->CurrentOperation = EnumPtr->Enum.CurrentOperation;
  1555. EnumPtr->PropertyValid = EnumPtr->Enum.PropertyValid;
  1556. return TRUE;
  1557. }
  1558. BOOL
  1559. EnumFirstFileOpA (
  1560. OUT PALL_FILEOPS_ENUMA EnumPtr,
  1561. IN DWORD Operations,
  1562. IN PCSTR FileSpec OPTIONAL
  1563. )
  1564. {
  1565. BOOL b;
  1566. PCWSTR UnicodeFileSpec;
  1567. if (FileSpec) {
  1568. UnicodeFileSpec = ConvertAtoW (FileSpec);
  1569. } else {
  1570. UnicodeFileSpec = NULL;
  1571. }
  1572. b = EnumFirstFileOpW (&EnumPtr->Enum, Operations, UnicodeFileSpec);
  1573. if (UnicodeFileSpec) {
  1574. FreeConvertedStr (UnicodeFileSpec);
  1575. }
  1576. if (b) {
  1577. return pEnumFileOpWorkerA (EnumPtr);
  1578. }
  1579. return FALSE;
  1580. }
  1581. BOOL
  1582. EnumFirstFileOpW (
  1583. OUT PALL_FILEOPS_ENUMW EnumPtr,
  1584. IN DWORD Operations,
  1585. IN PCWSTR FileSpec OPTIONAL
  1586. )
  1587. /*++
  1588. Routine Description:
  1589. EnumFirstFileOp is a general-purpose enumerator. It enumerates the paths
  1590. and all properties from a set of operations.
  1591. Arguments:
  1592. EnumPtr - Receives the enumerated item data
  1593. Operations - Specifies one or more operations to enumerate
  1594. FileSpec - Specifies a specific path to enumerate, or NULL to enumerate
  1595. all paths that have the specified operation(s)
  1596. Return Value:
  1597. TRUE if data was enuemrated, or FALSE if no data matches the specified
  1598. operations and file spec.
  1599. --*/
  1600. {
  1601. WCHAR LongFileSpec [MEMDB_MAX];
  1602. ZeroMemory (EnumPtr, sizeof (ALL_FILEOPS_ENUMW));
  1603. EnumPtr->State = FO_ENUM_BEGIN;
  1604. EnumPtr->Operations = Operations;
  1605. EnumPtr->Path = EnumPtr->OpEnum.Path;
  1606. EnumPtr->Property = EnumPtr->PropEnum.Property;
  1607. if (FileSpec) {
  1608. pFileOpsGetLongPathW (FileSpec, LongFileSpec);
  1609. _wcssafecpy (EnumPtr->FileSpec, LongFileSpec, MAX_WCHAR_PATH);
  1610. } else {
  1611. StringCopyW (EnumPtr->FileSpec, L"*");
  1612. }
  1613. return EnumNextFileOpW (EnumPtr);
  1614. }
  1615. BOOL
  1616. EnumNextFileOpA (
  1617. IN OUT PALL_FILEOPS_ENUMA EnumPtr
  1618. )
  1619. {
  1620. BOOL b;
  1621. b = EnumNextFileOpW (&EnumPtr->Enum);
  1622. if (b) {
  1623. return pEnumFileOpWorkerA (EnumPtr);
  1624. }
  1625. return FALSE;
  1626. }
  1627. BOOL
  1628. EnumNextFileOpW (
  1629. IN OUT PALL_FILEOPS_ENUMW EnumPtr
  1630. )
  1631. {
  1632. DWORD w;
  1633. while (EnumPtr->State != FO_ENUM_END) {
  1634. switch (EnumPtr->State) {
  1635. case FO_ENUM_BEGIN:
  1636. //
  1637. // Find the next operation
  1638. //
  1639. if (!EnumPtr->Operations) {
  1640. EnumPtr->State = FO_ENUM_END;
  1641. break;
  1642. }
  1643. w = EnumPtr->Operations & (~(EnumPtr->Operations - 1));
  1644. MYASSERT (ONEBITSET (w));
  1645. EnumPtr->CurrentOperation = w;
  1646. EnumPtr->OperationNum = pWhichBitIsSet (w);
  1647. EnumPtr->Operations ^= w;
  1648. EnumPtr->State = FO_ENUM_BEGIN_PATH_ENUM;
  1649. break;
  1650. case FO_ENUM_BEGIN_PATH_ENUM:
  1651. if (EnumFirstPathInOperationW (&EnumPtr->OpEnum, EnumPtr->CurrentOperation)) {
  1652. EnumPtr->State = FO_ENUM_BEGIN_PROP_ENUM;
  1653. } else {
  1654. EnumPtr->State = FO_ENUM_BEGIN;
  1655. }
  1656. break;
  1657. case FO_ENUM_BEGIN_PROP_ENUM:
  1658. if (!IsPatternMatchW (EnumPtr->FileSpec, EnumPtr->Path)) {
  1659. EnumPtr->State = FO_ENUM_NEXT_PATH;
  1660. break;
  1661. }
  1662. EnumPtr->Sequencer = EnumPtr->OpEnum.Sequencer;
  1663. EnumPtr->PropertyNum = 0;
  1664. if (EnumFirstFileOpPropertyW (
  1665. &EnumPtr->PropEnum,
  1666. EnumPtr->Sequencer,
  1667. EnumPtr->CurrentOperation
  1668. )) {
  1669. EnumPtr->State = FO_ENUM_RETURN_DATA;
  1670. break;
  1671. }
  1672. EnumPtr->State = FO_ENUM_RETURN_PATH;
  1673. break;
  1674. case FO_ENUM_RETURN_PATH:
  1675. EnumPtr->State = FO_ENUM_NEXT_PATH;
  1676. EnumPtr->PropertyValid = FALSE;
  1677. return TRUE;
  1678. case FO_ENUM_RETURN_DATA:
  1679. EnumPtr->State = FO_ENUM_NEXT_PROP;
  1680. EnumPtr->PropertyValid = TRUE;
  1681. return TRUE;
  1682. case FO_ENUM_NEXT_PROP:
  1683. EnumPtr->PropertyNum++;
  1684. if (EnumNextFileOpPropertyW (&EnumPtr->PropEnum)) {
  1685. EnumPtr->State = FO_ENUM_RETURN_DATA;
  1686. } else {
  1687. EnumPtr->State = FO_ENUM_NEXT_PATH;
  1688. }
  1689. break;
  1690. case FO_ENUM_NEXT_PATH:
  1691. if (EnumNextPathInOperationW (&EnumPtr->OpEnum)) {
  1692. EnumPtr->State = FO_ENUM_BEGIN_PROP_ENUM;
  1693. } else {
  1694. EnumPtr->State = FO_ENUM_BEGIN;
  1695. }
  1696. break;
  1697. }
  1698. }
  1699. return FALSE;
  1700. }
  1701. BOOL
  1702. TestPathsForOperationsA (
  1703. IN PCSTR BaseFileSpec,
  1704. IN DWORD OperationsToFind
  1705. )
  1706. {
  1707. BOOL b;
  1708. PCWSTR UnicodeBaseFileSpec;
  1709. UnicodeBaseFileSpec = ConvertAtoW (BaseFileSpec);
  1710. b = TestPathsForOperationsW (UnicodeBaseFileSpec, OperationsToFind);
  1711. FreeConvertedStr (UnicodeBaseFileSpec);
  1712. return b;
  1713. }
  1714. BOOL
  1715. TestPathsForOperationsW (
  1716. IN PCWSTR BaseFileSpec,
  1717. IN DWORD OperationsToFind
  1718. )
  1719. /*++
  1720. Routine Description:
  1721. TestPathsForOperations scans all subpaths of the given base for a specific
  1722. operation. This function is typically used to test a directory for an
  1723. operation on one of its files or subdirectories.
  1724. Arguments:
  1725. BaseFileSpec - Specifies the base path to scan
  1726. OperationsToFind - Specifies one or more operations to look for
  1727. Return Value:
  1728. TRUE if one of the operations was found within BaseFileSpec, or FALSE if no
  1729. subpath of BaseFileSpec has one of the operations.
  1730. --*/
  1731. {
  1732. WCHAR LongFileSpec [MEMDB_MAX];
  1733. WCHAR Node[MEMDB_MAX];
  1734. MEMDB_ENUMW e;
  1735. DWORD Operation;
  1736. if (MemDbGetValueAndFlagsW (BaseFileSpec, NULL, &Operation)) {
  1737. if (Operation & OperationsToFind) {
  1738. return TRUE;
  1739. }
  1740. }
  1741. pFileOpsGetLongPathW (BaseFileSpec, LongFileSpec);
  1742. MemDbBuildKeyW (
  1743. Node,
  1744. MEMDB_CATEGORY_PATHROOTW,
  1745. LongFileSpec,
  1746. L"*",
  1747. NULL
  1748. );
  1749. if (MemDbEnumFirstValueW (&e, Node, MEMDB_ALL_SUBLEVELS, MEMDB_ENDPOINTS_ONLY)) {
  1750. do {
  1751. if (e.Flags & OperationsToFind) {
  1752. return TRUE;
  1753. }
  1754. } while (MemDbEnumNextValueW (&e));
  1755. }
  1756. return FALSE;
  1757. }
  1758. BOOL
  1759. IsFileMarkedAsKnownGoodA (
  1760. IN PCSTR FileSpec
  1761. )
  1762. {
  1763. CHAR Node[MEMDB_MAX];
  1764. MemDbBuildKeyA (
  1765. Node,
  1766. MEMDB_CATEGORY_KNOWN_GOODA,
  1767. FileSpec,
  1768. NULL,
  1769. NULL);
  1770. return MemDbGetValueA (Node, NULL);
  1771. }
  1772. /*++
  1773. Routine Description:
  1774. IsFileMarkedForAnnounce determines if a file is listed in DeferredAnnounce category.
  1775. Arguments:
  1776. FileSpec - Specifies the file to query in long filename format
  1777. Return Value:
  1778. TRUE if the file is listed or FALSE if it is not.
  1779. --*/
  1780. BOOL
  1781. IsFileMarkedForAnnounceA (
  1782. IN PCSTR FileSpec
  1783. )
  1784. {
  1785. CHAR Node[MEMDB_MAX];
  1786. MemDbBuildKeyA (
  1787. Node,
  1788. MEMDB_CATEGORY_DEFERREDANNOUNCEA,
  1789. FileSpec,
  1790. NULL,
  1791. NULL);
  1792. return MemDbGetValueA (Node, NULL);
  1793. }
  1794. BOOL
  1795. IsFileMarkedForAnnounceW (
  1796. IN PCWSTR FileSpec
  1797. )
  1798. {
  1799. WCHAR Node[MEMDB_MAX];
  1800. MemDbBuildKeyW (
  1801. Node,
  1802. MEMDB_CATEGORY_DEFERREDANNOUNCEW,
  1803. FileSpec,
  1804. NULL,
  1805. NULL);
  1806. return MemDbGetValueW (Node, NULL);
  1807. }
  1808. /*++
  1809. Routine Description:
  1810. GetFileAnnouncement returnes the announcement value for a particular file.
  1811. The possible values are ACT_... values in fileops.h
  1812. Arguments:
  1813. FileSpec - Specifies the file to query in long filename format
  1814. Return Value:
  1815. The announcement value.
  1816. --*/
  1817. DWORD
  1818. GetFileAnnouncementA (
  1819. IN PCSTR FileSpec
  1820. )
  1821. {
  1822. CHAR Node[MEMDB_MAX];
  1823. DWORD result = ACT_UNKNOWN;
  1824. MemDbBuildKeyA (
  1825. Node,
  1826. MEMDB_CATEGORY_DEFERREDANNOUNCEA,
  1827. FileSpec,
  1828. NULL,
  1829. NULL);
  1830. MemDbGetValueAndFlagsA (Node, NULL, &result);
  1831. return result;
  1832. }
  1833. DWORD
  1834. GetFileAnnouncementW (
  1835. IN PCWSTR FileSpec
  1836. )
  1837. {
  1838. WCHAR Node[MEMDB_MAX];
  1839. DWORD result = ACT_UNKNOWN;
  1840. MemDbBuildKeyW (
  1841. Node,
  1842. MEMDB_CATEGORY_DEFERREDANNOUNCEW,
  1843. FileSpec,
  1844. NULL,
  1845. NULL);
  1846. MemDbGetValueAndFlagsW (Node, NULL, &result);
  1847. return result;
  1848. }
  1849. /*++
  1850. Routine Description:
  1851. GetFileAnnouncementContext returnes the context of a file that is
  1852. marked for announcement.
  1853. Arguments:
  1854. FileSpec - Specifies the file to query in long filename format
  1855. Return Value:
  1856. The announcement context.
  1857. --*/
  1858. DWORD
  1859. GetFileAnnouncementContextA (
  1860. IN PCSTR FileSpec
  1861. )
  1862. {
  1863. CHAR Node[MEMDB_MAX];
  1864. DWORD result = 0;
  1865. MemDbBuildKeyA (
  1866. Node,
  1867. MEMDB_CATEGORY_DEFERREDANNOUNCEA,
  1868. FileSpec,
  1869. NULL,
  1870. NULL);
  1871. MemDbGetValueAndFlagsA (Node, &result, NULL);
  1872. return result;
  1873. }
  1874. DWORD
  1875. GetFileAnnouncementContextW (
  1876. IN PCWSTR FileSpec
  1877. )
  1878. {
  1879. WCHAR Node[MEMDB_MAX];
  1880. DWORD result = 0;
  1881. MemDbBuildKeyW (
  1882. Node,
  1883. MEMDB_CATEGORY_DEFERREDANNOUNCEW,
  1884. FileSpec,
  1885. NULL,
  1886. NULL);
  1887. MemDbGetValueAndFlagsW (Node, &result, NULL);
  1888. return result;
  1889. }
  1890. /*++
  1891. Routine Description:
  1892. IsFileProvidedByNt checks to see if a specific file is going to
  1893. be installed by standard NT setup. This list was generated from
  1894. calls to FileIsProviedByNt.
  1895. Arguments:
  1896. FileName - Specifies the name of the file in long filename format
  1897. Return Value:
  1898. TRUE if the file will be installed by standard NT installation, or
  1899. FALSE if it will not.
  1900. --*/
  1901. BOOL
  1902. IsFileProvidedByNtA (
  1903. IN PCSTR FileName
  1904. )
  1905. {
  1906. CHAR Node[MEMDB_MAX];
  1907. MemDbBuildKeyA (Node, MEMDB_CATEGORY_NT_FILESA, FileName, NULL, NULL);
  1908. return MemDbGetValueA (Node, NULL);
  1909. }
  1910. BOOL
  1911. IsFileProvidedByNtW (
  1912. IN PCWSTR FileName
  1913. )
  1914. {
  1915. WCHAR Node[MEMDB_MAX];
  1916. MemDbBuildKeyW (Node, MEMDB_CATEGORY_NT_FILESW, FileName, NULL, NULL);
  1917. return MemDbGetValueW (Node, NULL);
  1918. }
  1919. /*++
  1920. Routine Description:
  1921. GetNewPathForFile copies the move path to the caller-supplied buffer
  1922. if the file is marked to be moved.
  1923. Arguments:
  1924. SrcFileSpec - Specifies the src file to query in long filename format
  1925. NewPath - Receives a copy of the new location, or if the file is not
  1926. being moved, receives a copy of the original file.
  1927. Return Value:
  1928. TRUE if the file is marked to be moved and the destination was copied
  1929. to NewPath, or FALSE if the file is not makred to be moved and
  1930. SrcFileSpec was copied to NewPath.
  1931. --*/
  1932. BOOL
  1933. GetNewPathForFileA (
  1934. IN PCSTR SrcFileSpec,
  1935. OUT PSTR NewPath
  1936. )
  1937. {
  1938. BOOL b;
  1939. PCWSTR UnicodeSrcFileSpec;
  1940. WCHAR UnicodeNewPath[MAX_WCHAR_PATH];
  1941. UnicodeSrcFileSpec = ConvertAtoW (SrcFileSpec);
  1942. b = GetNewPathForFileW (UnicodeSrcFileSpec, UnicodeNewPath);
  1943. FreeConvertedStr (UnicodeSrcFileSpec);
  1944. if (b) {
  1945. KnownSizeWtoA (NewPath, UnicodeNewPath);
  1946. }
  1947. return b;
  1948. }
  1949. BOOL
  1950. GetNewPathForFileW (
  1951. IN PCWSTR SrcFileSpec,
  1952. OUT PWSTR NewPath
  1953. )
  1954. {
  1955. DWORD Offset = INVALID_OFFSET;
  1956. DWORD w;
  1957. OPERATION Operation;
  1958. UINT Sequencer;
  1959. Sequencer = GetSequencerFromPathW (SrcFileSpec);
  1960. StringCopyW (NewPath, SrcFileSpec);
  1961. w = ALL_MOVE_OPERATIONS;
  1962. while (w && Offset == INVALID_OFFSET) {
  1963. Operation = w & (~(w - 1));
  1964. w ^= Operation;
  1965. Offset = GetPathPropertyOffset (Sequencer, Operation, 0);
  1966. }
  1967. if (Offset != INVALID_OFFSET) {
  1968. return MemDbBuildKeyFromOffsetW (Offset, NewPath, 1, NULL);
  1969. }
  1970. return FALSE;
  1971. }
  1972. BOOL
  1973. AnnounceFileInReportA (
  1974. IN PCSTR FileSpec,
  1975. IN DWORD ContextPtr,
  1976. IN DWORD Action
  1977. )
  1978. /*++
  1979. Routine Description:
  1980. Adds a file to the memdb DeferredAnnounce category.
  1981. Arguments:
  1982. FileSpec - Specifies the file to delete in long name format
  1983. Return Value:
  1984. TRUE if the file was recorded in memdb, or FALSE if it could not be recorded.
  1985. --*/
  1986. {
  1987. CHAR Key[MEMDB_MAX];
  1988. MemDbBuildKeyA (Key, MEMDB_CATEGORY_DEFERREDANNOUNCEA, FileSpec, NULL, NULL);
  1989. return MemDbSetValueAndFlagsA (Key, ContextPtr, Action, 0);
  1990. }
  1991. BOOL
  1992. MarkFileAsKnownGoodA (
  1993. IN PCSTR FileSpec
  1994. )
  1995. /*++
  1996. Routine Description:
  1997. Adds a file to the memdb KnownGood category.
  1998. Arguments:
  1999. FileSpec - Specifies the file name
  2000. Return Value:
  2001. TRUE if the file was recorded in memdb, or FALSE if it could not be recorded.
  2002. --*/
  2003. {
  2004. return MemDbSetValueExA (MEMDB_CATEGORY_KNOWN_GOODA, FileSpec, NULL, NULL, 0, NULL);
  2005. }
  2006. BOOL
  2007. AddCompatibleShellA (
  2008. IN PCSTR FileSpec,
  2009. IN DWORD ContextPtr OPTIONAL
  2010. )
  2011. /*++
  2012. Routine Description:
  2013. Adds a file to the memdb CompatibleShell category.
  2014. Arguments:
  2015. FileSpec - Specifies the file to delete in long name format
  2016. ContextPtr - Specifies the MigDb context, cast as a DWORD (can be 0 if no context
  2017. is available)
  2018. Return Value:
  2019. TRUE if the file was recorded in memdb, or FALSE if it could not be recorded.
  2020. --*/
  2021. {
  2022. CHAR Key[MEMDB_MAX];
  2023. MemDbBuildKeyA (Key, MEMDB_CATEGORY_COMPATIBLE_SHELLA, FileSpec, NULL, NULL);
  2024. return MemDbSetValueAndFlagsA (Key, ContextPtr, 0, 0);
  2025. }
  2026. BOOL
  2027. AddCompatibleRunKeyA (
  2028. IN PCSTR FileSpec,
  2029. IN DWORD ContextPtr
  2030. )
  2031. /*++
  2032. Routine Description:
  2033. Adds a file to the memdb CompatibleRunKey category.
  2034. Arguments:
  2035. FileSpec - Specifies the file to delete in long name format
  2036. ContextPtr - Specifies the MigDb context, cast as a DWORD (can be 0 if no context
  2037. is available)
  2038. Return Value:
  2039. TRUE if the file was recorded in memdb, or FALSE if it could not be recorded.
  2040. --*/
  2041. {
  2042. CHAR Key[MEMDB_MAX];
  2043. MemDbBuildKeyA (Key, MEMDB_CATEGORY_COMPATIBLE_RUNKEYA, FileSpec, NULL, NULL);
  2044. return MemDbSetValueAndFlagsA (Key, ContextPtr, 0, 0);
  2045. }
  2046. BOOL
  2047. AddCompatibleDosA (
  2048. IN PCSTR FileSpec,
  2049. IN DWORD ContextPtr OPTIONAL
  2050. )
  2051. /*++
  2052. Routine Description:
  2053. Adds a file to the memdb CompatibleDos category.
  2054. Arguments:
  2055. FileSpec - Specifies the file in long name format
  2056. ContextPtr - Specifies the MigDb context, cast as a DWORD (can be 0 if no context
  2057. is available)
  2058. Return Value:
  2059. TRUE if the file was recorded in memdb, or FALSE if it could not be recorded.
  2060. --*/
  2061. {
  2062. CHAR Key[MEMDB_MAX];
  2063. MemDbBuildKeyA (Key, MEMDB_CATEGORY_COMPATIBLE_DOSA, FileSpec, NULL, NULL);
  2064. return MemDbSetValueAndFlagsA (Key, ContextPtr, 0, 0);
  2065. }
  2066. BOOL
  2067. AddCompatibleHlpA (
  2068. IN PCSTR FileSpec,
  2069. IN DWORD ContextPtr
  2070. )
  2071. /*++
  2072. Routine Description:
  2073. Adds a file to the memdb CompatibleHlp category.
  2074. Arguments:
  2075. FileSpec - Specifies the file in long name format
  2076. ContextPtr - Specifies the MigDb context, cast as a DWORD (can be 0 if no context
  2077. is available)
  2078. Return Value:
  2079. TRUE if the file was recorded in memdb, or FALSE if it could not be recorded.
  2080. --*/
  2081. {
  2082. CHAR Key[MEMDB_MAX];
  2083. MemDbBuildKeyA (Key, MEMDB_CATEGORY_COMPATIBLE_HLPA, FileSpec, NULL, NULL);
  2084. return MemDbSetValueAndFlagsA (Key, ContextPtr, 0, 0);
  2085. }
  2086. //
  2087. // Compute the number of CHARs allowed for the normal and long temp
  2088. // locations. MAX_PATH includes the nul terminator, and we subtract
  2089. // that terminator via sizeof.
  2090. //
  2091. // NORMAL_MAX is the number of chars left after the subdir c:\user~tmp.@01\,
  2092. // including the nul
  2093. //
  2094. // LONG_MAX is the number of chars left after the subdir
  2095. // c:\user~tmp.@02\12345\, including the nul. 12345 is a %05X sequencer.
  2096. //
  2097. #define NORMAL_MAX (MAX_PATH - (sizeof(S_SHELL_TEMP_NORMAL_PATHA)/sizeof(CHAR)) + 2)
  2098. #define LONG_MAX (MAX_PATH - (sizeof(S_SHELL_TEMP_LONG_PATHA)/sizeof(CHAR)) - 6)
  2099. VOID
  2100. ComputeTemporaryPathA (
  2101. IN PCSTR SourcePath,
  2102. IN PCSTR SourcePrefix, OPTIONAL
  2103. IN PCSTR TempPrefix, OPTIONAL
  2104. IN PCSTR SetupTempDir,
  2105. OUT PSTR TempPath
  2106. )
  2107. /*++
  2108. Routine Description:
  2109. ComputeTemporaryPath builds a temporary path rooted in
  2110. S_SHELL_TEMP_NORMAL_PATH for a path that fits within MAX_PATH, or
  2111. S_SHELL_TEMP_LONG_PATH for a longer path. It attempts to use the original
  2112. subpath name in the "normal" path subdirectory. If that doesn't fit, then a
  2113. unique "long" subdirectory is created, and a subpath is computed by taking
  2114. the longest possible subpath (the right side).
  2115. Arguments:
  2116. SourcePath - Specifies the full file or directory path of the source
  2117. SourcePrefix - Specifies a prefix that will be stripped from SourcePath
  2118. TempPrefix - Specifies a prefix that will be inserted at the start of
  2119. TempPath
  2120. SetupTempDir - Specifies the setup temp dir, typically %windir%\setup,
  2121. to be used when no suitable path can be computed. (Unlikely
  2122. case.)
  2123. TempPath - Receives the temp path string. This buffer will receive up to
  2124. MAX_PATH characters (includes the nul).
  2125. Return Value:
  2126. None.
  2127. --*/
  2128. {
  2129. PCSTR subPath = NULL;
  2130. PCSTR smallerSubPath;
  2131. PSTR pathCopy = NULL;
  2132. PSTR lastWack;
  2133. static UINT dirSequencer = 0;
  2134. UINT prefixLen;
  2135. MBCHAR ch;
  2136. UINT normalMax = NORMAL_MAX;
  2137. //
  2138. // Build a temporary file name using the inbound file as a suggestion.
  2139. //
  2140. StringCopyA (TempPath, S_SHELL_TEMP_NORMAL_PATHA);
  2141. TempPath[0] = SourcePath[0];
  2142. if (SourcePrefix) {
  2143. prefixLen = TcharCountA (SourcePrefix);
  2144. if (StringIMatchTcharCountA (SourcePath, SourcePrefix, prefixLen)) {
  2145. ch = _mbsnextc (SourcePath + prefixLen);
  2146. if (!ch || ch == '\\') {
  2147. subPath = SourcePath + prefixLen;
  2148. if (*subPath) {
  2149. subPath++;
  2150. }
  2151. }
  2152. }
  2153. }
  2154. if (!subPath) {
  2155. subPath = _mbschr (SourcePath, '\\');
  2156. if (!subPath) {
  2157. subPath = SourcePath;
  2158. } else {
  2159. subPath++;
  2160. }
  2161. }
  2162. DEBUGMSGA_IF ((_mbschr (subPath, ':') != NULL, DBG_WHOOPS, "Bad temp path: %s", SourcePath));
  2163. if (TempPrefix) {
  2164. StringCopyA (AppendWackA (TempPath), TempPrefix);
  2165. normalMax = MAX_PATH - TcharCountA (TempPath);
  2166. }
  2167. if (TcharCountA (subPath) < normalMax) {
  2168. //
  2169. // typical case: source path fits within MAX_PATH; use it
  2170. //
  2171. if (*subPath) {
  2172. StringCopyA (AppendWackA (TempPath), subPath);
  2173. }
  2174. } else {
  2175. //
  2176. // subpath is too big, just take the right side of the src
  2177. //
  2178. dirSequencer++;
  2179. wsprintfA (TempPath, S_SHELL_TEMP_LONG_PATHA "\\%05x", dirSequencer);
  2180. TempPath[0] = SourcePath[0];
  2181. // compute end of string + nul terminator - backslash - (MAX_PATH - TcharCount of TempPath)
  2182. subPath = GetEndOfStringA (SourcePath) - LONG_MAX;
  2183. //
  2184. // try to eliminate a truncated subdirectory on the left
  2185. //
  2186. smallerSubPath = _mbschr (subPath, '\\');
  2187. if (smallerSubPath && smallerSubPath[1]) {
  2188. subPath = smallerSubPath + 1;
  2189. } else {
  2190. //
  2191. // still no subpath, try just the file name
  2192. //
  2193. subPath = _mbsrchr (subPath, '\\');
  2194. if (subPath) {
  2195. subPath++;
  2196. if (!(*subPath)) {
  2197. //
  2198. // file spec ends in backslash
  2199. //
  2200. pathCopy = DuplicateTextA (SourcePath);
  2201. if (!pathCopy) {
  2202. subPath = NULL;
  2203. } else {
  2204. for (;;) {
  2205. lastWack = _mbsrchr (pathCopy, '\\');
  2206. if (!lastWack || lastWack[1]) {
  2207. break;
  2208. }
  2209. *lastWack = 0;
  2210. }
  2211. subPath = lastWack;
  2212. }
  2213. } else if (TcharCountA (subPath) > LONG_MAX) {
  2214. //
  2215. // very long file name; truncate it
  2216. //
  2217. subPath = GetEndOfStringA (subPath) - LONG_MAX;
  2218. }
  2219. }
  2220. }
  2221. if (subPath) {
  2222. StringCopyA (AppendWackA (TempPath), subPath);
  2223. } else {
  2224. dirSequencer++;
  2225. wsprintfA (TempPath, "%s\\tmp%05x", SetupTempDir, dirSequencer);
  2226. }
  2227. if (pathCopy) {
  2228. FreeTextA (pathCopy);
  2229. }
  2230. }
  2231. }
  2232. BOOL
  2233. pMarkFileForTemporaryMoveA (
  2234. IN PCSTR SrcFileSpec,
  2235. IN PCSTR FinalDest,
  2236. IN PCSTR TempSpec,
  2237. IN BOOL TempSpecIsFile,
  2238. IN PCSTR TempFileIn, OPTIONAL
  2239. OUT PSTR TempFileOut OPTIONAL
  2240. )
  2241. /*++
  2242. Routine Description:
  2243. This routine adds operations to move a file to a temporary location in
  2244. text mode, and optionally move it to a final destination.
  2245. Arguments:
  2246. SrcFileSpec - Specifies the file that is to be moved to a safe place (out
  2247. of the way of normal NT installation), and then moved back
  2248. after NT is installed.
  2249. FinalDest - Specifies the final destination for FileSpec. If NULL, file
  2250. is moved to a temporary location but is not copied to a final
  2251. location in GUI mode.
  2252. TempSpec - Specifies the temp dir or file to relocate the file to. The temp dir
  2253. must be on the same drive as SrcFileSpec.
  2254. TempSpecIsFile - Specifies TRUE if the prev param is a file
  2255. TempFileIn - If non-NULL, specifies the temporary file to use instead of
  2256. automatically generated name. Provided only for
  2257. MarkHiveForTemporaryMove.
  2258. TempFileOut - If non-NULL, receives the path to the temporary file location.
  2259. Return Value:
  2260. TRUE if the operation was recorded, or FALSE otherwise.
  2261. --*/
  2262. {
  2263. BOOL b = TRUE;
  2264. CHAR TempFileSpec[MAX_MBCHAR_PATH];
  2265. static DWORD FileSequencer = 0;
  2266. //
  2267. // Move the file from source to temporary location
  2268. //
  2269. if (!CanSetOperationA (SrcFileSpec, OPERATION_TEMP_PATH)) {
  2270. return FALSE;
  2271. }
  2272. if (TempFileIn) {
  2273. MYASSERT (!TempSpecIsFile);
  2274. wsprintfA (TempFileSpec, "%s\\%s", TempSpec, TempFileIn);
  2275. } else if (TempSpecIsFile) {
  2276. StringCopyA (TempFileSpec, TempSpec);
  2277. } else {
  2278. FileSequencer++;
  2279. wsprintfA (TempFileSpec, "%s\\tmp%05x", TempSpec, FileSequencer);
  2280. }
  2281. DEBUGMSGA ((DBG_MEMDB, "MarkFileForTemporaryMove: %s -> %s", SrcFileSpec, TempFileSpec));
  2282. if (TempFileOut) {
  2283. StringCopyA (TempFileOut, TempFileSpec);
  2284. }
  2285. RemoveOperationsFromPathA (SrcFileSpec, OPERATION_TEMP_PATH | OPERATION_FILE_DELETE_EXTERNAL | OPERATION_FILE_MOVE_EXTERNAL);
  2286. b = AssociatePropertyWithPathA (SrcFileSpec, OPERATION_TEMP_PATH, TempFileSpec);
  2287. //
  2288. // Optionally move the file from temporary location to final dest
  2289. //
  2290. if (FinalDest) {
  2291. //
  2292. // We are adding additional properties to the temp path operation that
  2293. // already exists. So the properties are defined as zero being the temp
  2294. // path, and one and higher being destinations. That's how we achieve
  2295. // a one-to-many capability.
  2296. //
  2297. b = b && AssociatePropertyWithPathA (SrcFileSpec, OPERATION_TEMP_PATH, FinalDest);
  2298. //
  2299. // Now we add an external move operation, so the registry is updated
  2300. // correctly.
  2301. //
  2302. b = b && MarkFileForMoveExternalA (SrcFileSpec, FinalDest);
  2303. } else {
  2304. //
  2305. // Because the source file is going to be moved to a temporary location
  2306. // and never moved back, it is effectively going to be deleted.
  2307. //
  2308. b = b && MarkFileForExternalDeleteA (SrcFileSpec);
  2309. }
  2310. return b;
  2311. }
  2312. BOOL
  2313. MarkFileForTemporaryMoveExA (
  2314. IN PCSTR SrcFileSpec,
  2315. IN PCSTR FinalDest,
  2316. IN PCSTR TempSpec,
  2317. IN BOOL TempSpecIsFile
  2318. )
  2319. {
  2320. return pMarkFileForTemporaryMoveA (SrcFileSpec, FinalDest, TempSpec, TempSpecIsFile, NULL, NULL);
  2321. }
  2322. PCSTR
  2323. GetTemporaryLocationForFileA (
  2324. IN PCSTR SourceFile
  2325. )
  2326. {
  2327. UINT sequencer;
  2328. PCSTR result = NULL;
  2329. FILEOP_PROP_ENUMA eOpProp;
  2330. sequencer = GetSequencerFromPathA (SourceFile);
  2331. if (sequencer) {
  2332. if (EnumFirstFileOpPropertyA (&eOpProp, sequencer, OPERATION_TEMP_PATH)) {
  2333. result = DuplicatePathStringA (eOpProp.Property, 0);
  2334. }
  2335. }
  2336. return result;
  2337. }
  2338. PCWSTR
  2339. GetTemporaryLocationForFileW (
  2340. IN PCWSTR SourceFile
  2341. )
  2342. {
  2343. UINT sequencer;
  2344. PCWSTR result = NULL;
  2345. FILEOP_PROP_ENUMW eOpProp;
  2346. sequencer = GetSequencerFromPathW (SourceFile);
  2347. if (sequencer) {
  2348. if (EnumFirstFileOpPropertyW (&eOpProp, sequencer, OPERATION_TEMP_PATH)) {
  2349. result = DuplicatePathStringW (eOpProp.Property, 0);
  2350. }
  2351. }
  2352. return result;
  2353. }
  2354. BOOL
  2355. MarkHiveForTemporaryMoveA (
  2356. IN PCSTR HivePath,
  2357. IN PCSTR TempDir,
  2358. IN PCSTR UserName,
  2359. IN BOOL DefaultHives,
  2360. IN BOOL CreateOnly
  2361. )
  2362. /*++
  2363. Routine Description:
  2364. Adds a file or directory path to the TempReloc memdb category. The file or
  2365. dir is moved during text mode and is never moved back. If the file name is
  2366. user.dat, the destination location is written to the UserDatLoc category.
  2367. All hives are deleted at the end of setup.
  2368. Arguments:
  2369. HivePath - Specifies the Win9x path to a user.dat or system.dat file
  2370. TempDir - Specifies the path to the setup temporary dir on the same drive
  2371. as HivePath
  2372. UserName - Specifies the current user or NULL if default user or no user
  2373. DefaultHives - Specifies TRUE if the HivePath is a system default path, or
  2374. FALSE if the HivePath is specific to a user profile.
  2375. CreateOnly - Specifies TRUE if this account is create-only (such as
  2376. Administrator), or FALSE if this account gets full migration.
  2377. Return Value:
  2378. TRUE if the file was recorded in memdb, or FALSE if it could not be recorded.
  2379. --*/
  2380. {
  2381. BOOL b = TRUE;
  2382. CHAR OurTempFileSpec[MAX_MBCHAR_PATH];
  2383. CHAR RealTempFileSpec[MAX_MBCHAR_PATH];
  2384. static DWORD Sequencer = 0;
  2385. PSTR p, q;
  2386. if (!UserName || !UserName[0]) {
  2387. UserName = S_DOT_DEFAULTA;
  2388. }
  2389. //
  2390. // Has hive already been moved? If so, point two or more users to
  2391. // the same hive.
  2392. //
  2393. RealTempFileSpec[0] = 0;
  2394. p = (PSTR) GetFileNameFromPathA (HivePath);
  2395. GetPathPropertyA (HivePath, OPERATION_TEMP_PATH, 0, RealTempFileSpec);
  2396. if (!(RealTempFileSpec[0])) {
  2397. //
  2398. // Hive has not been moved yet -- move it now
  2399. //
  2400. if (!DefaultHives) {
  2401. Sequencer++;
  2402. wsprintfA (OurTempFileSpec, "hive%04u\\%s", Sequencer, p);
  2403. } else {
  2404. wsprintfA (OurTempFileSpec, "defhives\\%s", p);
  2405. }
  2406. b = pMarkFileForTemporaryMoveA (
  2407. HivePath,
  2408. NULL,
  2409. TempDir,
  2410. FALSE,
  2411. OurTempFileSpec,
  2412. RealTempFileSpec
  2413. );
  2414. if (b && DefaultHives) {
  2415. //
  2416. // Save defhives location in Paths\RelocWinDir
  2417. //
  2418. q = _mbsrchr (RealTempFileSpec, '\\');
  2419. MYASSERT(q);
  2420. *q = 0;
  2421. b = MemDbSetValueExA (
  2422. MEMDB_CATEGORY_PATHSA, // "Paths"
  2423. MEMDB_ITEM_RELOC_WINDIRA, // "RelocWinDir"
  2424. RealTempFileSpec, // Path to default hives
  2425. NULL,
  2426. 0,
  2427. NULL
  2428. );
  2429. *q = '\\';
  2430. }
  2431. }
  2432. if (b && StringIMatchA (p, "USER.DAT")) {
  2433. //
  2434. // Save location to all user.dat files in UserDatLoc
  2435. //
  2436. b = MemDbSetValueExA (
  2437. MEMDB_CATEGORY_USER_DAT_LOCA,
  2438. UserName,
  2439. NULL,
  2440. RealTempFileSpec,
  2441. (DWORD) CreateOnly,
  2442. NULL
  2443. );
  2444. }
  2445. if (b) {
  2446. DEBUGMSGA ((DBG_NAUSEA, "%s -> %s", HivePath, RealTempFileSpec));
  2447. }
  2448. return b;
  2449. }
  2450. VOID
  2451. MarkShellFolderForMoveA (
  2452. IN PCSTR SrcPath,
  2453. IN PCSTR TempPath
  2454. )
  2455. {
  2456. DWORD Offset;
  2457. //
  2458. // Add an entry so the specified source file or directory
  2459. // is moved to the temp path.
  2460. //
  2461. MemDbSetValueExA (
  2462. MEMDB_CATEGORY_SHELL_FOLDERS_PATHA,
  2463. SrcPath,
  2464. NULL,
  2465. NULL,
  2466. 0,
  2467. &Offset
  2468. );
  2469. MemDbSetValueExA (
  2470. MEMDB_CATEGORY_SF_TEMPA,
  2471. TempPath,
  2472. NULL,
  2473. NULL,
  2474. Offset,
  2475. NULL
  2476. );
  2477. }
  2478. BOOL
  2479. EnumFirstFileRelocA (
  2480. OUT PFILERELOC_ENUMA EnumPtr,
  2481. IN PCSTR FileSpec OPTIONAL
  2482. )
  2483. {
  2484. if (EnumFirstFileOpA (&EnumPtr->e, ALL_DEST_CHANGE_OPERATIONS, FileSpec)) {
  2485. if (!EnumPtr->e.PropertyValid) {
  2486. return EnumNextFileRelocA (EnumPtr);
  2487. } else {
  2488. StringCopyA (EnumPtr->SrcFile, EnumPtr->e.Path);
  2489. StringCopyA (EnumPtr->DestFile, EnumPtr->e.Property);
  2490. return TRUE;
  2491. }
  2492. }
  2493. return FALSE;
  2494. }
  2495. BOOL
  2496. EnumNextFileRelocA (
  2497. IN OUT PFILERELOC_ENUMA EnumPtr
  2498. )
  2499. {
  2500. do {
  2501. if (!EnumNextFileOpA (&EnumPtr->e)) {
  2502. return FALSE;
  2503. }
  2504. } while (!EnumPtr->e.PropertyValid);
  2505. StringCopyA (EnumPtr->SrcFile, EnumPtr->e.Path);
  2506. StringCopyA (EnumPtr->DestFile, EnumPtr->e.Property);
  2507. return TRUE;
  2508. }
  2509. /*++
  2510. Routine Description:
  2511. DeclareTemporaryFile adds a file to the memdb FileDel and CancelFileDel
  2512. category. That means the file will get deleted if the user hits CANCEL
  2513. or at the end of GUI mode setup.
  2514. Arguments:
  2515. FileSpec - Specifies the file to declare in long name format
  2516. Return Value:
  2517. TRUE if the file was recorded in memdb, or FALSE if it could not be recorded.
  2518. --*/
  2519. BOOL
  2520. DeclareTemporaryFileA (
  2521. IN PCSTR FileSpec
  2522. )
  2523. {
  2524. return MarkFileForCleanUpA (FileSpec) &&
  2525. MemDbSetValueExA (MEMDB_CATEGORY_CANCELFILEDELA, FileSpec, NULL, NULL, 0, NULL);
  2526. }
  2527. BOOL
  2528. DeclareTemporaryFileW (
  2529. IN PCWSTR FileSpec
  2530. )
  2531. {
  2532. return MarkFileForCleanUpW (FileSpec) &&
  2533. MemDbSetValueExW (MEMDB_CATEGORY_CANCELFILEDELW, FileSpec, NULL, NULL, 0, NULL);
  2534. }
  2535. /*++
  2536. Routine Description:
  2537. FileIsProvidedByNt identifies a file as being installed by Windows NT.
  2538. An entry is made in the NtFiles category for the file name, and the file
  2539. name is linked to the full path in NtDirs.
  2540. This funciton is implemented as an A version only because the list is
  2541. created on the Win9x side of the upgrade.
  2542. Arguments:
  2543. FullPath - Specifies the full path, including the file name.
  2544. FileName - Specifiles the file name only
  2545. UserFlags - Specifies if the existence of NT file should be verified very first
  2546. thing on NT side.
  2547. Return Value:
  2548. TRUE if memdb was updated, or FALSE if an error occurred.
  2549. --*/
  2550. BOOL
  2551. FileIsProvidedByNtA (
  2552. IN PCSTR FullPath,
  2553. IN PCSTR FileName,
  2554. IN DWORD UserFlags
  2555. )
  2556. {
  2557. DWORD Offset;
  2558. PSTR DirOnly;
  2559. CHAR Key[MEMDB_MAX];
  2560. PSTR p;
  2561. BOOL b;
  2562. DirOnly = DuplicatePathStringA (FullPath, 0);
  2563. p = _mbsrchr (DirOnly, '\\');
  2564. if (p) {
  2565. *p = 0;
  2566. }
  2567. b = MemDbSetValueExA (
  2568. MEMDB_CATEGORY_NT_DIRSA,
  2569. DirOnly,
  2570. NULL,
  2571. NULL,
  2572. 0,
  2573. &Offset
  2574. );
  2575. if (b) {
  2576. MemDbBuildKeyA (Key, MEMDB_CATEGORY_NT_FILESA, FileName, NULL, NULL);
  2577. b = MemDbSetValueAndFlagsA (Key, Offset, UserFlags, 0);
  2578. }
  2579. FreePathStringA (DirOnly);
  2580. return b;
  2581. }
  2582. /*++
  2583. Routine Description:
  2584. GetNtFilePath looks in the NtFiles category for the specified file,
  2585. and if found builds the complete path.
  2586. Arguments:
  2587. FileName - Specifies the file that may be installed by NT
  2588. FullPath - Receives the full path to the file as it will be installed
  2589. Return Value:
  2590. TRUE if the file exists and there were no errors building the path,
  2591. or FALSE if the file does not exist or the path could not be built.
  2592. --*/
  2593. BOOL
  2594. GetNtFilePathA (
  2595. IN PCSTR FileName,
  2596. OUT PSTR FullPath
  2597. )
  2598. {
  2599. DWORD Offset;
  2600. CHAR Node[MEMDB_MAX];
  2601. MemDbBuildKeyA (Node, MEMDB_CATEGORY_NT_FILESA, FileName, NULL, NULL);
  2602. if (MemDbGetValueA (Node, &Offset)) {
  2603. if (MemDbBuildKeyFromOffsetA (Offset, FullPath, 1, NULL)) {
  2604. StringCopyA (AppendPathWackA (FullPath), FileName);
  2605. return TRUE;
  2606. }
  2607. DEBUGMSG ((DBG_WHOOPS, "GetNtFilePath: Could not build path from offset"));
  2608. }
  2609. return FALSE;
  2610. }
  2611. BOOL
  2612. GetNtFilePathW (
  2613. IN PCWSTR FileName,
  2614. OUT PWSTR FullPath
  2615. )
  2616. {
  2617. DWORD Offset;
  2618. WCHAR Node[MEMDB_MAX];
  2619. MemDbBuildKeyW (Node, MEMDB_CATEGORY_NT_FILESW, FileName, NULL, NULL);
  2620. if (MemDbGetValueW (Node, &Offset)) {
  2621. if (MemDbBuildKeyFromOffsetW (Offset, FullPath, 1, NULL)) {
  2622. StringCopyW (AppendPathWackW (FullPath), FileName);
  2623. return TRUE;
  2624. }
  2625. DEBUGMSG ((DBG_WHOOPS, "GetNtFilePath: Could not build path from offset"));
  2626. }
  2627. return FALSE;
  2628. }
  2629. DWORD
  2630. GetFileInfoOnNtW (
  2631. IN PCWSTR FileSpec,
  2632. OUT PWSTR NewFileSpec, // OPTIONAL
  2633. IN UINT BufferChars // Required if NewFileSpec is specified
  2634. )
  2635. {
  2636. WCHAR Node[MEMDB_MAX];
  2637. DWORD Operations;
  2638. DWORD Offset;
  2639. WCHAR NtFilePath[MEMDB_MAX];
  2640. WCHAR DestPath[MEMDB_MAX];
  2641. PCWSTR InboundPath;
  2642. BOOL UserFile = FALSE;
  2643. DWORD status = FILESTATUS_UNCHANGED;
  2644. BOOL ShortFileNameFlag;
  2645. PCWSTR UltimateDestiny;
  2646. BOOL NtProvidesThisFile;
  2647. WCHAR LongFileSpec[MAX_WCHAR_PATH];
  2648. PCWSTR SanitizedPath;
  2649. PCSTR ansiPath;
  2650. CHAR ansiOutput[MAX_MBCHAR_PATH];
  2651. PWSTR lastWack;
  2652. //
  2653. // Require FileSpec to be a local path and less than MAX_WCHAR_PATH
  2654. //
  2655. if (lstrlen (FileSpec) >= MAX_WCHAR_PATH) {
  2656. if (NewFileSpec) {
  2657. _wcssafecpy (NewFileSpec, FileSpec, BufferChars * sizeof (WCHAR));
  2658. }
  2659. return 0;
  2660. }
  2661. //
  2662. // Now get the file status of an actual path
  2663. //
  2664. SanitizedPath = SanitizePathW (FileSpec);
  2665. if (!SanitizedPath) {
  2666. SanitizedPath = DuplicatePathStringW (FileSpec, 0);
  2667. }
  2668. lastWack = wcsrchr (SanitizedPath, L'\\');
  2669. if (lastWack) {
  2670. if (lastWack[1] != 0 || lastWack == wcschr (SanitizedPath, L'\\')) {
  2671. lastWack = NULL;
  2672. } else {
  2673. *lastWack = 0;
  2674. }
  2675. }
  2676. pFileOpsGetLongPathW (SanitizedPath, LongFileSpec);
  2677. if (!StringIMatchW (SanitizedPath, LongFileSpec)) {
  2678. InboundPath = LongFileSpec;
  2679. ShortFileNameFlag = TRUE;
  2680. } else {
  2681. InboundPath = SanitizedPath;
  2682. ShortFileNameFlag = FALSE;
  2683. }
  2684. DestPath[0] = 0;
  2685. UltimateDestiny = InboundPath;
  2686. //
  2687. // Get all operations set on the file
  2688. //
  2689. MemDbBuildKeyW (Node, MEMDB_CATEGORY_PATHROOTW, InboundPath, NULL, NULL);
  2690. if (!MemDbGetValueAndFlagsW (Node, NULL, &Operations)) {
  2691. Operations = 0;
  2692. }
  2693. //
  2694. // Migration DLLs have priority over all other operations
  2695. //
  2696. if (Operations & OPERATION_MIGDLL_HANDLED) {
  2697. if (Operations & OPERATION_FILE_DELETE_EXTERNAL) {
  2698. status = FILESTATUS_DELETED;
  2699. } else {
  2700. status = FILESTATUS_REPLACED;
  2701. if (Operations & OPERATION_FILE_MOVE_EXTERNAL) {
  2702. status |= FILESTATUS_MOVED;
  2703. GetNewPathForFileW (InboundPath, DestPath);
  2704. UltimateDestiny = DestPath;
  2705. }
  2706. }
  2707. } else {
  2708. //
  2709. // Check for per-user move
  2710. //
  2711. if (g_CurrentUser) {
  2712. MemDbBuildKeyW (
  2713. Node,
  2714. MEMDB_CATEGORY_USERFILEMOVE_SRCW,
  2715. InboundPath,
  2716. g_CurrentUser,
  2717. NULL
  2718. );
  2719. if (MemDbGetValueW (Node, &Offset)) {
  2720. if (MemDbBuildKeyFromOffsetW (Offset, DestPath, 1, NULL)) {
  2721. status = FILESTATUS_MOVED;
  2722. UltimateDestiny = DestPath;
  2723. }
  2724. UserFile = TRUE;
  2725. }
  2726. }
  2727. //
  2728. // Check for move or delete
  2729. //
  2730. if (!UserFile) {
  2731. if (Operations & ALL_MOVE_OPERATIONS) {
  2732. status = FILESTATUS_MOVED;
  2733. GetNewPathForFileW (InboundPath, DestPath);
  2734. UltimateDestiny = DestPath;
  2735. if (Operations & OPERATION_FILE_MOVE_EXTERNAL) {
  2736. status |= FILESTATUS_REPLACED;
  2737. }
  2738. } else if (Operations & ALL_DELETE_OPERATIONS) {
  2739. status = FILESTATUS_DELETED;
  2740. }
  2741. }
  2742. //
  2743. // Check if the file (or the new destination) is an NT file
  2744. //
  2745. NtProvidesThisFile = GetNtFilePathW (GetFileNameFromPathW (UltimateDestiny), NtFilePath);
  2746. if (status != FILESTATUS_UNCHANGED && NtProvidesThisFile) {
  2747. //
  2748. // Status may be either FILESTATUS_MOVED or FILESTATUS_DELETED.
  2749. //
  2750. if (StringIMatchW (UltimateDestiny, NtFilePath)) {
  2751. //
  2752. // NT installs the same file, so now we know that the ultimate
  2753. // destiny isn't deleted.
  2754. //
  2755. status &= ~FILESTATUS_DELETED;
  2756. status |= FILESTATUS_REPLACED|FILESTATUS_NTINSTALLED;
  2757. } else if (Operations & ALL_DELETE_OPERATIONS) {
  2758. //
  2759. // NT installs the same file but in a different location
  2760. // and the original file was to be deleted. The
  2761. // ultimate destiny is the NT location, and we know that the
  2762. // file is moved.
  2763. //
  2764. status = FILESTATUS_MOVED|FILESTATUS_REPLACED|FILESTATUS_NTINSTALLED;
  2765. UltimateDestiny = NtFilePath;
  2766. } else {
  2767. status |= FILESTATUS_NTINSTALLED;
  2768. }
  2769. } else if (NtProvidesThisFile) {
  2770. //
  2771. // Status is FILESTATUS_UNCHANGED
  2772. //
  2773. status = FILESTATUS_NTINSTALLED;
  2774. if (StringIMatchW (UltimateDestiny, NtFilePath)) {
  2775. status |= FILESTATUS_REPLACED;
  2776. }
  2777. }
  2778. if (!ShortFileNameFlag && (status == FILESTATUS_UNCHANGED)) {
  2779. //
  2780. // let's check for this case: undetected short file name query, NT installs this file in the same path
  2781. //
  2782. if (ISNT()) {
  2783. OurGetLongPathNameW (SanitizedPath, LongFileSpec, MAX_WCHAR_PATH);
  2784. if (!StringMatchW (UltimateDestiny, LongFileSpec)) {
  2785. //
  2786. // this was an undetected short file name query
  2787. //
  2788. NtProvidesThisFile = GetNtFilePathW (GetFileNameFromPathW (UltimateDestiny), NtFilePath);
  2789. if (StringIMatchW (UltimateDestiny, NtFilePath)) {
  2790. status |= FILESTATUS_REPLACED;
  2791. }
  2792. }
  2793. }
  2794. }
  2795. }
  2796. //
  2797. // Return the new path to the caller
  2798. //
  2799. if (NewFileSpec) {
  2800. if (lastWack) {
  2801. //
  2802. // BUGBUG - ugly truncation can happen here
  2803. //
  2804. BufferChars -= sizeof (WCHAR);
  2805. }
  2806. if (status & FILESTATUS_MOVED) {
  2807. if (ShortFileNameFlag) {
  2808. if (ISNT()) {
  2809. if (!OurGetShortPathNameW (UltimateDestiny, NewFileSpec, MAX_WCHAR_PATH)) {
  2810. _wcssafecpy (NewFileSpec, UltimateDestiny, BufferChars * sizeof (WCHAR));
  2811. }
  2812. } else {
  2813. ansiPath = ConvertWtoA (UltimateDestiny);
  2814. if (!OurGetShortPathNameA (ansiPath, ansiOutput, ARRAYSIZE(ansiOutput))) {
  2815. _mbssafecpy (ansiOutput, ansiPath, BufferChars);
  2816. }
  2817. FreeConvertedStr (ansiPath);
  2818. KnownSizeAtoW (NewFileSpec, ansiOutput);
  2819. }
  2820. } else {
  2821. _wcssafecpy (NewFileSpec, UltimateDestiny, BufferChars * sizeof (WCHAR));
  2822. }
  2823. } else {
  2824. _wcssafecpy (NewFileSpec, SanitizedPath, BufferChars * sizeof (WCHAR));
  2825. }
  2826. if (lastWack) {
  2827. AppendWackW (NewFileSpec);
  2828. }
  2829. }
  2830. if (Operations & ALL_CONTENT_CHANGE_OPERATIONS) {
  2831. status |= FILESTATUS_BACKUP;
  2832. }
  2833. FreePathStringW (SanitizedPath);
  2834. return status;
  2835. }
  2836. DWORD
  2837. GetFileStatusOnNtW (
  2838. IN PCWSTR FileName
  2839. )
  2840. {
  2841. return GetFileInfoOnNtW (FileName, NULL, 0);
  2842. }
  2843. PWSTR
  2844. GetPathStringOnNtW (
  2845. IN PCWSTR FileName
  2846. )
  2847. {
  2848. PWSTR newFileName;
  2849. newFileName = AllocPathStringW (MEMDB_MAX);
  2850. GetFileInfoOnNtW (FileName, newFileName, MEMDB_MAX);
  2851. return newFileName;
  2852. }
  2853. DWORD
  2854. GetFileInfoOnNtA (
  2855. IN PCSTR FileName,
  2856. OUT PSTR NewFileName, // OPTIONAL
  2857. IN UINT BufferChars // Required if NewFileSpec is specified
  2858. )
  2859. {
  2860. PCWSTR UnicodeFileName;
  2861. PWSTR UnicodeNewFileName = NULL;
  2862. DWORD fileStatus;
  2863. if (NewFileName && BufferChars) {
  2864. UnicodeNewFileName = AllocPathStringW (BufferChars);
  2865. }
  2866. UnicodeFileName = ConvertAtoW (FileName);
  2867. fileStatus = GetFileInfoOnNtW (UnicodeFileName, UnicodeNewFileName, BufferChars);
  2868. FreeConvertedStr (UnicodeFileName);
  2869. if (NewFileName && BufferChars) {
  2870. KnownSizeWtoA (NewFileName, UnicodeNewFileName);
  2871. FreePathStringW (UnicodeNewFileName);
  2872. }
  2873. return fileStatus;
  2874. }
  2875. DWORD
  2876. GetFileStatusOnNtA (
  2877. IN PCSTR FileName
  2878. )
  2879. {
  2880. return GetFileInfoOnNtA (FileName, NULL, 0);
  2881. }
  2882. PSTR
  2883. GetPathStringOnNtA (
  2884. IN PCSTR FileName
  2885. )
  2886. {
  2887. PSTR newFileName;
  2888. newFileName = AllocPathStringA (MEMDB_MAX);
  2889. GetFileInfoOnNtA (FileName, newFileName, MEMDB_MAX);
  2890. return newFileName;
  2891. }
  2892. /*++
  2893. Routine Description:
  2894. ExtractArgZero locates the first argument in a command line and copies
  2895. it to Buffer. Assumes the break is the first space character, the ending
  2896. quote of a quoted argument, or the nul terminator.
  2897. Arguments:
  2898. CmdLine - Specifies the full command line that has zero or more arguments
  2899. Buffer - Receives the first argument on the command line if it exists, or
  2900. an empty string if it does not exist. Must hold MAX_TCHAR_PATH
  2901. bytes.
  2902. TerminatingChars - Specifies character set that terminates the command line arg.
  2903. If NULL, the set " ,;"
  2904. Return Value:
  2905. none
  2906. --*/
  2907. PCSTR
  2908. ExtractArgZeroExA (
  2909. IN PCSTR CmdLine,
  2910. OUT PSTR Buffer,
  2911. IN PCSTR TerminatingChars, OPTIONAL
  2912. IN BOOL KeepQuotes
  2913. )
  2914. {
  2915. CHAR cmdLine1 [MAX_CMDLINE];
  2916. CHAR cmdLine2 [MAX_CMDLINE];
  2917. PSTR spacePtr1 [MAX_PATH];
  2918. PSTR spacePtr2 [MAX_PATH];
  2919. UINT spaceIdx = 0;
  2920. PSTR ptr1 = cmdLine1;
  2921. PSTR ptr2 = cmdLine2;
  2922. PSTR end;
  2923. CHAR saved;
  2924. PCSTR s = CmdLine;
  2925. BOOL inQuote = FALSE;
  2926. BOOL skipQuotes = FALSE;
  2927. MBCHAR ch;
  2928. BOOL fullPath = FALSE;
  2929. WIN32_FIND_DATAA FindData;
  2930. ch = _mbsnextc (CmdLine);
  2931. fullPath = (isalpha (ch) && *(_mbsinc (CmdLine)) == ':');
  2932. for (;;) {
  2933. ch = _mbsnextc (s);
  2934. if (ch == 0) {
  2935. break;
  2936. }
  2937. if (ch == '\"') {
  2938. skipQuotes = TRUE;
  2939. inQuote = !inQuote;
  2940. }
  2941. else {
  2942. if (!inQuote) {
  2943. if (TerminatingChars && _mbschr (TerminatingChars, ch)) {
  2944. break;
  2945. }
  2946. if (isspace (ch)) {
  2947. if (spaceIdx < MAX_PATH) {
  2948. spacePtr1 [spaceIdx] = ptr1;
  2949. spacePtr2 [spaceIdx] = ptr2;
  2950. spaceIdx ++;
  2951. }
  2952. else {
  2953. // too many spaces. We better stop now.
  2954. break;
  2955. }
  2956. }
  2957. }
  2958. }
  2959. if (KeepQuotes && skipQuotes) {
  2960. _copymbchar (ptr2, s);
  2961. ptr2 = _mbsinc (ptr2);
  2962. }
  2963. if (skipQuotes) {
  2964. skipQuotes = FALSE;
  2965. }
  2966. else {
  2967. _copymbchar (ptr1, s);
  2968. ptr1 = _mbsinc (ptr1);
  2969. _copymbchar (ptr2, s);
  2970. ptr2 = _mbsinc (ptr2);
  2971. }
  2972. s = _mbsinc(s);
  2973. }
  2974. saved = 0;
  2975. *ptr1 = 0;
  2976. *ptr2 = 0;
  2977. end = ptr2;
  2978. for (;;) {
  2979. if (fullPath && DoesFileExistExA (cmdLine1, &FindData)) {
  2980. break;
  2981. }
  2982. if (ISNT()) {
  2983. if (GetOperationsOnPathA (cmdLine1)) {
  2984. break;
  2985. }
  2986. }
  2987. if (spaceIdx) {
  2988. spaceIdx --;
  2989. *ptr2 = saved;
  2990. ptr1 = spacePtr1 [spaceIdx];
  2991. ptr2 = spacePtr2 [spaceIdx];
  2992. if (fullPath) {
  2993. saved = *ptr2;
  2994. }
  2995. *ptr1 = 0;
  2996. *ptr2 = 0;
  2997. }
  2998. else {
  2999. *ptr2 = saved;
  3000. break;
  3001. }
  3002. }
  3003. StringCopyA (Buffer, cmdLine2);
  3004. if (*ptr2) {
  3005. return (CmdLine + (end - cmdLine2));
  3006. }
  3007. else {
  3008. return (CmdLine + (ptr2 - cmdLine2));
  3009. }
  3010. }
  3011. PCWSTR
  3012. ExtractArgZeroExW (
  3013. IN PCWSTR CmdLine,
  3014. OUT PWSTR Buffer,
  3015. IN PCWSTR TerminatingChars, OPTIONAL
  3016. IN BOOL KeepQuotes
  3017. )
  3018. {
  3019. WCHAR cmdLine1 [MAX_CMDLINE];
  3020. WCHAR cmdLine2 [MAX_CMDLINE];
  3021. PWSTR spacePtr1 [MAX_PATH];
  3022. PWSTR spacePtr2 [MAX_PATH];
  3023. UINT spaceIdx = 0;
  3024. PWSTR ptr1 = cmdLine1;
  3025. PWSTR ptr2 = cmdLine2;
  3026. PWSTR end;
  3027. WCHAR saved;
  3028. PCWSTR s = CmdLine;
  3029. BOOL inQuote = FALSE;
  3030. BOOL skipQuotes = FALSE;
  3031. BOOL fullPath = FALSE;
  3032. WIN32_FIND_DATAW FindData;
  3033. fullPath = (iswalpha (CmdLine[0]) && (CmdLine[1] == L':'));
  3034. for (;;) {
  3035. if (*s == 0) {
  3036. break;
  3037. }
  3038. if (*s == '\"') {
  3039. skipQuotes = TRUE;
  3040. inQuote = !inQuote;
  3041. }
  3042. else {
  3043. if (!inQuote) {
  3044. if (TerminatingChars && wcschr (TerminatingChars, *s)) {
  3045. break;
  3046. }
  3047. if (iswspace (*s)) {
  3048. if (spaceIdx < MAX_PATH) {
  3049. spacePtr1 [spaceIdx] = ptr1;
  3050. spacePtr2 [spaceIdx] = ptr2;
  3051. spaceIdx ++;
  3052. }
  3053. else {
  3054. // too many spaces. We better stop now.
  3055. break;
  3056. }
  3057. }
  3058. }
  3059. }
  3060. if (KeepQuotes && skipQuotes) {
  3061. *ptr2 = *s;
  3062. ptr2 ++;
  3063. }
  3064. if (skipQuotes) {
  3065. skipQuotes = FALSE;
  3066. }
  3067. else {
  3068. *ptr1 = *s;
  3069. ptr1 ++;
  3070. *ptr2 = *s;
  3071. ptr2 ++;
  3072. }
  3073. s ++;
  3074. }
  3075. saved = 0;
  3076. *ptr1 = 0;
  3077. *ptr2 = 0;
  3078. end = ptr2;
  3079. for (;;) {
  3080. if (fullPath && DoesFileExistExW (cmdLine1, &FindData)) {
  3081. break;
  3082. }
  3083. if (ISNT()) {
  3084. if (GetOperationsOnPathW (cmdLine1)) {
  3085. break;
  3086. }
  3087. }
  3088. if (spaceIdx) {
  3089. spaceIdx --;
  3090. *ptr2 = saved;
  3091. ptr1 = spacePtr1 [spaceIdx];
  3092. ptr2 = spacePtr2 [spaceIdx];
  3093. if (fullPath) {
  3094. saved = *ptr2;
  3095. }
  3096. *ptr1 = 0;
  3097. *ptr2 = 0;
  3098. }
  3099. else {
  3100. *ptr2 = saved;
  3101. break;
  3102. }
  3103. }
  3104. StringCopyW (Buffer, cmdLine2);
  3105. if (*ptr2) {
  3106. return (CmdLine + (end - cmdLine2));
  3107. }
  3108. else {
  3109. return (CmdLine + (ptr2 - cmdLine2));
  3110. }
  3111. }
  3112. BOOL
  3113. pIsExcludedFromBackupW (
  3114. IN PCWSTR Path,
  3115. IN PCWSTR TempDir OPTIONAL
  3116. )
  3117. {
  3118. PCWSTR fileName;
  3119. fileName = GetFileNameFromPathW (Path);
  3120. if (!fileName) {
  3121. return TRUE;
  3122. }
  3123. if (StringIMatchW (fileName, L"win386.swp")) {
  3124. return TRUE;
  3125. }
  3126. if (StringIMatchW (fileName, L"backup.txt")) {
  3127. return TRUE;
  3128. }
  3129. if (StringIMatchW (fileName, L"moved.txt")) {
  3130. return TRUE;
  3131. }
  3132. if (StringIMatchW (fileName, L"delfiles.txt")) {
  3133. return TRUE;
  3134. }
  3135. if (StringIMatchW (fileName, L"deldirs.txt")) {
  3136. return TRUE;
  3137. }
  3138. if (StringIMatchW (Path, L"c:\\boot.ini")) {
  3139. return TRUE;
  3140. }
  3141. if (TempDir) {
  3142. if (StringIPrefixW (Path, TempDir)) {
  3143. fileName = Path + TcharCountW (TempDir) + 1;
  3144. if (wcschr (fileName, L'\\')) {
  3145. return TRUE;
  3146. }
  3147. }
  3148. }
  3149. return FALSE;
  3150. }
  3151. HANDLE
  3152. pCreateFileList (
  3153. IN PCSTR TempDir,
  3154. IN PCSTR FileName,
  3155. IN BOOL InUninstallSubDir
  3156. )
  3157. {
  3158. HANDLE file;
  3159. PCSTR fileString;
  3160. DWORD bytesWritten;
  3161. CHAR decoratedFile[MAX_PATH];
  3162. PCSTR fileToUse;
  3163. if (!InUninstallSubDir) {
  3164. fileToUse = FileName;
  3165. } else {
  3166. wsprintfA (decoratedFile, "uninstall\\%s", FileName);
  3167. fileToUse = decoratedFile;
  3168. }
  3169. fileString = JoinPathsA (TempDir, fileToUse);
  3170. file = CreateFileA (
  3171. fileString,
  3172. GENERIC_WRITE,
  3173. 0,
  3174. NULL,
  3175. CREATE_ALWAYS,
  3176. FILE_ATTRIBUTE_NORMAL,
  3177. NULL
  3178. );
  3179. if (file == INVALID_HANDLE_VALUE) {
  3180. LOGA ((LOG_ERROR,"Error creating file %s.", fileString));
  3181. FreePathStringA (fileString);
  3182. return INVALID_HANDLE_VALUE;
  3183. }
  3184. DeclareTemporaryFileA (fileString);
  3185. FreePathStringA (fileString);
  3186. //
  3187. // Write UNICODE signature
  3188. //
  3189. // Do not write as a string. FE is a lead byte.
  3190. //
  3191. if ((!WriteFile (file, "\xff\xfe", 2, &bytesWritten, NULL)) ||
  3192. (bytesWritten != 2)
  3193. ) {
  3194. LOG ((LOG_ERROR,"Unable to write unicode header."));
  3195. CloseHandle (file);
  3196. return INVALID_HANDLE_VALUE;
  3197. }
  3198. return file;
  3199. }
  3200. BOOL
  3201. WriteHashTableToFileW (
  3202. IN HANDLE File,
  3203. IN HASHTABLE FileTable
  3204. )
  3205. {
  3206. UINT unused;
  3207. HASHTABLE_ENUMW e;
  3208. BOOL result = TRUE;
  3209. if (!FileTable || File == INVALID_HANDLE_VALUE) {
  3210. return TRUE;
  3211. }
  3212. if (EnumFirstHashTableStringW (&e, FileTable)) {
  3213. do {
  3214. if (!WriteFile (File, e.String, ByteCountW (e.String), &unused, NULL)) {
  3215. result = FALSE;
  3216. }
  3217. if (!WriteFile (File, L"\r\n", 4, &unused, NULL)) {
  3218. result = FALSE;
  3219. }
  3220. } while (result && EnumNextHashTableStringW (&e));
  3221. }
  3222. return result;
  3223. }
  3224. PWSTR
  3225. pGetParentDirPathFromFilePathW(
  3226. IN PCWSTR FilePath,
  3227. OUT PWSTR DirPath
  3228. )
  3229. {
  3230. PWSTR ptr;
  3231. if(!FilePath || !DirPath){
  3232. MYASSERT(FALSE);
  3233. return NULL;
  3234. }
  3235. StringCopyW(DirPath, FilePath);
  3236. ptr = wcsrchr(DirPath, '\\');
  3237. if(ptr){
  3238. *ptr = '\0';
  3239. }
  3240. return DirPath;
  3241. }
  3242. PSTR
  3243. pGetParentDirPathFromFilePathA(
  3244. IN PCSTR FilePath,
  3245. OUT PSTR DirPath
  3246. )
  3247. {
  3248. PSTR ptr;
  3249. if(!FilePath || !DirPath){
  3250. MYASSERT(FALSE);
  3251. return NULL;
  3252. }
  3253. StringCopyA(DirPath, FilePath);
  3254. ptr = _mbsrchr(DirPath, '\\');
  3255. if(ptr){
  3256. *ptr = '\0';
  3257. }
  3258. return DirPath;
  3259. }
  3260. BOOL
  3261. IsDirEmptyA(
  3262. IN PCSTR DirPathPtr
  3263. )
  3264. {
  3265. TREE_ENUMA e;
  3266. BOOL result;
  3267. if (!EnumFirstFileInTreeExA (
  3268. &e,
  3269. DirPathPtr,
  3270. NULL,
  3271. FALSE,
  3272. FALSE,
  3273. FILE_ENUM_ALL_LEVELS
  3274. )) {
  3275. result = TRUE;
  3276. }
  3277. else{
  3278. AbortEnumFileInTreeA(&e);
  3279. result = FALSE;
  3280. }
  3281. return result;
  3282. }
  3283. BOOL
  3284. IsDirEmptyW(
  3285. IN PCWSTR DirPathPtr
  3286. )
  3287. {
  3288. TREE_ENUMW e;
  3289. BOOL result;
  3290. if (!EnumFirstFileInTreeExW (
  3291. &e,
  3292. DirPathPtr,
  3293. NULL,
  3294. FALSE,
  3295. FALSE,
  3296. FILE_ENUM_ALL_LEVELS
  3297. )) {
  3298. result = TRUE;
  3299. }
  3300. else{
  3301. AbortEnumFileInTreeW(&e);
  3302. result = FALSE;
  3303. }
  3304. return result;
  3305. }
  3306. VOID
  3307. pAddDirWorkerW (
  3308. IN PCWSTR DirPathPtr,
  3309. IN BOOL AddParentDirIfFile, OPTIONAL
  3310. IN BOOL AddParentDirIfFileExist, OPTIONAL
  3311. IN DWORD InitialAttributes
  3312. )
  3313. {
  3314. DWORD fileAttributes;
  3315. BOOL addToCategory;
  3316. WCHAR parentDirPath[MAX_WCHAR_PATH];
  3317. PCWSTR parentDirPathPtr;
  3318. FILE_ENUMW e;
  3319. //
  3320. // We are adding to the empty dirs category, which once held
  3321. // empty dirs, but now holds all kinds of dirs and their attributes
  3322. //
  3323. if (!DirPathPtr) {
  3324. MYASSERT(FALSE);
  3325. return;
  3326. }
  3327. //
  3328. // Ignore root dir
  3329. //
  3330. if (!DirPathPtr[0] || // C
  3331. !DirPathPtr[1] || // :
  3332. !DirPathPtr[2] || // backslash
  3333. !DirPathPtr[3]
  3334. ) {
  3335. return;
  3336. }
  3337. addToCategory = FALSE;
  3338. fileAttributes = InitialAttributes;
  3339. if (fileAttributes == INVALID_ATTRIBUTES) {
  3340. fileAttributes = GetFileAttributesW (DirPathPtr);
  3341. }
  3342. if (fileAttributes != INVALID_ATTRIBUTES){
  3343. if (!(fileAttributes & FILE_ATTRIBUTE_DIRECTORY)) {
  3344. //
  3345. // Ignore files. If caller wants the parent dir, then
  3346. // process it now.
  3347. //
  3348. if (AddParentDirIfFile) {
  3349. parentDirPathPtr = pGetParentDirPathFromFilePathW (DirPathPtr, parentDirPath);
  3350. if (parentDirPathPtr) {
  3351. AddDirPathToEmptyDirsCategoryW (parentDirPathPtr, FALSE, FALSE);
  3352. }
  3353. }
  3354. return;
  3355. }
  3356. //
  3357. // This is a dir, add it to memdb, and add attributes if they aren't normal
  3358. //
  3359. addToCategory = TRUE;
  3360. if (fileAttributes == FILE_ATTRIBUTE_DIRECTORY) {
  3361. fileAttributes = 0;
  3362. }
  3363. } else {
  3364. //
  3365. // This file does not exist. If it is a dir spec, then
  3366. // add it with no attributes.
  3367. //
  3368. if (!AddParentDirIfFile || !AddParentDirIfFileExist) {
  3369. fileAttributes = 0;
  3370. addToCategory = TRUE;
  3371. }
  3372. }
  3373. if (addToCategory) {
  3374. //
  3375. // Add only if fileAttributes are non normal or
  3376. // dir is empty
  3377. //
  3378. if (!fileAttributes) {
  3379. if (EnumFirstFileW (&e, DirPathPtr, NULL)) {
  3380. addToCategory = FALSE;
  3381. AbortFileEnumW (&e);
  3382. }
  3383. }
  3384. }
  3385. if (addToCategory) {
  3386. MemDbSetValueExW (
  3387. MEMDB_CATEGORY_EMPTY_DIRSW,
  3388. DirPathPtr,
  3389. NULL,
  3390. NULL,
  3391. fileAttributes,
  3392. NULL
  3393. );
  3394. }
  3395. }
  3396. VOID
  3397. AddDirPathToEmptyDirsCategoryW (
  3398. IN PCWSTR DirPathPtr,
  3399. IN BOOL AddParentDirIfFile, OPTIONAL
  3400. IN BOOL AddParentDirIfFileExist OPTIONAL
  3401. )
  3402. {
  3403. pAddDirWorkerW (
  3404. DirPathPtr,
  3405. AddParentDirIfFile,
  3406. AddParentDirIfFileExist,
  3407. INVALID_ATTRIBUTES
  3408. );
  3409. }
  3410. VOID
  3411. pAddDirWorkerA (
  3412. IN PCSTR DirPathPtr,
  3413. IN BOOL AddParentDirIfFile, OPTIONAL
  3414. IN BOOL AddParentDirIfFileExist, OPTIONAL
  3415. IN DWORD InitialAttributes
  3416. )
  3417. {
  3418. DWORD fileAttributes;
  3419. BOOL addToCategory;
  3420. CHAR parentDirPath[MAX_MBCHAR_PATH];
  3421. PCSTR parentDirPathPtr;
  3422. FILE_ENUMA e;
  3423. //
  3424. // We are adding to the empty dirs category, which once held
  3425. // empty dirs, but now holds all kinds of dirs and their attributes
  3426. //
  3427. if (!DirPathPtr) {
  3428. MYASSERT(FALSE);
  3429. return;
  3430. }
  3431. addToCategory = FALSE;
  3432. fileAttributes = InitialAttributes;
  3433. if (fileAttributes == INVALID_ATTRIBUTES) {
  3434. fileAttributes = GetFileAttributesA (DirPathPtr);
  3435. }
  3436. if (fileAttributes != INVALID_ATTRIBUTES){
  3437. if (!(fileAttributes & FILE_ATTRIBUTE_DIRECTORY)) {
  3438. //
  3439. // Ignore files. If caller wants the parent dir, then
  3440. // process it now.
  3441. //
  3442. if (AddParentDirIfFile) {
  3443. parentDirPathPtr = pGetParentDirPathFromFilePathA (DirPathPtr, parentDirPath);
  3444. if (parentDirPathPtr) {
  3445. AddDirPathToEmptyDirsCategoryA (parentDirPathPtr, FALSE, FALSE);
  3446. }
  3447. }
  3448. return;
  3449. }
  3450. //
  3451. // This is a dir, add it to memdb, and add attributes if they aren't normal
  3452. //
  3453. addToCategory = TRUE;
  3454. if (fileAttributes == FILE_ATTRIBUTE_DIRECTORY) {
  3455. fileAttributes = 0;
  3456. }
  3457. } else {
  3458. //
  3459. // This file does not exist. If it is a dir spec, then
  3460. // add it with no attributes.
  3461. //
  3462. if (!AddParentDirIfFile || !AddParentDirIfFileExist) {
  3463. fileAttributes = 0;
  3464. addToCategory = TRUE;
  3465. }
  3466. }
  3467. if (addToCategory) {
  3468. //
  3469. // Add only if fileAttributes are non normal or
  3470. // dir is empty
  3471. //
  3472. if (!fileAttributes) {
  3473. if (EnumFirstFileA (&e, DirPathPtr, NULL)) {
  3474. addToCategory = FALSE;
  3475. AbortFileEnumA (&e);
  3476. }
  3477. }
  3478. }
  3479. if (addToCategory) {
  3480. MemDbSetValueExA (
  3481. MEMDB_CATEGORY_EMPTY_DIRSA,
  3482. DirPathPtr,
  3483. NULL,
  3484. NULL,
  3485. fileAttributes,
  3486. NULL
  3487. );
  3488. }
  3489. }
  3490. VOID
  3491. AddDirPathToEmptyDirsCategoryA(
  3492. IN PCSTR DirPathPtr,
  3493. IN BOOL AddParentDirIfFile, OPTIONAL
  3494. IN BOOL AddParentDirIfFileExist OPTIONAL
  3495. )
  3496. {
  3497. pAddDirWorkerA (
  3498. DirPathPtr,
  3499. AddParentDirIfFile,
  3500. AddParentDirIfFileExist,
  3501. INVALID_ATTRIBUTES
  3502. );
  3503. }
  3504. BOOL
  3505. GetDiskSpaceForFilesList (
  3506. IN HASHTABLE FileTable,
  3507. OUT ULARGE_INTEGER * AmountOfSpace, OPTIONAL
  3508. OUT ULARGE_INTEGER * AmountOfSpaceIfCompressed, OPTIONAL
  3509. IN INT CompressionFactor, OPTIONAL
  3510. IN INT BootCabImagePadding, OPTIONAL
  3511. IN BOOL ProcessDirs, OPTIONAL
  3512. OUT ULARGE_INTEGER * AmountOfSpaceClusterAligned OPTIONAL
  3513. )
  3514. /*++
  3515. Routine Description:
  3516. GetDiskSpaceForFilesList calculate amount of space to store all files
  3517. from FileTable hashtable.
  3518. Arguments:
  3519. FileTable - Specifies container for paths of files.
  3520. AmountOfSpace - Receives the amount of space required to store files.
  3521. AmountOfSpaceIfCompressed - Receives the amount of space required to store
  3522. files, if compression will apply on files.
  3523. CompressionFactor - Receives the compression factor in 0..100 range.
  3524. BootCabImagePadding - Receives the backup disk space padding for
  3525. additional files like boot.cab.
  3526. Return Value:
  3527. TRUE if IN parameters is correct, FALSE otherwise
  3528. --*/
  3529. {
  3530. HASHTABLE_ENUMW e;
  3531. WIN32_FIND_DATAA fileAttributeData;
  3532. HANDLE h;
  3533. ULARGE_INTEGER sizeOfFiles;
  3534. ULARGE_INTEGER fileSize;
  3535. unsigned int numberOfFiles = 0;
  3536. char filePathNameA[MAX_PATH * 2];
  3537. ULARGE_INTEGER BootCabImagePaddingInBytes;
  3538. TCHAR DirPath[MAX_PATH * 2];
  3539. ULARGE_INTEGER clusterSize = {512, 0};
  3540. char drive[_MAX_DRIVE] = "?:";
  3541. DWORD sectorsPerCluster;
  3542. DWORD bytesPerSector;
  3543. if (!FileTable) {
  3544. return FALSE;
  3545. }
  3546. sizeOfFiles.QuadPart = 0;
  3547. if (EnumFirstHashTableStringW (&e, FileTable)) {
  3548. do {
  3549. KnownSizeUnicodeToDbcsN(filePathNameA, e.String, wcslen(e.String) + 1);
  3550. h = FindFirstFileA (filePathNameA, &fileAttributeData);
  3551. if(h != INVALID_HANDLE_VALUE) {
  3552. FindClose (h);
  3553. if(!(fileAttributeData.dwFileAttributes&FILE_ATTRIBUTE_DIRECTORY)){
  3554. fileSize.LowPart = fileAttributeData.nFileSizeLow;
  3555. fileSize.HighPart = fileAttributeData.nFileSizeHigh;
  3556. sizeOfFiles.QuadPart += fileSize.QuadPart;
  3557. numberOfFiles++;
  3558. if(AmountOfSpaceClusterAligned){
  3559. if(UNKNOWN_DRIVE == drive[0]){
  3560. drive[0] = filePathNameA[0];
  3561. if(GetDiskFreeSpaceA(drive, &sectorsPerCluster, &bytesPerSector, NULL, NULL)){
  3562. clusterSize.QuadPart = sectorsPerCluster * bytesPerSector;
  3563. AmountOfSpaceClusterAligned->QuadPart = 0;
  3564. }
  3565. else{
  3566. DEBUGMSG((DBG_VERBOSE, "GetDiskFreeSpace failed in GetDiskSpaceForFilesList"));
  3567. AmountOfSpaceClusterAligned = NULL;
  3568. continue;
  3569. }
  3570. }
  3571. AmountOfSpaceClusterAligned->QuadPart +=
  3572. fileSize.QuadPart % clusterSize.QuadPart? // || sizeOfFiles.QuadPart == NULL
  3573. ((fileSize.QuadPart / clusterSize.QuadPart) + 1) * clusterSize.QuadPart:
  3574. fileSize.QuadPart;
  3575. }
  3576. }
  3577. if(ProcessDirs){
  3578. AddDirPathToEmptyDirsCategoryA(filePathNameA, TRUE, TRUE);
  3579. }
  3580. MYASSERT(DirPath);
  3581. }
  3582. else {
  3583. //DEBUGMSGA((DBG_VERBOSE, "SETUP: GetDiskSpaceForFilesList - file does not exist: %s", filePathNameA));
  3584. }
  3585. } while (EnumNextHashTableStringW (&e));
  3586. }
  3587. if(!BootCabImagePadding) {
  3588. BootCabImagePaddingInBytes.QuadPart = BACKUP_DISK_SPACE_PADDING_DEFAULT;
  3589. DEBUGMSG ((DBG_VERBOSE, "Disk space padding for backup image: %i MB (DEFAULT)", BootCabImagePadding));
  3590. }
  3591. else{
  3592. BootCabImagePaddingInBytes.QuadPart = BootCabImagePadding;
  3593. BootCabImagePaddingInBytes.QuadPart <<= 20;
  3594. DEBUGMSG ((DBG_VERBOSE, "Disk space padding for backup image: %i MB", BootCabImagePadding));
  3595. }
  3596. if(AmountOfSpaceClusterAligned){
  3597. AmountOfSpaceClusterAligned->QuadPart += BootCabImagePaddingInBytes.QuadPart;
  3598. }
  3599. if(AmountOfSpace) {
  3600. AmountOfSpace->QuadPart = sizeOfFiles.QuadPart + BootCabImagePaddingInBytes.QuadPart;
  3601. }
  3602. if(AmountOfSpaceIfCompressed) {
  3603. if(!CompressionFactor) {
  3604. CompressionFactor = COMPRESSION_RATE_DEFAULT;
  3605. DEBUGMSG ((DBG_VERBOSE, "Compression factor: %i (DEFAULT)", CompressionFactor));
  3606. }
  3607. ELSE_DEBUGMSG ((DBG_VERBOSE, "Compression factor: %i", CompressionFactor));
  3608. AmountOfSpaceIfCompressed->QuadPart =
  3609. (sizeOfFiles.QuadPart * CompressionFactor) / 100 +
  3610. STARTUP_INFORMATION_BYTES_NUMBER * numberOfFiles + BootCabImagePaddingInBytes.QuadPart;//boot.cab
  3611. }
  3612. return TRUE;
  3613. }
  3614. #if 0
  3615. BOOL
  3616. pGetTruePathName (
  3617. IN PCWSTR InPath,
  3618. OUT PWSTR OutPath
  3619. )
  3620. {
  3621. PCSTR start;
  3622. PCSTR end;
  3623. WIN32_FIND_DATAA fd;
  3624. PCSTR ansiInPath;
  3625. CHAR ansiOutPath[MAX_MBCHAR_PATH];
  3626. HANDLE findHandle;
  3627. PSTR p;
  3628. //
  3629. // If not a local path, ignore it. If longer than MAX_PATH, ignore it.
  3630. //
  3631. if (!InPath[0] || InPath[1] != L':' || InPath[2] != L'\\') {
  3632. StringCopyW (OutPath, InPath);
  3633. return;
  3634. }
  3635. if (TcharCount (InPath) >= MAX_PATH) {
  3636. StringCopyW (OutPath, InPath);
  3637. return;
  3638. }
  3639. //
  3640. // Convert down to ANSI because Win9x API requirements
  3641. //
  3642. ansiInPath = ConvertWtoA (InPath);
  3643. //
  3644. // Copy the drive spec
  3645. //
  3646. start = ansiInPath;
  3647. end = start + 2;
  3648. MYASSERT (*end == '\\');
  3649. p = ansiOutPath;
  3650. StringCopyABA (p, start, end);
  3651. p = GetEndOfStringA (p);
  3652. //
  3653. // Walk the path, and for each segment, get the full name via
  3654. // FindFirstFile
  3655. //
  3656. start = end + 1;
  3657. end = _mbschr (start, '\\');
  3658. if (!end) {
  3659. end = GetEndOfStringA (start);
  3660. }
  3661. for (;;) {
  3662. if (end > start + 1) {
  3663. *p++ = '\\';
  3664. StringCopyABA (p, start, end);
  3665. findHandle = FindFirstFileA (ansiOutPath, &fd);
  3666. if (findHandle == INVALID_HANDLE_VALUE) {
  3667. //
  3668. // File/directory does not exist. Use the remaining
  3669. // string as passed in.
  3670. //
  3671. StringCopyA (p, start);
  3672. DEBUGMSGA ((DBG_ERROR, "File %s not found", ansiInPath));
  3673. KnownSizeAtoW (OutPath, ansiOutPath);
  3674. FreeConvertedStr (ansiInPath);
  3675. return FALSE;
  3676. }
  3677. //
  3678. // Copy the file system's value to the out buffer
  3679. //
  3680. StringCopyA (p, fd.cFileName);
  3681. p = GetEndOfStringA (p);
  3682. FindClose (findHandle);
  3683. }
  3684. //
  3685. // Advance to the next segment
  3686. //
  3687. if (*end) {
  3688. start = end + 1;
  3689. end = _mbschr (start, '\\');
  3690. if (!end) {
  3691. end = GetEndOfStringA (start);
  3692. }
  3693. } else {
  3694. break;
  3695. }
  3696. }
  3697. KnownSizeAtoW (OutPath, ansiOutPath);
  3698. FreeConvertedStr (ansiInPath);
  3699. return TRUE;
  3700. }
  3701. #endif
  3702. VOID
  3703. pPutInBackupTable (
  3704. IN HASHTABLE BackupTable,
  3705. IN HASHTABLE SourceTable,
  3706. IN PCWSTR Path
  3707. )
  3708. {
  3709. if (pIsExcludedFromBackupW (Path, NULL)) {
  3710. return;
  3711. }
  3712. if (!HtFindStringW (SourceTable, Path)) {
  3713. HtAddStringW (SourceTable, Path);
  3714. MarkFileForBackupW (Path);
  3715. HtAddStringW (BackupTable, Path);
  3716. }
  3717. }
  3718. VOID
  3719. pPutInDelFileTable (
  3720. IN HASHTABLE DelFileTable,
  3721. IN HASHTABLE DestTable,
  3722. IN PCWSTR Path
  3723. )
  3724. {
  3725. if (!HtFindStringW (DestTable, Path)) {
  3726. HtAddStringW (DestTable, Path);
  3727. HtAddStringW (DelFileTable, Path);
  3728. }
  3729. }
  3730. BOOL
  3731. pIsWinDirProfilesPath (
  3732. IN PCWSTR PathToTest
  3733. )
  3734. {
  3735. static WCHAR winDirProfiles[MAX_PATH];
  3736. CHAR winDirProfilesA[MAX_PATH];
  3737. if (!(winDirProfiles[0])) {
  3738. GetWindowsDirectoryA (winDirProfilesA, MAX_PATH - 9);
  3739. KnownSizeAtoW (winDirProfiles, winDirProfilesA);
  3740. StringCatW (winDirProfiles, L"\\Profiles");
  3741. }
  3742. return StringIMatchW (PathToTest, winDirProfiles);
  3743. }
  3744. BOOL
  3745. WriteBackupFilesA (
  3746. IN BOOL Win9xSide,
  3747. IN PCSTR TempDir,
  3748. OUT ULARGE_INTEGER * OutAmountOfSpaceIfCompressed, OPTIONAL
  3749. OUT ULARGE_INTEGER * OutAmountOfSpace, OPTIONAL
  3750. IN INT CompressionFactor, OPTIONAL
  3751. IN INT BootCabImagePadding, OPTIONAL
  3752. OUT ULARGE_INTEGER * OutAmountOfSpaceForDelFiles, OPTIONAL
  3753. OUT ULARGE_INTEGER * OutAmountOfSpaceClusterAligned OPTIONAL
  3754. )
  3755. /*++
  3756. Routine Description:
  3757. WriteBackupFiles outputs the files needed by the text mode backup engine
  3758. to create a backup image. This includes:
  3759. backup.txt - Lists all files that need to be backed up, either
  3760. because they are Win9x-specific, or are replaced
  3761. during the upgrade.
  3762. moved.txt - Lists all files that were moved from a Win9x location
  3763. to a temporary or NT location
  3764. delfiles.txt - Lists all files that are new to the upgraded OS
  3765. deldirs.txt - Lists subdirectories that are new to the upgraded OS
  3766. Arguments:
  3767. Win9xSide - Specifies TRUE if setup is running on Win9x. This causes the
  3768. files to be generated for the rollback of an incomplete setup.
  3769. Specifies FALSE if setup is running on NT. This causes the
  3770. files to be generated for the rollback of the final NT OS.
  3771. TempDir - Specifies the setup temporary directory (%windir%\setup).
  3772. OutAmountOfSpaceIfCompressed - return amount of space for backup files, if
  3773. compression will apply.
  3774. OutAmountOfSpace - return amount of space for backup files, if compression
  3775. will not apply.
  3776. CompressionFactor - receives the compression factor in 0..100 range.
  3777. BootCabImagePadding - receives the backup disk space padding for
  3778. additional files.
  3779. Return Value:
  3780. TRUE if the files were created successfully, FALSE otherwise.
  3781. --*/
  3782. {
  3783. MEMDB_ENUMW e;
  3784. TREE_ENUMA treeEnumA;
  3785. PCSTR ansiRoot;
  3786. PCSTR ansiFullPath;
  3787. PCWSTR unicodeFullPath;
  3788. PCWSTR unicodeTempDir = NULL;
  3789. PBYTE bufferRoot;
  3790. PWSTR buffer;
  3791. WCHAR pattern[MAX_PATH];
  3792. DWORD bytesWritten;
  3793. DWORD Count = 0;
  3794. PWSTR srcFile = NULL;
  3795. PWSTR destFile = NULL;
  3796. DWORD status;
  3797. HANDLE backupFileList = INVALID_HANDLE_VALUE;
  3798. HANDLE movedOutput = INVALID_HANDLE_VALUE;
  3799. HANDLE delDirsList = INVALID_HANDLE_VALUE;
  3800. HANDLE mkDirsList = INVALID_HANDLE_VALUE;
  3801. HANDLE delFilesList = INVALID_HANDLE_VALUE;
  3802. HASHTABLE backupTable = NULL;
  3803. HASHTABLE delFileTable = NULL;
  3804. HASHTABLE delDirTable = NULL;
  3805. HASHTABLE mkDirsTable = NULL;
  3806. HASHTABLE srcTable = HtAllocExW (FALSE, 0, 41911);
  3807. HASHTABLE destTable = HtAllocExW (FALSE, 0, 41911);
  3808. UINT type;
  3809. ULARGE_INTEGER AmountOfSpace;
  3810. ULARGE_INTEGER AmountOfSpaceIfCompressed;
  3811. ULARGE_INTEGER AmountOfSpaceClusterAligned;
  3812. ULARGE_INTEGER FreeBytesAvailableUser;
  3813. ULARGE_INTEGER TotalNumberOfBytes;
  3814. ULARGE_INTEGER FreeBytesAvailable;
  3815. DWORD attribs;
  3816. PCSTR ansiFile;
  3817. PWSTR entryName;
  3818. DWORD fileAttributes;
  3819. PCSTR dirName;
  3820. BOOL IsDirExist;
  3821. UINT depth;
  3822. POOLHANDLE moveListPool;
  3823. MOVELISTW moveList;
  3824. BOOL result = FALSE;
  3825. HASHTABLE_ENUM htEnum;
  3826. PWSTR thisDir;
  3827. PWSTR lastDir;
  3828. PWSTR p;
  3829. FILEOP_ENUMW OpEnum;
  3830. ALL_FILEOPS_ENUMW allOpEnum;
  3831. __try {
  3832. bufferRoot = MemAllocUninit ((MEMDB_MAX * 6) * sizeof (WCHAR));
  3833. if (!bufferRoot) {
  3834. __leave;
  3835. }
  3836. srcFile = (PWSTR) bufferRoot;
  3837. destFile = srcFile + MEMDB_MAX;
  3838. buffer = destFile + MEMDB_MAX;
  3839. thisDir = buffer + MEMDB_MAX;
  3840. lastDir = thisDir + MEMDB_MAX;
  3841. entryName = lastDir + MEMDB_MAX;
  3842. //
  3843. // Open the output files
  3844. //
  3845. backupTable = HtAllocExW(TRUE, 0, 31013);
  3846. delFileTable = HtAllocExW(TRUE, 0, 10973);
  3847. delDirTable = HtAllocExW(TRUE, 0, 23);
  3848. delFilesList = pCreateFileList (TempDir, "delfiles.txt", TRUE);
  3849. delDirsList = pCreateFileList (TempDir, "deldirs.txt", TRUE);
  3850. moveListPool = PoolMemInitNamedPool ("Reverse Move List");
  3851. if (!moveListPool) {
  3852. DEBUGMSG ((DBG_ERROR, "Can't create move list pool"));
  3853. __leave;
  3854. }
  3855. moveList = AllocateMoveListW (moveListPool);
  3856. if (!moveList) {
  3857. DEBUGMSG ((DBG_ERROR, "Can't create move list"));
  3858. __leave;
  3859. }
  3860. if (delFilesList == INVALID_HANDLE_VALUE ||
  3861. delDirsList == INVALID_HANDLE_VALUE
  3862. ) {
  3863. DEBUGMSG ((DBG_ERROR, "Can't open one of the backup files"));
  3864. __leave;
  3865. }
  3866. if (Win9xSide) {
  3867. mkDirsTable = HtAllocExW(TRUE, 0, 0);
  3868. backupFileList = pCreateFileList (TempDir, "backup.txt", FALSE);
  3869. mkDirsList = pCreateFileList (TempDir, "mkdirs.txt", TRUE);
  3870. if (backupFileList == INVALID_HANDLE_VALUE ||
  3871. mkDirsList == INVALID_HANDLE_VALUE
  3872. ) {
  3873. DEBUGMSG ((DBG_ERROR, "Can't open one of the backup files"));
  3874. __leave;
  3875. }
  3876. }
  3877. unicodeTempDir = ConvertAtoW (TempDir);
  3878. //
  3879. // Go through the registered operations and put the reverse action
  3880. // in the undo hash tables. As files are processed here, they are
  3881. // recorded in the source and dest hash tables, so they don't end
  3882. // up in multiple hash tables.
  3883. //
  3884. if (EnumFirstPathInOperationW (&OpEnum, OPERATION_LONG_FILE_NAME)) {
  3885. do {
  3886. //
  3887. // Ignore excluded files
  3888. // Ignore already processed files
  3889. //
  3890. // we fix this with case-insensitive srcTable and rely on
  3891. // the first entry being the proper case
  3892. //pGetTruePathName (OpEnum.Path, caseCorrectName);
  3893. if (pIsExcludedFromBackupW (OpEnum.Path, unicodeTempDir)) {
  3894. continue;
  3895. }
  3896. if (HtFindStringW (srcTable, OpEnum.Path)) {
  3897. continue;
  3898. }
  3899. //
  3900. // If this is a preserved dir, then put it in mkdirs.txt
  3901. //
  3902. if (mkDirsTable) {
  3903. MYASSERT (Win9xSide);
  3904. if (IsDirectoryMarkedAsEmptyW (OpEnum.Path)) {
  3905. ansiFile = ConvertWtoA (OpEnum.Path);
  3906. if (ansiFile) {
  3907. attribs = GetFileAttributesA (ansiFile);
  3908. if (attribs != INVALID_ATTRIBUTES) {
  3909. if (attribs & FILE_ATTRIBUTE_DIRECTORY) {
  3910. HtAddStringW (mkDirsTable, OpEnum.Path);
  3911. }
  3912. }
  3913. FreeConvertedStr (ansiFile);
  3914. }
  3915. }
  3916. }
  3917. //
  3918. // Process the source file given in OpEnum.Path
  3919. //
  3920. status = GetFileInfoOnNtW (OpEnum.Path, destFile, MEMDB_MAX);
  3921. if (status & FILESTATUS_BACKUP) {
  3922. //
  3923. // This file is going to change -- back it up
  3924. //
  3925. if (backupFileList != INVALID_HANDLE_VALUE) {
  3926. //
  3927. // If this file is a directory, then back up the whole tree
  3928. //
  3929. ansiFile = ConvertWtoA (OpEnum.Path);
  3930. attribs = GetFileAttributesA (ansiFile);
  3931. if (attribs != INVALID_ATTRIBUTES &&
  3932. (attribs & FILE_ATTRIBUTE_DIRECTORY)
  3933. ) {
  3934. if (EnumFirstFileInTreeA (&treeEnumA, ansiFile, NULL, FALSE)) {
  3935. do {
  3936. unicodeFullPath = ConvertAtoW (treeEnumA.FullPath);
  3937. pPutInBackupTable (backupTable, srcTable, unicodeFullPath);
  3938. FreeConvertedStr (unicodeFullPath);
  3939. } while (EnumNextFileInTreeA (&treeEnumA));
  3940. }
  3941. } else if (attribs != INVALID_ATTRIBUTES) {
  3942. pPutInBackupTable (backupTable, srcTable, OpEnum.Path);
  3943. }
  3944. FreeConvertedStr (ansiFile);
  3945. }
  3946. //
  3947. // If the file is also going to be moved, remove the dest copy
  3948. //
  3949. if (status & FILESTATUS_MOVED) {
  3950. HtAddStringW (delFileTable, destFile);
  3951. }
  3952. //
  3953. // Keep track that we're done for good with the source
  3954. // file and dest file
  3955. //
  3956. HtAddStringW (srcTable, OpEnum.Path);
  3957. HtAddStringW (destTable, destFile);
  3958. } else if (!Win9xSide && (status & FILESTATUS_MOVED)) {
  3959. if (!pIsWinDirProfilesPath (OpEnum.Path)) {
  3960. //
  3961. // This file isn't going to change, but it will be moved
  3962. //
  3963. InsertMoveIntoListW (
  3964. moveList,
  3965. destFile,
  3966. OpEnum.Path
  3967. );
  3968. //
  3969. // Keep track that we're done for good with the source
  3970. // file and dest file
  3971. //
  3972. HtAddStringW (srcTable, OpEnum.Path);
  3973. HtAddStringW (destTable, destFile);
  3974. }
  3975. }
  3976. //
  3977. // Update UI
  3978. //
  3979. Count++;
  3980. if (!(Count % 128)) {
  3981. if (!TickProgressBar ()) {
  3982. __leave;
  3983. }
  3984. }
  3985. } while (EnumNextPathInOperationW (&OpEnum));
  3986. }
  3987. //
  3988. // On the Win9x side, put the temp file moves in the move hash table, so
  3989. // that they are returned back to their original locations.
  3990. //
  3991. if (Win9xSide) {
  3992. if (EnumFirstFileOpW (&allOpEnum, OPERATION_FILE_MOVE|OPERATION_TEMP_PATH, NULL)) {
  3993. do {
  3994. //
  3995. // only take into account the first destination of a file
  3996. // (when allOpEnum.PropertyNum == 0)
  3997. // all other destinations are not relevant for textmode move
  3998. //
  3999. if (allOpEnum.PropertyValid && allOpEnum.PropertyNum == 0) {
  4000. if (!pIsWinDirProfilesPath (allOpEnum.Path)) {
  4001. InsertMoveIntoListW (
  4002. moveList,
  4003. allOpEnum.Property,
  4004. allOpEnum.Path
  4005. );
  4006. }
  4007. Count++;
  4008. if (!(Count % 256)) {
  4009. if (!TickProgressBar ()) {
  4010. __leave;
  4011. }
  4012. }
  4013. }
  4014. } while (EnumNextFileOpW (&allOpEnum));
  4015. }
  4016. //
  4017. // Enumerate all the SfTemp values and add them to the list of things to move.
  4018. //
  4019. if (MemDbGetValueExW (&e, MEMDB_CATEGORY_SF_TEMPW, NULL, NULL)) {
  4020. do {
  4021. if (MemDbBuildKeyFromOffsetW (e.dwValue, srcFile, 1, NULL)) {
  4022. if (!pIsWinDirProfilesPath (srcFile)) {
  4023. InsertMoveIntoListW (
  4024. moveList,
  4025. e.szName,
  4026. srcFile
  4027. );
  4028. }
  4029. Count++;
  4030. if (!(Count % 256)) {
  4031. if (!TickProgressBar ()) {
  4032. __leave;
  4033. }
  4034. }
  4035. }
  4036. } while (MemDbEnumNextValueW (&e));
  4037. }
  4038. //
  4039. // Enumerate all DirsCollision values and add them to the list of things to move.
  4040. //
  4041. if (MemDbGetValueExW (&e, MEMDB_CATEGORY_DIRS_COLLISIONW, NULL, NULL)) {
  4042. do {
  4043. if (EnumFirstFileOpW (&allOpEnum, OPERATION_FILE_MOVE, e.szName)) {
  4044. if (!pIsWinDirProfilesPath (allOpEnum.Path)) {
  4045. InsertMoveIntoListW (
  4046. moveList,
  4047. allOpEnum.Property,
  4048. e.szName
  4049. );
  4050. }
  4051. }
  4052. } while (MemDbEnumNextValueW (&e));
  4053. }
  4054. }
  4055. //
  4056. // Process the NT file list, adding files specific to NT to the delete hash table
  4057. //
  4058. if (delFilesList != INVALID_HANDLE_VALUE) {
  4059. MemDbBuildKeyW (pattern, MEMDB_CATEGORY_NT_FILESW, L"*", NULL, NULL);
  4060. if (MemDbEnumFirstValueW (&e, pattern, MEMDB_ALL_SUBLEVELS, MEMDB_ENDPOINTS_ONLY)) {
  4061. do {
  4062. if (MemDbBuildKeyFromOffsetW (e.dwValue, buffer, 1, NULL)) {
  4063. StringCopyW (AppendWackW (buffer), e.szName);
  4064. pPutInDelFileTable (delFileTable, destTable, buffer);
  4065. }
  4066. Count++;
  4067. if (!(Count % 128)) {
  4068. if (!TickProgressBar ()) {
  4069. __leave;
  4070. }
  4071. }
  4072. } while (MemDbEnumNextValueW (&e));
  4073. }
  4074. }
  4075. //
  4076. // Append the remaining files to the backup (Win9xSide) or delete
  4077. // (!Win9xSide) lists by scanning the current file system. These specs
  4078. // mostly come from win95upg.inf's [Backup] section. This INF is
  4079. // parsed during WINNT32 and converted into memdb operations. The
  4080. // memdb operations persist to the GUI mode side automatically, as
  4081. // memdb is saved before reboot to text mode and is reloaded in GUI
  4082. // mode.
  4083. //
  4084. if (MemDbEnumFirstValueW (
  4085. &e,
  4086. MEMDB_CATEGORY_CLEAN_OUTW L"\\*",
  4087. MEMDB_ALL_SUBLEVELS,
  4088. MEMDB_ENDPOINTS_ONLY
  4089. )) {
  4090. do {
  4091. type = e.dwValue;
  4092. //
  4093. // If on Win9x, and if type is BACKUP_SUBDIRECTORY_TREE, then
  4094. // back up the entire tree as well as putting it in the
  4095. // deldirs.txt file.
  4096. //
  4097. if (Win9xSide) {
  4098. if (type == BACKUP_SUBDIRECTORY_TREE) {
  4099. type = BACKUP_AND_CLEAN_TREE;
  4100. } else if (type == BACKUP_AND_CLEAN_SUBDIR) {
  4101. type = BACKUP_SUBDIRECTORY_FILES;
  4102. }
  4103. }
  4104. if (type == BACKUP_FILE) {
  4105. //
  4106. // file
  4107. //
  4108. if (Win9xSide) {
  4109. //
  4110. // This is a single file or directory specification.
  4111. // - If it exists as a file, then back it up.
  4112. // - If it exists as a directory, then back up its
  4113. // contents (if any).
  4114. // - If it does not exist, put it in the delete list.
  4115. //
  4116. ansiFile = ConvertWtoA (e.szName);
  4117. attribs = GetFileAttributesA (ansiFile);
  4118. if (attribs != INVALID_ATTRIBUTES) {
  4119. if (attribs & FILE_ATTRIBUTE_DIRECTORY) {
  4120. if (EnumFirstFileInTreeA (&treeEnumA, ansiFile, NULL, FALSE)) {
  4121. do {
  4122. unicodeFullPath = ConvertAtoW (treeEnumA.FullPath);
  4123. pPutInBackupTable (backupTable, srcTable, unicodeFullPath);
  4124. FreeConvertedStr (unicodeFullPath);
  4125. } while (EnumNextFileInTreeA (&treeEnumA));
  4126. }
  4127. } else {
  4128. pPutInBackupTable (backupTable, srcTable, e.szName);
  4129. }
  4130. } else {
  4131. pPutInDelFileTable (delFileTable, destTable, e.szName);
  4132. }
  4133. FreeConvertedStr (ansiFile);
  4134. } else {
  4135. //
  4136. // Put this file/subdirectory in the delete list
  4137. // unless it was either backed up or is the
  4138. // destination of a move. Note we rely on the fact
  4139. // that every time a file was put in the backup table
  4140. // on Win9xSide, it was also marked for explicit
  4141. // backup. This causes the loop at the top of this
  4142. // function to put the proper file spec in destTable.
  4143. //
  4144. GetNewPathForFileW (e.szName, buffer);
  4145. pPutInDelFileTable (delFileTable, destTable, buffer);
  4146. }
  4147. } else {
  4148. //
  4149. // directory or tree
  4150. //
  4151. if (Win9xSide || type != BACKUP_AND_CLEAN_TREE) {
  4152. //
  4153. // Record backup or single dir cleanup
  4154. //
  4155. if (!Win9xSide) {
  4156. GetNewPathForFileW (e.szName, buffer);
  4157. ansiRoot = ConvertWtoA (buffer);
  4158. } else {
  4159. ansiRoot = ConvertWtoA (e.szName);
  4160. }
  4161. if (type == BACKUP_SUBDIRECTORY_FILES ||
  4162. type == BACKUP_AND_CLEAN_SUBDIR
  4163. ) {
  4164. depth = 1;
  4165. } else {
  4166. depth = FILE_ENUM_ALL_LEVELS;
  4167. }
  4168. if (EnumFirstFileInTreeExA (
  4169. &treeEnumA,
  4170. ansiRoot,
  4171. NULL,
  4172. FALSE,
  4173. FALSE,
  4174. depth
  4175. )) {
  4176. do {
  4177. if (treeEnumA.Directory) {
  4178. continue;
  4179. }
  4180. unicodeFullPath = ConvertAtoW (treeEnumA.FullPath);
  4181. if (Win9xSide) {
  4182. //
  4183. // Mark this file for backup and put it in the txt file.
  4184. //
  4185. pPutInBackupTable (backupTable, srcTable, unicodeFullPath);
  4186. } else {
  4187. //
  4188. // Put this file in the delete list unless it was either
  4189. // backed up or is the destination of a move. This is
  4190. // the same logic as the call to pPutInDelFileTable above.
  4191. //
  4192. pPutInDelFileTable (delFileTable, destTable, unicodeFullPath);
  4193. }
  4194. FreeConvertedStr (unicodeFullPath);
  4195. } while (EnumNextFileInTreeA (&treeEnumA));
  4196. }
  4197. FreeConvertedStr (ansiRoot);
  4198. }
  4199. //
  4200. // Write deldirs entry if subdir should be blown away on
  4201. // rollback. (Backup files might be restored after the
  4202. // subdir is blown away.)
  4203. //
  4204. // For backups of type BACKUP_SUBDIRECTORY_TREE, put
  4205. // this subdirectory in the deldirs.txt file on the Win9x
  4206. // side. Deldirs.txt will be re-written in GUI mode
  4207. // without it.
  4208. //
  4209. if (type == BACKUP_AND_CLEAN_TREE) {
  4210. //
  4211. // Record tree deletes
  4212. //
  4213. GetNewPathForFileW (e.szName, buffer);
  4214. HtAddStringW (delDirTable, buffer);
  4215. if (Win9xSide) {
  4216. ansiFullPath = ConvertWtoA (e.szName);
  4217. AddDirPathToEmptyDirsCategoryA(ansiFullPath, TRUE, TRUE);
  4218. FreeConvertedStr (ansiFullPath);
  4219. }
  4220. }
  4221. }
  4222. } while (MemDbEnumNextValue (&e));
  4223. }
  4224. //
  4225. // Disk Space calculation and check for availability
  4226. //
  4227. if(OutAmountOfSpaceIfCompressed || OutAmountOfSpace || OutAmountOfSpaceClusterAligned) {
  4228. AmountOfSpace.QuadPart = 0;
  4229. AmountOfSpaceIfCompressed.QuadPart = 0;
  4230. AmountOfSpaceClusterAligned.QuadPart = 0;
  4231. if(!GetDiskSpaceForFilesList(
  4232. backupTable,
  4233. &AmountOfSpace,
  4234. &AmountOfSpaceIfCompressed,
  4235. CompressionFactor,
  4236. BootCabImagePadding,
  4237. FALSE,
  4238. &AmountOfSpaceClusterAligned
  4239. )) {
  4240. DEBUGMSG((DBG_WHOOPS, "Can't calculate disk space for files. GetDiskSpaceForFilesList - failed.\n"));
  4241. } else {
  4242. //
  4243. // The disk space numbers include the padding necessary to ensure
  4244. // a user's hard disk does not get filled completely
  4245. //
  4246. if (OutAmountOfSpaceIfCompressed) {
  4247. OutAmountOfSpaceIfCompressed->QuadPart = AmountOfSpaceIfCompressed.QuadPart;
  4248. }
  4249. if (OutAmountOfSpace) {
  4250. OutAmountOfSpace->QuadPart = AmountOfSpace.QuadPart;
  4251. }
  4252. if(OutAmountOfSpaceClusterAligned){
  4253. OutAmountOfSpaceClusterAligned->QuadPart = AmountOfSpaceClusterAligned.QuadPart;
  4254. }
  4255. DEBUGMSG((DBG_VERBOSE, "AmountOfSpace: %dMB\nAmountOfSpaceIfCompressed: %dMB\nAmountOfSpaceClusterAligned: %dMB", (UINT)(AmountOfSpace.QuadPart>>20), (UINT)(AmountOfSpaceIfCompressed.QuadPart>>20), (UINT)(AmountOfSpaceClusterAligned.QuadPart>>20)));
  4256. }
  4257. }
  4258. //
  4259. // Disk Space calculation for deldirs
  4260. //
  4261. if(OutAmountOfSpaceForDelFiles) {
  4262. if(!GetDiskSpaceForFilesList(
  4263. delFileTable,
  4264. NULL,
  4265. NULL,
  4266. 0,
  4267. 1,
  4268. FALSE,
  4269. OutAmountOfSpaceForDelFiles
  4270. )) {
  4271. DEBUGMSG((DBG_WHOOPS, "Can't calculate disk space for del files. GetDiskSpaceForFilesList - failed.\n"));
  4272. } else {
  4273. DEBUGMSG((DBG_VERBOSE, "AmountOfSpaceForDelFiles: %d MB", (UINT)(OutAmountOfSpaceForDelFiles->QuadPart>>20)));
  4274. }
  4275. }
  4276. //
  4277. // preserve attributes of all the backup file parent dirs
  4278. //
  4279. if (Win9xSide) {
  4280. lastDir[0] = 0;
  4281. if (EnumFirstHashTableStringW (&htEnum, backupTable)) {
  4282. do {
  4283. //
  4284. // Put the dir attributes or file's parent attributes in
  4285. // memdb. Optimize for the case where there are several
  4286. // files in a row all from the same parent.
  4287. //
  4288. ansiFullPath = ConvertWtoA (htEnum.String);
  4289. attribs = GetFileAttributesA (ansiFullPath);
  4290. if (attribs != INVALID_ATTRIBUTES &&
  4291. !(attribs & FILE_ATTRIBUTE_DIRECTORY)
  4292. ) {
  4293. StringCopyTcharCountW (thisDir, htEnum.String, MEMDB_MAX);
  4294. p = wcsrchr (thisDir, L'\\');
  4295. if (p) {
  4296. *p = 0;
  4297. }
  4298. _wcslwr (thisDir);
  4299. MYASSERT (thisDir[0]);
  4300. } else {
  4301. thisDir[0] = 0;
  4302. lastDir[0] = 0;
  4303. if (attribs != INVALID_ATTRIBUTES) {
  4304. //
  4305. // Optimize for case where dir is normal
  4306. //
  4307. if (attribs == FILE_ATTRIBUTE_DIRECTORY) {
  4308. attribs = INVALID_ATTRIBUTES;
  4309. }
  4310. }
  4311. }
  4312. //
  4313. // record attributes in memdb
  4314. //
  4315. if (attribs != INVALID_ATTRIBUTES) {
  4316. if ((!thisDir[0]) || (!StringMatchW (lastDir, thisDir))) {
  4317. pAddDirWorkerA (ansiFullPath, TRUE, TRUE, attribs);
  4318. StringCopyW (lastDir, thisDir);
  4319. }
  4320. }
  4321. //
  4322. // continue with loop, remembering current dir
  4323. //
  4324. FreeConvertedStr (ansiFullPath);
  4325. Count++;
  4326. if (!(Count % 256)) {
  4327. if (!TickProgressBar ()) {
  4328. __leave;
  4329. }
  4330. }
  4331. } while (EnumNextHashTableStringW (&htEnum));
  4332. }
  4333. }
  4334. //
  4335. // Transfer the empty dirs to a hash table. We could just output the
  4336. // file now but to be consistent at the expense of a few milliseconds
  4337. // we'll use the hash table.
  4338. //
  4339. if (mkDirsTable && MemDbEnumFirstValueW (
  4340. &e,
  4341. MEMDB_CATEGORY_EMPTY_DIRSW L"\\*",
  4342. MEMDB_ALL_SUBLEVELS,
  4343. MEMDB_ENDPOINTS_ONLY
  4344. )) {
  4345. do {
  4346. if (!e.szName[0] ||
  4347. e.szName[1] != L':' ||
  4348. e.szName[2] != L'\\' ||
  4349. !e.szName[3]
  4350. ) {
  4351. //
  4352. // Ignore roots & malformed entries
  4353. //
  4354. continue;
  4355. }
  4356. swprintf(
  4357. entryName,
  4358. e.dwValue? L"%s,%u": L"%s",
  4359. e.szName,
  4360. e.dwValue
  4361. );
  4362. ansiFile = ConvertWtoA (e.szName);
  4363. if (ansiFile) {
  4364. attribs = GetFileAttributesA (ansiFile);
  4365. if (attribs != INVALID_ATTRIBUTES) {
  4366. if (attribs & FILE_ATTRIBUTE_DIRECTORY) {
  4367. HtAddStringW (mkDirsTable, entryName);
  4368. }
  4369. }
  4370. FreeConvertedStr (ansiFile);
  4371. }
  4372. } while (MemDbEnumNextValue (&e));
  4373. }
  4374. //
  4375. // blast the lists to disk
  4376. //
  4377. if (!WriteHashTableToFileW (backupFileList, backupTable)) {
  4378. LOG ((LOG_ERROR, "Unable to write to backup.txt"));
  4379. __leave;
  4380. }
  4381. if (!WriteHashTableToFileW (delFilesList, delFileTable)) {
  4382. LOG ((LOG_ERROR, "Unable to write to delfiles.txt"));
  4383. __leave;
  4384. }
  4385. if (!WriteHashTableToFileW (delDirsList, delDirTable)) {
  4386. LOG ((LOG_ERROR, "Unable to write to deldirs.txt"));
  4387. __leave;
  4388. }
  4389. if (!WriteHashTableToFileW (mkDirsList, mkDirsTable)) {
  4390. LOG ((LOG_ERROR, "Unable to write to mkdirs.txt"));
  4391. __leave;
  4392. }
  4393. //
  4394. // Finalize move list processing. If we are on the Win9x side, then
  4395. // allow nesting collisions (the second arg).
  4396. //
  4397. moveList = RemoveMoveListOverlapW (moveList);
  4398. ansiFullPath = JoinPathsA (TempDir, "uninstall\\moved.txt");
  4399. if (!ansiFullPath) {
  4400. __leave;
  4401. }
  4402. movedOutput = CreateFileA (
  4403. ansiFullPath,
  4404. GENERIC_WRITE,
  4405. 0,
  4406. NULL,
  4407. CREATE_ALWAYS,
  4408. FILE_ATTRIBUTE_NORMAL,
  4409. NULL
  4410. );
  4411. FreePathStringA (ansiFullPath);
  4412. if (!OutputMoveListW (movedOutput, moveList, !Win9xSide)) {
  4413. LOG ((LOG_ERROR,"Unable to write to moved.txt."));
  4414. __leave;
  4415. }
  4416. //
  4417. // Success
  4418. //
  4419. result = TRUE;
  4420. }
  4421. __finally {
  4422. if (backupFileList != INVALID_HANDLE_VALUE) {
  4423. CloseHandle (backupFileList);
  4424. }
  4425. if (movedOutput != INVALID_HANDLE_VALUE) {
  4426. CloseHandle (movedOutput);
  4427. }
  4428. if (delDirsList != INVALID_HANDLE_VALUE) {
  4429. CloseHandle (delDirsList);
  4430. }
  4431. if (mkDirsList != INVALID_HANDLE_VALUE) {
  4432. CloseHandle (mkDirsList);
  4433. }
  4434. if (delFilesList != INVALID_HANDLE_VALUE) {
  4435. CloseHandle (delFilesList);
  4436. }
  4437. HtFree (backupTable);
  4438. HtFree (delFileTable);
  4439. HtFree (delDirTable);
  4440. HtFree (mkDirsTable);
  4441. HtFree (destTable);
  4442. HtFree (srcTable);
  4443. PoolMemDestroyPool (moveListPool);
  4444. FreeConvertedStr (unicodeTempDir);
  4445. if (bufferRoot) {
  4446. FreeMem (bufferRoot);
  4447. }
  4448. }
  4449. return result;
  4450. }