Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

1435 lines
36 KiB

  1. /******************************************************************************
  2. *
  3. * Copyright (c) 1999 Microsoft Corporation
  4. *
  5. * Module Name:
  6. * reslist.cpp
  7. *
  8. * Abstract:
  9. * This file contains the implementation of Restore List.
  10. *
  11. * Revision History:
  12. * Brijesh Krishnaswami (brijeshk) 06/02/00
  13. * created
  14. *
  15. *
  16. ******************************************************************************/
  17. #include <nt.h>
  18. #include <ntrtl.h>
  19. #include <nturtl.h>
  20. #include <windows.h>
  21. #include "restmap.h"
  22. #include "reslist.h"
  23. #include "shlwapi.h"
  24. #include "utils.h"
  25. #ifdef THIS_FILE
  26. #undef THIS_FILE
  27. #endif
  28. static char __szTraceSourceFile[] = __FILE__;
  29. #define THIS_FILE __szTraceSourceFile
  30. #include "dbgtrace.h"
  31. // copy acl
  32. void
  33. CopyAcl(CNode *pNode, BYTE *pbAcl, DWORD cbAcl, BOOL fAclInline)
  34. {
  35. if (pbAcl)
  36. {
  37. HEAP_FREE(pNode->m_pbAcl);
  38. pNode->m_pbAcl = (BYTE *) HEAP_ALLOC(cbAcl);
  39. if (pNode->m_pbAcl)
  40. memcpy(pNode->m_pbAcl, pbAcl, cbAcl);
  41. pNode->m_cbAcl = cbAcl;
  42. pNode->m_fAclInline = fAclInline;
  43. }
  44. }
  45. //
  46. // GetReverseOperation : This function will return the reverse operation of the
  47. // current changelog operation.
  48. //
  49. DWORD
  50. GetReverseOperation(
  51. DWORD dwOpr
  52. )
  53. {
  54. DWORD dwRestoreOpr = OPR_UNKNOWN;
  55. switch( dwOpr )
  56. {
  57. case OPR_FILE_DELETE:
  58. dwRestoreOpr = OPR_FILE_ADD;
  59. break;
  60. case OPR_FILE_ADD :
  61. dwRestoreOpr = OPR_FILE_DELETE;
  62. break;
  63. case OPR_FILE_MODIFY:
  64. dwRestoreOpr = OPR_FILE_MODIFY;
  65. break;
  66. case OPR_SETATTRIB:
  67. dwRestoreOpr = OPR_SETATTRIB;
  68. break;
  69. case OPR_FILE_RENAME:
  70. dwRestoreOpr = OPR_FILE_RENAME;
  71. break;
  72. case OPR_DIR_RENAME:
  73. dwRestoreOpr = OPR_DIR_RENAME;
  74. break;
  75. case OPR_DIR_DELETE:
  76. dwRestoreOpr = OPR_DIR_CREATE;
  77. break;
  78. case OPR_DIR_CREATE:
  79. dwRestoreOpr = OPR_DIR_DELETE;
  80. break;
  81. case OPR_SETACL:
  82. dwRestoreOpr = OPR_SETACL;
  83. break;
  84. default:
  85. dwRestoreOpr = OPR_UNKNOWN;
  86. break;
  87. }
  88. return dwRestoreOpr;
  89. }
  90. //
  91. // AllocateNode : allocates a list node
  92. //
  93. CNode *
  94. AllocateNode(
  95. LPWSTR pPath1,
  96. LPWSTR pPath2)
  97. {
  98. CNode * pNode = NULL;
  99. BOOL fRet = FALSE;
  100. if (! pPath1)
  101. {
  102. fRet = TRUE; // BUGBUG - is this a valid case?
  103. goto Exit;
  104. }
  105. pNode = (CNode *) HEAP_ALLOC( sizeof(CNode) );
  106. if (! pNode )
  107. goto Exit;
  108. // all pointers set to NULL
  109. if ( pPath1 )
  110. STRCOPY(pNode->m_pPath1, pPath1);
  111. if ( pPath2 )
  112. STRCOPY(pNode->m_pPath2, pPath2);
  113. pNode->m_dwOperation = OPR_UNKNOWN;
  114. pNode->m_dwAttributes = 0xFFFFFFFF;
  115. pNode->m_pPrev = NULL;
  116. pNode->m_pNext = NULL;
  117. fRet = TRUE;
  118. Exit:
  119. if (! fRet)
  120. {
  121. // something failed, so cleanup
  122. FreeNode(pNode);
  123. pNode = NULL;
  124. }
  125. return pNode;
  126. }
  127. //
  128. // FreeNode : This function frees a list node
  129. //
  130. VOID
  131. FreeNode(
  132. CNode * pNode
  133. )
  134. {
  135. if ( pNode )
  136. {
  137. HEAP_FREE(pNode->m_pPath1);
  138. HEAP_FREE(pNode->m_pPath2);
  139. HEAP_FREE(pNode->m_pszTemp);
  140. HEAP_FREE(pNode->m_pbAcl);
  141. HEAP_FREE(pNode);
  142. }
  143. }
  144. //
  145. // Looks at an existing node and the new operation coming and decides
  146. // if they can be merged or not.
  147. //
  148. BOOL
  149. CanMerge(
  150. DWORD dwExistingOpr,
  151. DWORD dwNewOpr,
  152. DWORD dwFlags
  153. )
  154. {
  155. BOOL fRet = FALSE;
  156. //
  157. // Don't optimize directory renames
  158. //
  159. if ( OPR_DIR_RENAME == dwExistingOpr ||
  160. OPR_DIR_RENAME == dwNewOpr )
  161. goto Exit;
  162. //
  163. // Don't optimize for rename if the node we find is a delete node
  164. // and the current opr is rename. In such cases since rename is
  165. // dependent on deletion to succeed.
  166. // Example : A -> B , Create A should generate Delete A, B -> A
  167. //
  168. if ( IsRename(dwNewOpr) &&
  169. ( OPR_DIR_DELETE == dwExistingOpr || OPR_FILE_DELETE == dwExistingOpr )
  170. )
  171. goto Exit;
  172. //
  173. // Also Del A, A->B should not merge this can happen if the file is
  174. // getting renamed out of the directory and back.
  175. //
  176. if ( IsRename(dwExistingOpr) &&
  177. ( OPR_DIR_DELETE == dwNewOpr ||
  178. OPR_DIR_CREATE == dwNewOpr ||
  179. OPR_FILE_DELETE == dwNewOpr )
  180. )
  181. goto Exit;
  182. if ( IsRename(dwNewOpr) &&
  183. ( OPR_DIR_DELETE == dwExistingOpr ||
  184. OPR_DIR_CREATE == dwExistingOpr )
  185. )
  186. goto Exit;
  187. //
  188. // Dir + File operations don't merge
  189. //
  190. if ( ( OPR_FILE_DELETE == dwExistingOpr ||
  191. OPR_FILE_MODIFY == dwExistingOpr ||
  192. OPR_FILE_ADD == dwExistingOpr ) &&
  193. ( OPR_DIR_CREATE == dwNewOpr ||
  194. OPR_DIR_DELETE == dwNewOpr )
  195. )
  196. goto Exit;
  197. if ( ( OPR_FILE_DELETE == dwNewOpr ||
  198. OPR_FILE_ADD == dwNewOpr ||
  199. OPR_FILE_MODIFY == dwNewOpr ) &&
  200. ( OPR_DIR_CREATE == dwExistingOpr ||
  201. OPR_DIR_DELETE == dwExistingOpr )
  202. )
  203. goto Exit;
  204. // can merge
  205. fRet = TRUE;
  206. Exit:
  207. return fRet;
  208. }
  209. //
  210. // CRestoreList implementation.
  211. //
  212. CRestoreList::CRestoreList()
  213. {
  214. m_pListHead = m_pListTail = NULL;
  215. }
  216. CRestoreList::~CRestoreList()
  217. {
  218. //
  219. // Destroy the list
  220. //
  221. CNode * pNodeNext = m_pListHead;
  222. CNode * pNode = NULL;
  223. while( pNodeNext )
  224. {
  225. pNode = pNodeNext;
  226. pNodeNext = pNodeNext->m_pNext;
  227. FreeNode( pNode );
  228. }
  229. }
  230. //
  231. // AddNode : Alocates and Adds a tree node to the restore tree.
  232. //
  233. CNode *
  234. CRestoreList::AppendNode(
  235. LPWSTR pPath1,
  236. LPWSTR pPath2)
  237. {
  238. CNode * pNode = NULL;
  239. if ( pPath1 )
  240. {
  241. pNode = AllocateNode( pPath1, pPath2 );
  242. if ( !pNode )
  243. {
  244. goto Exit;
  245. }
  246. if( m_pListHead )
  247. {
  248. CNode * pPrevNode = m_pListTail;
  249. pPrevNode->m_pNext = pNode;
  250. pNode->m_pPrev = pPrevNode;
  251. pNode->m_pNext = NULL;
  252. m_pListTail = pNode;
  253. }
  254. else
  255. {
  256. m_pListHead = pNode;
  257. m_pListTail = pNode;
  258. pNode->m_pPrev = NULL;
  259. pNode->m_pNext = NULL;
  260. }
  261. }
  262. Exit:
  263. return pNode;
  264. }
  265. //
  266. // RemoveNode: Removes a node from the list
  267. //
  268. CNode *
  269. CRestoreList::RemoveNode(
  270. CNode * pNode
  271. )
  272. {
  273. if ( pNode )
  274. {
  275. CNode * pPrevNode = pNode->m_pPrev;
  276. CNode * pNextNode = pNode->m_pNext;
  277. if (pPrevNode)
  278. {
  279. pPrevNode->m_pNext = pNode->m_pNext;
  280. }
  281. if (pNextNode)
  282. {
  283. pNextNode->m_pPrev = pNode->m_pPrev;
  284. }
  285. if ( pNode == m_pListHead )
  286. {
  287. m_pListHead = pNextNode;
  288. }
  289. if ( pNode == m_pListTail )
  290. {
  291. m_pListTail = pPrevNode;
  292. }
  293. pNode->m_pPrev = NULL;
  294. pNode->m_pNext = NULL;
  295. }
  296. return pNode;
  297. }
  298. //
  299. // GetLastNode : finds the most recent candidate to merge
  300. //
  301. CNode *
  302. CRestoreList::GetLastNode(
  303. LPWSTR pPath1,
  304. LPWSTR pPath2,
  305. BOOL fFailOnPrefixMatch
  306. )
  307. {
  308. CNode * pNode = NULL;
  309. pNode = m_pListTail;
  310. while( pNode )
  311. {
  312. //
  313. // If the node has invalid operation skip it.
  314. //
  315. if ( OPR_UNKNOWN == pNode->m_dwOperation )
  316. {
  317. pNode = pNode->m_pPrev;
  318. continue;
  319. }
  320. //
  321. // If node matches, return it
  322. //
  323. if (0 == lstrcmpi(pPath1, pNode->m_pPath1))
  324. goto Exit;
  325. //
  326. // Check for a dependent rename operation, if found we should not
  327. // merge beyond it.
  328. //
  329. if ( pPath1 &&
  330. IsRename(pNode->m_dwOperation) &&
  331. 0 == lstrcmpi(pPath1, pNode->m_pPath2) )
  332. {
  333. pNode = NULL;
  334. goto Exit;
  335. }
  336. //
  337. // Check for swap conditions, if so don't do any optimization.
  338. //
  339. if ( pPath2 &&
  340. IsRename(pNode->m_dwOperation) &&
  341. 0 == lstrcmpi(pPath2, pNode->m_pPath2) )
  342. {
  343. pNode = NULL;
  344. goto Exit;
  345. }
  346. //
  347. // Check if the entire path matches as a prefix, in such a
  348. // case we should fail search because an operation under that
  349. // directory is found.
  350. //
  351. if ( fFailOnPrefixMatch )
  352. {
  353. //
  354. // Check if entire path matches a prefix that means this
  355. // directory has other operations so don't merge.
  356. //
  357. if (StrStrI(pNode->m_pPath1, pPath1))
  358. {
  359. pNode = NULL;
  360. goto Exit;
  361. }
  362. if ( IsRename(pNode->m_dwOperation) &&
  363. StrStrI(pNode->m_pPath2, pPath1))
  364. {
  365. pNode = NULL;
  366. goto Exit;
  367. }
  368. //
  369. // Check if prefix of the path matches with the full path in
  370. // nodelist, means we are moving across directory's lifespan.
  371. // ToDo: Only check for directory life operations
  372. //
  373. if ( IsRename(pNode->m_dwOperation) ||
  374. OPR_DIR_DELETE == pNode->m_dwOperation ||
  375. OPR_DIR_CREATE == pNode->m_dwOperation )
  376. {
  377. if ( StrStrI(pPath1, pNode->m_pPath1) )
  378. {
  379. pNode = NULL;
  380. goto Exit;
  381. }
  382. if ( IsRename(pNode->m_dwOperation) &&
  383. StrStrI(pPath1, pNode->m_pPath2) )
  384. {
  385. pNode = NULL;
  386. goto Exit;
  387. }
  388. if ( pPath2 )
  389. {
  390. if ( StrStrI(pPath2, pNode->m_pPath1) )
  391. {
  392. pNode = NULL;
  393. goto Exit;
  394. }
  395. if ( IsRename(pNode->m_dwOperation) &&
  396. StrStrI(pPath2, pNode->m_pPath2) )
  397. {
  398. pNode = NULL;
  399. goto Exit;
  400. }
  401. }
  402. }
  403. }
  404. pNode = pNode->m_pPrev;
  405. }
  406. Exit:
  407. //
  408. // We have found a potential merge candidate, now check if this is
  409. // a rename node and dest prefix has any operations on it.
  410. //
  411. if ( pNode && IsRename(pNode->m_dwOperation))
  412. {
  413. CNode * pTmpNode = m_pListTail;
  414. while( pTmpNode && pTmpNode != pNode )
  415. {
  416. if ( IsRename(pTmpNode->m_dwOperation) ||
  417. OPR_DIR_DELETE == pTmpNode->m_dwOperation ||
  418. OPR_DIR_CREATE == pTmpNode->m_dwOperation )
  419. {
  420. if ( StrStrI(pNode->m_pPath2, pTmpNode->m_pPath1) )
  421. {
  422. pNode = NULL;
  423. break;
  424. }
  425. if ( IsRename(pTmpNode->m_dwOperation) &&
  426. StrStrI(pNode->m_pPath2, pTmpNode->m_pPath2) )
  427. {
  428. pNode = NULL;
  429. break;
  430. }
  431. }
  432. pTmpNode = pTmpNode->m_pPrev;
  433. }
  434. }
  435. return pNode;
  436. }
  437. //
  438. // CopyNode : Copies node information, destination opr, copy data, etc.
  439. //
  440. BOOL
  441. CRestoreList::CopyNode(
  442. CNode * pSrcNode,
  443. CNode * pDesNode,
  444. BOOL fReplacePPath2
  445. )
  446. {
  447. BOOL fRet = FALSE;
  448. if (pSrcNode && pDesNode)
  449. {
  450. pSrcNode->m_dwOperation = pDesNode->m_dwOperation ;
  451. pSrcNode->m_dwAttributes = pDesNode->m_dwAttributes;
  452. STRCOPY(pSrcNode->m_pszTemp, pDesNode->m_pszTemp);
  453. CopyAcl(pSrcNode, pDesNode->m_pbAcl, pDesNode->m_cbAcl, pDesNode->m_fAclInline);
  454. if ( IsRename(pDesNode->m_dwOperation) && fReplacePPath2 )
  455. {
  456. HEAP_FREE( pSrcNode->m_pPath2 );
  457. pSrcNode->m_pPath2 = pDesNode->m_pPath2;
  458. pDesNode->m_pPath2 = NULL;
  459. }
  460. fRet = TRUE;
  461. }
  462. return fRet;
  463. }
  464. //
  465. // CreateRestoreNode : Creates appropriate restore node
  466. //
  467. CRestoreList::CreateRestoreNode(
  468. CNode * pNode,
  469. DWORD dwOpr,
  470. DWORD dwAttr,
  471. DWORD dwFlags,
  472. LPWSTR pTmpFile,
  473. LPWSTR pPath1,
  474. LPWSTR pPath2,
  475. BYTE* pbAcl,
  476. DWORD cbAcl,
  477. BOOL fAclInline)
  478. {
  479. BOOL fRet = FALSE;
  480. if (pNode)
  481. {
  482. fRet = TRUE;
  483. DWORD dwRestoreOpr = GetReverseOperation( dwOpr );
  484. //
  485. // If Source / Dest paths are same then remove this just
  486. // added node.
  487. //
  488. if ( IsRename(dwRestoreOpr) &&
  489. 0 == lstrcmpi(pNode->m_pPath1,
  490. pNode->m_pPath2) )
  491. {
  492. RemoveNode( pNode );
  493. FreeNode( pNode );
  494. goto Exit;
  495. }
  496. //
  497. // Rename optimizations should not be done for directories.
  498. //
  499. if ( OPR_FILE_RENAME == dwRestoreOpr )
  500. {
  501. //
  502. // Check if the des node already exists in the tree, if so
  503. // copy all the data from that node and delete it. Current
  504. // node effectively represents that node.
  505. //
  506. DWORD dwCurNodeOpr = pNode->m_dwOperation;
  507. CNode *pNodeDes = GetLastNode( pPath2, pPath1, TRUE );
  508. if (pNodeDes &&
  509. OPR_UNKNOWN != pNodeDes->m_dwOperation)
  510. {
  511. //
  512. // Check for Cycle if so remove the current node also
  513. //
  514. if ( OPR_FILE_RENAME == pNodeDes->m_dwOperation &&
  515. !lstrcmpi (pNode->m_pPath1,
  516. pNodeDes->m_pPath2) )
  517. {
  518. //
  519. // The existing node may be a hybrid one so preserve the
  520. // hybrid operations cancel only rename
  521. //
  522. if (! pNodeDes->m_pszTemp &&
  523. pNodeDes->m_dwAttributes == 0xFFFFFFFF &&
  524. pNodeDes->m_pbAcl == NULL)
  525. {
  526. //
  527. // Not a hybrid node - remove it.
  528. //
  529. RemoveNode( pNodeDes );
  530. FreeNode( pNodeDes );
  531. }
  532. else
  533. {
  534. //
  535. // Hybrid Node so change the node to the other
  536. // operations only.
  537. //
  538. HEAP_FREE( pNodeDes->m_pPath1 );
  539. pNodeDes->m_pPath1 = pNodeDes->m_pPath2;
  540. pNodeDes->m_pPath2 = NULL;
  541. pNodeDes->m_dwOperation = OPR_SETATTRIB;
  542. if (pNodeDes->m_pbAcl)
  543. {
  544. pNodeDes->m_dwOperation = OPR_SETACL;
  545. }
  546. if (pNodeDes->m_pszTemp)
  547. {
  548. pNodeDes->m_dwOperation = OPR_FILE_MODIFY;
  549. }
  550. }
  551. //
  552. // Remove the just add node as the operation cancels
  553. // returning false will have that effect
  554. fRet = FALSE;
  555. goto Exit;
  556. }
  557. //
  558. // Remove the matching node from the list
  559. //
  560. RemoveNode( pNodeDes );
  561. //
  562. // Merge the matching node into the current rename node
  563. //
  564. CopyNode( pNode, pNodeDes, TRUE );
  565. //
  566. // Since all the information for modify/attrib/acl is
  567. // copied over, change the opr to rename.
  568. //
  569. if (pNodeDes->m_dwOperation == OPR_SETATTRIB ||
  570. pNodeDes->m_dwOperation == OPR_SETACL ||
  571. pNodeDes->m_dwOperation == OPR_FILE_MODIFY)
  572. {
  573. pNode->m_dwOperation = dwRestoreOpr;
  574. STRCOPY(pNode->m_pPath2, pPath2);
  575. }
  576. //
  577. // If current opr on the node was delete and the newly
  578. // copied operation is create we need to merge these and
  579. // and change the operation to modify
  580. //
  581. // BUGBUG - will this code ever be executed?
  582. // dwCurNodeOpr always seems to be OPR_UNKNOWN
  583. if ( OPR_FILE_ADD == pNodeDes->m_dwOperation &&
  584. OPR_FILE_DELETE == dwCurNodeOpr )
  585. {
  586. pNode->m_dwOperation = OPR_FILE_MODIFY;
  587. }
  588. if ( OPR_DIR_CREATE == pNodeDes->m_dwOperation &&
  589. OPR_DIR_DELETE == dwCurNodeOpr )
  590. {
  591. pNode->m_dwOperation = OPR_SETATTRIB;
  592. }
  593. //
  594. // If the operation is changed from a rename then pPath2 should
  595. // not exist
  596. //
  597. if ( OPR_FILE_RENAME != pNode->m_dwOperation )
  598. {
  599. if ( pNode->m_pPath2 )
  600. {
  601. HEAP_FREE(pNode->m_pPath2);
  602. pNode->m_pPath2 = NULL ;
  603. }
  604. }
  605. FreeNode( pNodeDes );
  606. goto Exit;
  607. }
  608. }
  609. //
  610. // Copy the necessary information into this node.
  611. //
  612. pNode->m_dwOperation = dwRestoreOpr;
  613. pNode->m_dwAttributes = dwAttr;
  614. STRCOPY(pNode->m_pszTemp, pTmpFile);
  615. CopyAcl(pNode, pbAcl, cbAcl, fAclInline);
  616. }
  617. Exit:
  618. return fRet;
  619. }
  620. //
  621. // MergeRestoreNode : Merge the new information into the current retore node
  622. //
  623. BOOL
  624. CRestoreList::MergeRestoreNode(
  625. CNode * pNode,
  626. DWORD dwOpr,
  627. DWORD dwAttr,
  628. DWORD dwFlags,
  629. LPWSTR pTmpFile,
  630. LPWSTR pPath1,
  631. LPWSTR pPath2,
  632. BYTE* pbAcl,
  633. DWORD cbAcl,
  634. BOOL fAclInline)
  635. {
  636. BOOL fRet = FALSE;
  637. if (pNode)
  638. {
  639. DWORD dwRestoreOpr = GetReverseOperation( dwOpr );
  640. // note that dwOpr cannot be a rename operation,
  641. // because we handle that separately in CreateRestoreNode
  642. ASSERT( ! IsRename(dwOpr) );
  643. switch( dwOpr )
  644. {
  645. case OPR_FILE_ADD :
  646. {
  647. //
  648. // If current opr is add and the node already encountered a
  649. // delete opr then remove this node because this is a no-op
  650. //
  651. if ( OPR_FILE_ADD == pNode->m_dwOperation )
  652. {
  653. RemoveNode( pNode );
  654. FreeNode ( pNode );
  655. goto Exit;
  656. }
  657. if ( IsRename(pNode->m_dwOperation) )
  658. {
  659. //
  660. // Change the original node to a delete operation, to
  661. // retain proper order.
  662. //
  663. pNode->m_dwOperation = OPR_FILE_DELETE;
  664. //
  665. // Delete operation should be generated on PPath2
  666. //
  667. if (pNode->m_pPath1)
  668. {
  669. HEAP_FREE( pNode->m_pPath1);
  670. pNode->m_pPath1 = NULL;
  671. }
  672. if (pNode->m_pPath2)
  673. {
  674. pNode->m_pPath1 = pNode->m_pPath2;
  675. pNode->m_pPath2 = NULL;
  676. }
  677. goto Exit;
  678. }
  679. break;
  680. }
  681. case OPR_FILE_DELETE :
  682. {
  683. //
  684. // Delete followd by an add should result in modify
  685. //
  686. if (OPR_FILE_DELETE == pNode->m_dwOperation)
  687. {
  688. pNode->m_dwOperation = OPR_FILE_MODIFY;
  689. pNode->m_dwAttributes = dwAttr;
  690. STRCOPY(pNode->m_pszTemp, pTmpFile);
  691. CopyAcl(pNode, pbAcl, cbAcl, fAclInline);
  692. goto Exit;
  693. }
  694. break;
  695. }
  696. case OPR_FILE_MODIFY:
  697. {
  698. //
  699. // Copy the modified file copy location, don't change
  700. // the current restore operation.
  701. //
  702. if ( OPR_FILE_ADD == pNode->m_dwOperation ||
  703. IsRename(pNode->m_dwOperation) )
  704. {
  705. STRCOPY(pNode->m_pszTemp, pTmpFile);
  706. goto Exit;
  707. }
  708. break;
  709. }
  710. case OPR_SETATTRIB:
  711. {
  712. //
  713. // Don't change the current restore operation just set the attr.
  714. //
  715. if ( OPR_UNKNOWN != pNode->m_dwOperation )
  716. {
  717. pNode->m_dwAttributes = dwAttr;
  718. goto Exit;
  719. }
  720. break;
  721. }
  722. case OPR_SETACL:
  723. {
  724. // setacl followed by any op
  725. // just copy the acl to the new op
  726. if (OPR_UNKNOWN != pNode->m_dwOperation)
  727. {
  728. CopyAcl(pNode, pbAcl, cbAcl, fAclInline);
  729. goto Exit;
  730. }
  731. break;
  732. }
  733. case OPR_DIR_DELETE :
  734. {
  735. //
  736. // if Dir delete followed by a dir create then this
  737. // operation should condense to set attrib + setacl
  738. if ( OPR_DIR_DELETE == pNode->m_dwOperation )
  739. {
  740. //
  741. // Need to change the oprn to set attrib if
  742. // Attribute changed
  743. //
  744. pNode->m_dwOperation = OPR_SETATTRIB;
  745. pNode->m_dwAttributes = dwAttr;
  746. CopyAcl(pNode, pbAcl, cbAcl, fAclInline);
  747. goto Exit;
  748. }
  749. break;
  750. }
  751. case OPR_DIR_CREATE :
  752. {
  753. if ( OPR_DIR_CREATE == pNode->m_dwOperation )
  754. {
  755. RemoveNode( pNode );
  756. FreeNode( pNode );
  757. goto Exit;
  758. }
  759. if ( IsRename(pNode->m_dwOperation) )
  760. {
  761. //
  762. // Check if the existing node has some file operations
  763. // afterwards then don't optimize
  764. //
  765. if ( GetLastNode(
  766. pNode->m_pPath1,
  767. NULL,
  768. TRUE) )
  769. {
  770. //
  771. // Change the last node to a delete operation, to
  772. // retain proper order.
  773. //
  774. pNode->m_dwOperation = OPR_DIR_DELETE;
  775. //
  776. // Delete operation should be generated on PPath2
  777. //
  778. if (pNode->m_pPath1)
  779. {
  780. HEAP_FREE( pNode->m_pPath1);
  781. pNode->m_pPath1 = NULL;
  782. }
  783. if (pNode->m_pPath2)
  784. {
  785. pNode->m_pPath1 = pNode->m_pPath2;
  786. pNode->m_pPath2 = NULL;
  787. }
  788. }
  789. else
  790. {
  791. CNode * pNewNode = NULL;
  792. //
  793. // Create a new dir delete node
  794. //
  795. if (pNewNode = AppendNode(pPath1, pPath2) )
  796. {
  797. fRet = CreateRestoreNode(
  798. pNewNode,
  799. dwOpr,
  800. dwAttr,
  801. dwFlags,
  802. pTmpFile,
  803. pPath1,
  804. pPath2,
  805. pbAcl,
  806. cbAcl,
  807. fAclInline);
  808. }
  809. }
  810. goto Exit;
  811. }
  812. break;
  813. }
  814. }
  815. pNode->m_dwOperation = dwRestoreOpr;
  816. //
  817. // Change the node's attribute only if the new attrib exists
  818. //
  819. if (dwAttr != 0xFFFFFFFF)
  820. pNode->m_dwAttributes = dwAttr;
  821. STRCOPY(pNode->m_pszTemp, pTmpFile);
  822. CopyAcl(pNode, pbAcl, cbAcl, fAclInline);
  823. }
  824. Exit:
  825. return TRUE;
  826. }
  827. BOOL
  828. CRestoreList::CheckIntegrity(
  829. LPWSTR pszDrive,
  830. DWORD dwOpr,
  831. DWORD dwAttr,
  832. DWORD dwFlags,
  833. LPWSTR pTmpFile,
  834. LPWSTR pPath1,
  835. LPWSTR pPath2,
  836. BYTE * pbAcl,
  837. DWORD cbAcl,
  838. BOOL fAclInline)
  839. {
  840. BOOL fRet = TRUE;
  841. WCHAR szPath[MAX_PATH];
  842. // source name MUST be present
  843. if (! pPath1)
  844. {
  845. fRet = FALSE;
  846. goto done;
  847. }
  848. // if acl is present and it's not inline,
  849. // then temp file must exist
  850. if (pbAcl && ! fAclInline)
  851. {
  852. MakeRestorePath(szPath, pszDrive, (LPWSTR) pbAcl);
  853. if (-1 == GetFileAttributes(szPath))
  854. {
  855. fRet = FALSE;
  856. goto done;
  857. }
  858. }
  859. switch (dwOpr)
  860. {
  861. case OPR_FILE_RENAME:
  862. case OPR_DIR_RENAME:
  863. // renames should have dest path and no temp file
  864. if (! pPath2 || pTmpFile)
  865. fRet = FALSE;
  866. break;
  867. case OPR_FILE_MODIFY:
  868. // modify should not have dest path but must have temp file
  869. if (pPath2 || ! pTmpFile)
  870. {
  871. fRet = FALSE;
  872. break;
  873. }
  874. // and the temp file must exist inside the datastore
  875. MakeRestorePath(szPath, pszDrive, pTmpFile);
  876. if (-1 == GetFileAttributes(szPath))
  877. {
  878. fRet = FALSE;
  879. break;
  880. }
  881. break;
  882. case OPR_SETACL:
  883. // acl operation should have acl (either inline or not)
  884. if (! pbAcl)
  885. {
  886. fRet = FALSE;
  887. break;
  888. }
  889. default:
  890. break;
  891. }
  892. done:
  893. return fRet;
  894. }
  895. // AddMergeElement : Adds or merge the current element as appropriate
  896. //
  897. BOOL
  898. CRestoreList::AddMergeElement(
  899. LPWSTR pszDrive,
  900. DWORD dwOpr,
  901. DWORD dwAttr,
  902. DWORD dwFlags,
  903. LPWSTR pTmpFile,
  904. LPWSTR pPath1,
  905. LPWSTR pPath2,
  906. BYTE * pbAcl,
  907. DWORD cbAcl,
  908. BOOL fAclInline)
  909. {
  910. BOOL fRet = FALSE;
  911. CNode * pNode = NULL;
  912. // check to see if the entry is consistent
  913. fRet = CheckIntegrity(pszDrive,
  914. dwOpr,
  915. dwAttr,
  916. dwFlags,
  917. pTmpFile,
  918. pPath1,
  919. pPath2,
  920. pbAcl,
  921. cbAcl,
  922. fAclInline);
  923. if (FALSE == fRet)
  924. {
  925. ASSERT(-1);
  926. goto Exit;
  927. }
  928. if ( pPath1 )
  929. {
  930. if (
  931. //
  932. // Merge for renames are handled inside the Create/Merge funcs
  933. //
  934. ! IsRename(dwOpr) &&
  935. //
  936. // Merge should only be allowed within directory life, check
  937. // node paths to see if there are any directory life oprs.
  938. //
  939. ( pNode = GetLastNode( pPath1, pPath2, TRUE ) ) &&
  940. CanMerge( pNode->m_dwOperation , dwOpr, dwFlags )
  941. )
  942. {
  943. fRet = MergeRestoreNode(
  944. pNode,
  945. dwOpr,
  946. dwAttr,
  947. dwFlags,
  948. pTmpFile,
  949. pPath1,
  950. pPath2,
  951. pbAcl,
  952. cbAcl,
  953. fAclInline);
  954. if (!fRet)
  955. goto Exit;
  956. }
  957. else
  958. {
  959. if (pNode = AppendNode(pPath1, pPath2) )
  960. {
  961. fRet = CreateRestoreNode(
  962. pNode,
  963. dwOpr,
  964. dwAttr,
  965. dwFlags,
  966. pTmpFile,
  967. pPath1,
  968. pPath2,
  969. pbAcl,
  970. cbAcl,
  971. fAclInline);
  972. if (!fRet)
  973. {
  974. //
  975. // We failed to create the node properly, free this node
  976. //
  977. RemoveNode( pNode );
  978. FreeNode( pNode );
  979. //
  980. // We still want to continue
  981. //
  982. fRet = TRUE;
  983. goto Exit;
  984. }
  985. }
  986. }
  987. }
  988. Exit:
  989. return fRet;
  990. }
  991. //
  992. // GenerateRestoreMap : Walk the tree and generates the restore map.
  993. //
  994. BOOL
  995. CRestoreList::GenerateRestoreMap (
  996. HANDLE hFile
  997. )
  998. {
  999. BOOL fRet = FALSE;
  1000. if (hFile)
  1001. {
  1002. CNode * pNode = m_pListHead;
  1003. while (pNode)
  1004. {
  1005. if (! GenerateOperation( pNode , hFile ))
  1006. goto Exit;
  1007. pNode = pNode->m_pNext;
  1008. }
  1009. fRet = TRUE;
  1010. }
  1011. Exit:
  1012. return fRet;
  1013. }
  1014. //
  1015. // GenerateRenameEntry : Callback to write out the renames
  1016. //
  1017. BOOL
  1018. CRestoreList::GenerateRenameEntry(
  1019. CNode * pNode ,
  1020. HANDLE hFile
  1021. )
  1022. {
  1023. BOOL fRet = FALSE;
  1024. if( !pNode || ! IsRename(pNode->m_dwOperation) )
  1025. goto Exit;
  1026. //
  1027. // Check if this rename is no-op , src/des are the same
  1028. //
  1029. if ( IsRename(pNode->m_dwOperation) &&
  1030. lstrcmpi(pNode->m_pPath1, pNode->m_pPath2) == 0)
  1031. {
  1032. goto SkipMainNodeEntry;
  1033. }
  1034. // add rename operation
  1035. fRet = AppendRestoreMapEntry(
  1036. hFile,
  1037. pNode->m_dwOperation,
  1038. 0xFFFFFFFF,
  1039. NULL,
  1040. pNode->m_pPath1,
  1041. pNode->m_pPath2,
  1042. NULL,
  1043. 0,
  1044. 0);
  1045. SkipMainNodeEntry:
  1046. // add modify operation if temp file exists
  1047. if ( pNode->m_pszTemp )
  1048. {
  1049. fRet = AppendRestoreMapEntry(
  1050. hFile,
  1051. OPR_FILE_MODIFY,
  1052. 0xFFFFFFFF,
  1053. pNode->m_pszTemp,
  1054. pNode->m_pPath1,
  1055. NULL,
  1056. NULL,
  1057. 0,
  1058. 0);
  1059. }
  1060. // add setattrib operation if attrib exists
  1061. if ( pNode->m_dwAttributes != 0xFFFFFFFF &&
  1062. pNode->m_dwAttributes != FILE_ATTRIBUTE_DIRECTORY )
  1063. {
  1064. fRet = AppendRestoreMapEntry(
  1065. hFile,
  1066. OPR_SETATTRIB,
  1067. pNode->m_dwAttributes,
  1068. NULL,
  1069. pNode->m_pPath1,
  1070. NULL,
  1071. NULL,
  1072. 0,
  1073. 0);
  1074. }
  1075. // add setacl operation if acl exists
  1076. if ( pNode->m_pbAcl != NULL &&
  1077. pNode->m_cbAcl != 0)
  1078. {
  1079. fRet = AppendRestoreMapEntry(
  1080. hFile,
  1081. OPR_SETACL,
  1082. 0xFFFFFFFF,
  1083. NULL,
  1084. pNode->m_pPath1,
  1085. NULL,
  1086. pNode->m_pbAcl,
  1087. pNode->m_cbAcl,
  1088. pNode->m_fAclInline);
  1089. }
  1090. Exit:
  1091. return fRet;
  1092. }
  1093. BOOL
  1094. CRestoreList::GenerateOperation(
  1095. CNode * pNode ,
  1096. HANDLE hFile
  1097. )
  1098. {
  1099. BOOL fRet = FALSE;
  1100. BYTE bData[4096];
  1101. RestoreMapEntry * pResEntry = (RestoreMapEntry *)bData;
  1102. if( !pNode || OPR_UNKNOWN == pNode->m_dwOperation)
  1103. goto Exit;
  1104. if (IsRename(pNode->m_dwOperation) )
  1105. {
  1106. fRet = GenerateRenameEntry( pNode, hFile );
  1107. goto Exit;
  1108. }
  1109. //
  1110. // Generate operations for Add/Modify/SetAttrib
  1111. //
  1112. // ensure that each persisted entry contains only necessary data
  1113. // e.g. a setattrib entry will not contain a temp filename, or acl
  1114. fRet = AppendRestoreMapEntry(
  1115. hFile,
  1116. pNode->m_dwOperation,
  1117. (pNode->m_dwOperation == OPR_SETATTRIB) ? pNode->m_dwAttributes : 0xFFFFFFFF,
  1118. (pNode->m_dwOperation == OPR_FILE_MODIFY ||
  1119. pNode->m_dwOperation == OPR_FILE_ADD) ? pNode->m_pszTemp : NULL,
  1120. pNode->m_pPath1,
  1121. NULL, // pPath2 should matter only for renames, which are handled separately
  1122. (pNode->m_dwOperation == OPR_SETACL) ? pNode->m_pbAcl : NULL,
  1123. (pNode->m_dwOperation == OPR_SETACL) ? pNode->m_cbAcl : 0,
  1124. (pNode->m_dwOperation == OPR_SETACL) ? pNode->m_fAclInline : 0);
  1125. //
  1126. // Generate an explicit set attrib operation
  1127. // entries except set attrib itself and delete.
  1128. //
  1129. if ( OPR_SETATTRIB != pNode->m_dwOperation &&
  1130. OPR_FILE_DELETE != pNode->m_dwOperation &&
  1131. OPR_DIR_DELETE != pNode->m_dwOperation &&
  1132. pNode->m_dwAttributes != 0xFFFFFFFF &&
  1133. pNode->m_dwAttributes != FILE_ATTRIBUTE_DIRECTORY )
  1134. {
  1135. fRet = AppendRestoreMapEntry(
  1136. hFile,
  1137. OPR_SETATTRIB,
  1138. pNode->m_dwAttributes,
  1139. NULL,
  1140. pNode->m_pPath1,
  1141. NULL,
  1142. NULL,
  1143. 0,
  1144. 0);
  1145. }
  1146. //
  1147. // Generate an explicit set acl if needed
  1148. //
  1149. if ( pNode->m_pbAcl != NULL &&
  1150. pNode->m_cbAcl != 0 &&
  1151. OPR_SETACL != pNode->m_dwOperation &&
  1152. OPR_FILE_DELETE != pNode->m_dwOperation &&
  1153. OPR_DIR_DELETE != pNode->m_dwOperation)
  1154. {
  1155. fRet = AppendRestoreMapEntry(
  1156. hFile,
  1157. OPR_SETACL,
  1158. 0xFFFFFFFF,
  1159. NULL,
  1160. pNode->m_pPath1,
  1161. NULL,
  1162. pNode->m_pbAcl,
  1163. pNode->m_cbAcl,
  1164. pNode->m_fAclInline);
  1165. }
  1166. Exit:
  1167. return fRet;
  1168. }