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.

2745 lines
72 KiB

  1. /*
  2. * foldtwin.c - Folder twin ADT module.
  3. */
  4. /* Headers
  5. **********/
  6. #include "project.h"
  7. #pragma hdrstop
  8. #include "stub.h"
  9. #include "subcycle.h"
  10. /* Constants
  11. ************/
  12. /* pointer array allocation constants */
  13. #define NUM_START_FOLDER_TWIN_PTRS (16)
  14. #define NUM_FOLDER_TWIN_PTRS_TO_ADD (16)
  15. /* Types
  16. ********/
  17. /* internal new folder twin description */
  18. typedef struct _inewfoldertwin
  19. {
  20. HPATH hpathFirst;
  21. HPATH hpathSecond;
  22. HSTRING hsName;
  23. DWORD dwAttributes;
  24. HBRFCASE hbr;
  25. DWORD dwFlags;
  26. }
  27. INEWFOLDERTWIN;
  28. DECLARE_STANDARD_TYPES(INEWFOLDERTWIN);
  29. /* database folder twin list header */
  30. typedef struct _dbfoldertwinlistheader
  31. {
  32. LONG lcFolderPairs;
  33. }
  34. DBFOLDERTWINLISTHEADER;
  35. DECLARE_STANDARD_TYPES(DBFOLDERTWINLISTHEADER);
  36. /* database folder twin structure */
  37. typedef struct _dbfoldertwin
  38. {
  39. /* shared stub flags */
  40. DWORD dwStubFlags;
  41. /* old handle to first folder path */
  42. HPATH hpath1;
  43. /* old handle to second folder path */
  44. HPATH hpath2;
  45. /* old handle to name string */
  46. HSTRING hsName;
  47. /* attributes to match */
  48. DWORD dwAttributes;
  49. }
  50. DBFOLDERTWIN;
  51. DECLARE_STANDARD_TYPES(DBFOLDERTWIN);
  52. /***************************** Private Functions *****************************/
  53. /* Module Prototypes
  54. ********************/
  55. PRIVATE_CODE TWINRESULT MakeINewFolderTwin(HBRFCASE, PCNEWFOLDERTWIN, PINEWFOLDERTWIN);
  56. PRIVATE_CODE void ReleaseINewFolderTwin(PINEWFOLDERTWIN);
  57. PRIVATE_CODE TWINRESULT TwinFolders(PCINEWFOLDERTWIN, PFOLDERPAIR *);
  58. PRIVATE_CODE BOOL FindFolderPair(PCINEWFOLDERTWIN, PFOLDERPAIR *);
  59. PRIVATE_CODE BOOL CreateFolderPair(PCINEWFOLDERTWIN, PFOLDERPAIR *);
  60. PRIVATE_CODE BOOL CreateHalfOfFolderPair(HPATH, HBRFCASE, PFOLDERPAIR *);
  61. PRIVATE_CODE void DestroyHalfOfFolderPair(PFOLDERPAIR);
  62. PRIVATE_CODE BOOL CreateSharedFolderPairData(PCINEWFOLDERTWIN, PFOLDERPAIRDATA *);
  63. PRIVATE_CODE void DestroySharedFolderPairData(PFOLDERPAIRDATA);
  64. PRIVATE_CODE COMPARISONRESULT FolderPairSortCmp(PCVOID, PCVOID);
  65. PRIVATE_CODE COMPARISONRESULT FolderPairSearchCmp(PCVOID, PCVOID);
  66. PRIVATE_CODE BOOL RemoveSourceFolderTwin(POBJECTTWIN, PVOID);
  67. PRIVATE_CODE void UnlinkHalfOfFolderPair(PFOLDERPAIR);
  68. PRIVATE_CODE BOOL FolderTwinIntersectsFolder(PCFOLDERPAIR, HPATH);
  69. PRIVATE_CODE TWINRESULT CreateListOfFolderTwins(HBRFCASE, ARRAYINDEX, HPATH, PFOLDERTWIN *, PARRAYINDEX);
  70. PRIVATE_CODE void DestroyListOfFolderTwins(PFOLDERTWIN);
  71. PRIVATE_CODE TWINRESULT AddFolderTwinToList(PFOLDERPAIR, PFOLDERTWIN, PFOLDERTWIN *);
  72. PRIVATE_CODE TWINRESULT TransplantFolderPair(PFOLDERPAIR, HPATH, HPATH);
  73. PRIVATE_CODE TWINRESULT WriteFolderPair(HCACHEDFILE, PFOLDERPAIR);
  74. PRIVATE_CODE TWINRESULT ReadFolderPair(HCACHEDFILE, HBRFCASE, HHANDLETRANS, HHANDLETRANS);
  75. #ifdef VSTF
  76. PRIVATE_CODE BOOL IsValidPCNEWFOLDERTWIN(PCNEWFOLDERTWIN);
  77. PRIVATE_CODE BOOL IsValidPCFOLDERTWINLIST(PCFOLDERTWINLIST);
  78. PRIVATE_CODE BOOL IsValidPCFOLDERTWIN(PCFOLDERTWIN);
  79. PRIVATE_CODE BOOL IsValidFolderPairHalf(PCFOLDERPAIR);
  80. PRIVATE_CODE BOOL IsValidPCFOLDERPAIRDATA(PCFOLDERPAIRDATA);
  81. #endif
  82. #ifdef DEBUG
  83. PRIVATE_CODE BOOL IsValidPCINEWFOLDERTWIN(PCINEWFOLDERTWIN);
  84. PRIVATE_CODE BOOL AreFolderPairsValid(HPTRARRAY);
  85. #endif
  86. /*
  87. ** MakeINewFolderTwin()
  88. **
  89. **
  90. **
  91. ** Arguments:
  92. **
  93. ** Returns:
  94. **
  95. ** Side Effects: none
  96. */
  97. PRIVATE_CODE TWINRESULT MakeINewFolderTwin(HBRFCASE hbr,
  98. PCNEWFOLDERTWIN pcnftSrc,
  99. PINEWFOLDERTWIN pinftDest)
  100. {
  101. TWINRESULT tr;
  102. ASSERT(IS_VALID_HANDLE(hbr, BRFCASE));
  103. ASSERT(IS_VALID_STRUCT_PTR(pcnftSrc, CNEWFOLDERTWIN));
  104. ASSERT(IS_VALID_WRITE_PTR(pinftDest, CINEWFOLDERTWIN));
  105. if (AddString(pcnftSrc->pcszName, GetBriefcaseNameStringTable(hbr),
  106. GetHashBucketIndex, &(pinftDest->hsName)))
  107. {
  108. HPATHLIST hpl;
  109. hpl = GetBriefcasePathList(hbr);
  110. tr = TranslatePATHRESULTToTWINRESULT(
  111. AddPath(hpl, pcnftSrc->pcszFolder1, &(pinftDest->hpathFirst)));
  112. if (tr == TR_SUCCESS)
  113. {
  114. tr = TranslatePATHRESULTToTWINRESULT(
  115. AddPath(hpl, pcnftSrc->pcszFolder2, &(pinftDest->hpathSecond)));
  116. if (tr == TR_SUCCESS)
  117. {
  118. pinftDest->dwAttributes = pcnftSrc->dwAttributes;
  119. pinftDest->dwFlags = pcnftSrc->dwFlags;
  120. pinftDest->hbr = hbr;
  121. }
  122. else
  123. {
  124. DeletePath(pinftDest->hpathFirst);
  125. MAKEINEWFOLDERTWIN_BAIL:
  126. DeleteString(pinftDest->hsName);
  127. }
  128. }
  129. else
  130. goto MAKEINEWFOLDERTWIN_BAIL;
  131. }
  132. else
  133. tr = TR_OUT_OF_MEMORY;
  134. ASSERT(tr != TR_SUCCESS ||
  135. IS_VALID_STRUCT_PTR(pinftDest, CINEWFOLDERTWIN));
  136. return(tr);
  137. }
  138. /*
  139. ** ReleaseINewFolderTwin()
  140. **
  141. **
  142. **
  143. ** Arguments:
  144. **
  145. ** Returns:
  146. **
  147. ** Side Effects: none
  148. */
  149. PRIVATE_CODE void ReleaseINewFolderTwin(PINEWFOLDERTWIN pinft)
  150. {
  151. ASSERT(IS_VALID_STRUCT_PTR(pinft, CINEWFOLDERTWIN));
  152. DeletePath(pinft->hpathFirst);
  153. DeletePath(pinft->hpathSecond);
  154. DeleteString(pinft->hsName);
  155. return;
  156. }
  157. /*
  158. ** TwinFolders()
  159. **
  160. ** Twins two folders.
  161. **
  162. ** Arguments:
  163. **
  164. ** Returns: TWINRESULT
  165. **
  166. ** Side Effects: none
  167. */
  168. PRIVATE_CODE TWINRESULT TwinFolders(PCINEWFOLDERTWIN pcinft, PFOLDERPAIR *ppfp)
  169. {
  170. PFOLDERPAIR pfp;
  171. TWINRESULT tr;
  172. ASSERT(IS_VALID_STRUCT_PTR(pcinft, CINEWFOLDERTWIN));
  173. ASSERT(IS_VALID_WRITE_PTR(ppfp, PFOLDERPAIR));
  174. /* Are the two folders the same? */
  175. if (ComparePaths(pcinft->hpathFirst, pcinft->hpathSecond) != CR_EQUAL)
  176. {
  177. /* Look for the two folders in existing folder pairs. */
  178. if (FindFolderPair(pcinft, &pfp))
  179. {
  180. /* Found a existing matching folder pair. Complain. */
  181. *ppfp = pfp;
  182. tr = TR_DUPLICATE_TWIN;
  183. }
  184. else
  185. {
  186. /*
  187. * No existing matching folder pairs found. Only allowing twinning to
  188. * paths whose roots are available.
  189. */
  190. if (IsPathVolumeAvailable(pcinft->hpathFirst) &&
  191. IsPathVolumeAvailable(pcinft->hpathSecond))
  192. {
  193. /*
  194. * If this is a new folder subtree pair, check to see if it would
  195. * create a cycle.
  196. */
  197. if (IS_FLAG_SET(pcinft->dwFlags, NFT_FL_SUBTREE))
  198. tr = CheckForSubtreeCycles(
  199. GetBriefcaseFolderPairPtrArray(pcinft->hbr),
  200. pcinft->hpathFirst, pcinft->hpathSecond,
  201. pcinft->hsName);
  202. else
  203. tr = TR_SUCCESS;
  204. if (tr == TR_SUCCESS)
  205. {
  206. if (CreateFolderPair(pcinft, &pfp))
  207. {
  208. *ppfp = pfp;
  209. TRACE_OUT((TEXT("TwinFolders(): Creating %s twin pair %s and %s, files %s."),
  210. IS_FLAG_SET(pcinft->dwFlags, NFT_FL_SUBTREE) ? TEXT("subtree") : TEXT("folder"),
  211. DebugGetPathString(pcinft->hpathFirst),
  212. DebugGetPathString(pcinft->hpathSecond),
  213. GetString(pcinft->hsName)));
  214. }
  215. else
  216. tr = TR_OUT_OF_MEMORY;
  217. }
  218. }
  219. else
  220. tr = TR_UNAVAILABLE_VOLUME;
  221. }
  222. }
  223. else
  224. tr = TR_SAME_FOLDER;
  225. return(tr);
  226. }
  227. /*
  228. ** FindFolderPair()
  229. **
  230. ** Looks for a folder pair matching the given description.
  231. **
  232. ** Arguments: pcinft - pointer to INEWFOLDERTWIN describing folder pair to
  233. ** search for
  234. **
  235. ** Returns: Pointer to PFOLDERPAIR if found. NULL if not found.
  236. **
  237. ** Side Effects: none
  238. */
  239. PRIVATE_CODE BOOL FindFolderPair(PCINEWFOLDERTWIN pcinft, PFOLDERPAIR *ppfp)
  240. {
  241. ARRAYINDEX aiFirst;
  242. ASSERT(IS_VALID_STRUCT_PTR(pcinft, CINEWFOLDERTWIN));
  243. ASSERT(IS_VALID_WRITE_PTR(ppfp, PFOLDERPAIR));
  244. /*
  245. * Search all folder pairs containing the first folder. Then scan all these
  246. * folder pairs for the second folder.
  247. */
  248. *ppfp = NULL;
  249. if (SearchSortedArray(GetBriefcaseFolderPairPtrArray(pcinft->hbr),
  250. &FolderPairSearchCmp, pcinft->hpathFirst, &aiFirst))
  251. {
  252. ARRAYINDEX aicPtrs;
  253. HPTRARRAY hpaFolderPairs;
  254. LONG ai;
  255. PFOLDERPAIR pfp;
  256. /*
  257. * aiFirst holds the index of the first folder pair that
  258. * contains the first folder name.
  259. */
  260. /*
  261. * Now search each of these folder pairs for all paired folders
  262. * using the second folder name.
  263. */
  264. hpaFolderPairs = GetBriefcaseFolderPairPtrArray(pcinft->hbr);
  265. aicPtrs = GetPtrCount(hpaFolderPairs);
  266. ASSERT(aicPtrs > 0);
  267. ASSERT(! (aicPtrs % 2));
  268. ASSERT(aiFirst >= 0);
  269. ASSERT(aiFirst < aicPtrs);
  270. for (ai = aiFirst; ai < aicPtrs; ai++)
  271. {
  272. pfp = GetPtr(hpaFolderPairs, ai);
  273. ASSERT(IS_VALID_STRUCT_PTR(pfp, CFOLDERPAIR));
  274. /* Does this folder pair match the proposed folder pair? */
  275. if (ComparePaths(pfp->hpath, pcinft->hpathFirst) == CR_EQUAL)
  276. {
  277. /*
  278. * An existing pair of folder twins is considered the same as a
  279. * proposed new pair of folder twins when the two pairs of folder
  280. * twins share the same:
  281. * 1) pair of PATHs
  282. * 2) name specification
  283. * 3) file attributes
  284. * 4) subtree flag setting
  285. */
  286. if (ComparePaths(pfp->pfpOther->hpath, pcinft->hpathSecond) == CR_EQUAL &&
  287. CompareNameStringsByHandle(pfp->pfpd->hsName, pcinft->hsName) == CR_EQUAL &&
  288. pfp->pfpd->dwAttributes == pcinft->dwAttributes &&
  289. ((IS_FLAG_SET(pfp->stub.dwFlags, STUB_FL_SUBTREE) &&
  290. IS_FLAG_SET(pcinft->dwFlags, NFT_FL_SUBTREE)) ||
  291. (IS_FLAG_CLEAR(pfp->stub.dwFlags, STUB_FL_SUBTREE) &&
  292. IS_FLAG_CLEAR(pcinft->dwFlags, NFT_FL_SUBTREE))))
  293. {
  294. /* Yes. */
  295. *ppfp = pfp;
  296. break;
  297. }
  298. }
  299. else
  300. break;
  301. }
  302. }
  303. return(*ppfp != NULL);
  304. }
  305. /*
  306. ** CreateFolderPair()
  307. **
  308. ** Creates a new folder pair, and adds them to a briefcase's list of folder
  309. ** pairs.
  310. **
  311. ** Arguments: pcinft - pointer to INEWFOLDERTWIN describing folder pair to
  312. ** create
  313. ** ppfp - pointer to PFOLDERPAIR to be filled in with pointer to
  314. ** half of new folder pair representing
  315. ** pcnft->pcszFolder1
  316. **
  317. ** Returns:
  318. **
  319. ** Side Effects: Adds the new folder pair to the global array of folder pairs.
  320. **
  321. ** N.b., this function does not first check to see if the folder pair already
  322. ** exists in the global list of folder pairs.
  323. */
  324. PRIVATE_CODE BOOL CreateFolderPair(PCINEWFOLDERTWIN pcinft, PFOLDERPAIR *ppfp)
  325. {
  326. BOOL bResult = FALSE;
  327. PFOLDERPAIRDATA pfpd;
  328. ASSERT(IS_VALID_STRUCT_PTR(pcinft, CINEWFOLDERTWIN));
  329. ASSERT(IS_VALID_WRITE_PTR(ppfp, PFOLDERPAIR));
  330. /* Try to create the shared folder data structure. */
  331. if (CreateSharedFolderPairData(pcinft, &pfpd))
  332. {
  333. PFOLDERPAIR pfpNew1;
  334. BOOL bPtr1Loose = TRUE;
  335. if (CreateHalfOfFolderPair(pcinft->hpathFirst, pcinft->hbr, &pfpNew1))
  336. {
  337. PFOLDERPAIR pfpNew2;
  338. if (CreateHalfOfFolderPair(pcinft->hpathSecond, pcinft->hbr,
  339. &pfpNew2))
  340. {
  341. HPTRARRAY hpaFolderPairs;
  342. ARRAYINDEX ai1;
  343. /* Combine the two folder pair halves. */
  344. pfpNew1->pfpd = pfpd;
  345. pfpNew1->pfpOther = pfpNew2;
  346. pfpNew2->pfpd = pfpd;
  347. pfpNew2->pfpOther = pfpNew1;
  348. /* Set flags. */
  349. if (IS_FLAG_SET(pcinft->dwFlags, NFT_FL_SUBTREE))
  350. {
  351. SetStubFlag(&(pfpNew1->stub), STUB_FL_SUBTREE);
  352. SetStubFlag(&(pfpNew2->stub), STUB_FL_SUBTREE);
  353. }
  354. /*
  355. * Try to add the two folder pairs to the global list of folder
  356. * pairs.
  357. */
  358. hpaFolderPairs = GetBriefcaseFolderPairPtrArray(pcinft->hbr);
  359. if (AddPtr(hpaFolderPairs, FolderPairSortCmp, pfpNew1, &ai1))
  360. {
  361. ARRAYINDEX ai2;
  362. bPtr1Loose = FALSE;
  363. if (AddPtr(hpaFolderPairs, FolderPairSortCmp, pfpNew2, &ai2))
  364. {
  365. ASSERT(IS_VALID_STRUCT_PTR(pfpNew1, CFOLDERPAIR));
  366. ASSERT(IS_VALID_STRUCT_PTR(pfpNew2, CFOLDERPAIR));
  367. if (ApplyNewFolderTwinsToTwinFamilies(pfpNew1))
  368. {
  369. *ppfp = pfpNew1;
  370. bResult = TRUE;
  371. }
  372. else
  373. {
  374. DeletePtr(hpaFolderPairs, ai2);
  375. CREATEFOLDERPAIR_BAIL1:
  376. DeletePtr(hpaFolderPairs, ai1);
  377. CREATEFOLDERPAIR_BAIL2:
  378. /*
  379. * Don't try to remove pfpNew2 from the global list of
  380. * folder pairs here since it was never added
  381. * successfully.
  382. */
  383. DestroyHalfOfFolderPair(pfpNew2);
  384. CREATEFOLDERPAIR_BAIL3:
  385. /*
  386. * Don't try to remove pfpNew1 from the global list of
  387. * folder pairs here since it was never added
  388. * successfully.
  389. */
  390. DestroyHalfOfFolderPair(pfpNew1);
  391. CREATEFOLDERPAIR_BAIL4:
  392. DestroySharedFolderPairData(pfpd);
  393. }
  394. }
  395. else
  396. goto CREATEFOLDERPAIR_BAIL1;
  397. }
  398. else
  399. goto CREATEFOLDERPAIR_BAIL2;
  400. }
  401. else
  402. goto CREATEFOLDERPAIR_BAIL3;
  403. }
  404. else
  405. goto CREATEFOLDERPAIR_BAIL4;
  406. }
  407. return(bResult);
  408. }
  409. /*
  410. ** CreateHalfOfFolderPair()
  411. **
  412. **
  413. **
  414. ** Arguments:
  415. **
  416. ** Returns:
  417. **
  418. ** Side Effects: none
  419. */
  420. PRIVATE_CODE BOOL CreateHalfOfFolderPair(HPATH hpathFolder, HBRFCASE hbr,
  421. PFOLDERPAIR *ppfp)
  422. {
  423. BOOL bResult = FALSE;
  424. PFOLDERPAIR pfpNew;
  425. ASSERT(IS_VALID_HANDLE(hpathFolder, PATH));
  426. ASSERT(IS_VALID_HANDLE(hbr, BRFCASE));
  427. ASSERT(IS_VALID_WRITE_PTR(ppfp, PFOLDERPAIR));
  428. /* Try to create a new FOLDERPAIR structure. */
  429. if (AllocateMemory(sizeof(*pfpNew), &pfpNew))
  430. {
  431. /* Try to add the folder string to the folder string table. */
  432. if (CopyPath(hpathFolder, GetBriefcasePathList(hbr), &(pfpNew->hpath)))
  433. {
  434. /* Fill in the fields of the new FOLDERPAIR structure. */
  435. InitStub(&(pfpNew->stub), ST_FOLDERPAIR);
  436. *ppfp = pfpNew;
  437. bResult = TRUE;
  438. }
  439. else
  440. FreeMemory(pfpNew);
  441. }
  442. return(bResult);
  443. }
  444. /*
  445. ** DestroyHalfOfFolderPair()
  446. **
  447. **
  448. **
  449. ** Arguments:
  450. **
  451. ** Returns:
  452. **
  453. ** Side Effects: none
  454. */
  455. PRIVATE_CODE void DestroyHalfOfFolderPair(PFOLDERPAIR pfp)
  456. {
  457. ASSERT(IS_VALID_STRUCT_PTR(pfp, CFOLDERPAIR));
  458. TRACE_OUT((TEXT("DestroyHalfOfFolderPair(): Destroying folder twin %s."),
  459. DebugGetPathString(pfp->hpath)));
  460. /* Has the other half of this folder pair already been destroyed? */
  461. if (IsStubFlagClear(&(pfp->stub), STUB_FL_BEING_DELETED))
  462. /* No. Indicate that this half has already been deleted. */
  463. SetStubFlag(&(pfp->pfpOther->stub), STUB_FL_BEING_DELETED);
  464. /* Destroy FOLDERPAIR fields. */
  465. DeletePath(pfp->hpath);
  466. FreeMemory(pfp);
  467. return;
  468. }
  469. /*
  470. ** CreateSharedFolderPairData()
  471. **
  472. ** Creates a shared folder pair data structure.
  473. **
  474. ** Arguments: pcinft - pointer to INEWFOLDERTWIN describing folder pair
  475. ** being created
  476. **
  477. ** Returns: Pointer to new folder pair data structure if successful.
  478. ** NULL if unsuccessful.
  479. **
  480. ** Side Effects: none
  481. */
  482. PRIVATE_CODE BOOL CreateSharedFolderPairData(PCINEWFOLDERTWIN pcinft,
  483. PFOLDERPAIRDATA *ppfpd)
  484. {
  485. PFOLDERPAIRDATA pfpd;
  486. ASSERT(IS_VALID_STRUCT_PTR(pcinft, CINEWFOLDERTWIN));
  487. ASSERT(IS_VALID_WRITE_PTR(ppfpd, PFOLDERPAIRDATA));
  488. /* Try to allocate a new shared folder pair data data structure. */
  489. *ppfpd = NULL;
  490. if (AllocateMemory(sizeof(*pfpd), &pfpd))
  491. {
  492. /* Fill in the FOLDERPAIRDATA structure fields. */
  493. LockString(pcinft->hsName);
  494. pfpd->hsName = pcinft->hsName;
  495. pfpd->dwAttributes = pcinft->dwAttributes;
  496. pfpd->hbr = pcinft->hbr;
  497. ASSERT(! IS_ATTR_DIR(pfpd->dwAttributes));
  498. CLEAR_FLAG(pfpd->dwAttributes, FILE_ATTRIBUTE_DIRECTORY);
  499. *ppfpd = pfpd;
  500. ASSERT(IS_VALID_STRUCT_PTR(*ppfpd, CFOLDERPAIRDATA));
  501. }
  502. return(*ppfpd != NULL);
  503. }
  504. /*
  505. ** DestroySharedFolderPairData()
  506. **
  507. ** Destroys shared folder pair data.
  508. **
  509. ** Arguments: pfpd - pointer to shared folder pair data to destroy
  510. **
  511. ** Returns: void
  512. **
  513. ** Side Effects: none
  514. */
  515. PRIVATE_CODE void DestroySharedFolderPairData(PFOLDERPAIRDATA pfpd)
  516. {
  517. ASSERT(IS_VALID_STRUCT_PTR(pfpd, CFOLDERPAIRDATA));
  518. /* Destroy FOLDERPAIRDATA fields. */
  519. DeleteString(pfpd->hsName);
  520. FreeMemory(pfpd);
  521. return;
  522. }
  523. /*
  524. ** FolderPairSortCmp()
  525. **
  526. ** Pointer comparison function used to sort the global array of folder pairs.
  527. **
  528. ** Arguments: pcfp1 - pointer to FOLDERPAIR describing first folder pair
  529. ** pcfp2 - pointer to FOLDERPAIR describing second folder pair
  530. **
  531. ** Returns:
  532. **
  533. ** Side Effects: none
  534. **
  535. ** Folder pairs are sorted by:
  536. ** 1) path
  537. ** 2) pointer value
  538. */
  539. PRIVATE_CODE COMPARISONRESULT FolderPairSortCmp(PCVOID pcfp1, PCVOID pcfp2)
  540. {
  541. COMPARISONRESULT cr;
  542. ASSERT(IS_VALID_STRUCT_PTR(pcfp1, CFOLDERPAIR));
  543. ASSERT(IS_VALID_STRUCT_PTR(pcfp2, CFOLDERPAIR));
  544. cr = ComparePaths(((PCFOLDERPAIR)pcfp1)->hpath,
  545. ((PCFOLDERPAIR)pcfp2)->hpath);
  546. if (cr == CR_EQUAL)
  547. cr = ComparePointers(pcfp1, pcfp2);
  548. return(cr);
  549. }
  550. /*
  551. ** FolderPairSearchCmp()
  552. **
  553. ** Pointer comparison function used to search the global array of folder pairs
  554. ** for the first folder pair for a given folder.
  555. **
  556. ** Arguments: hpath - folder pair to search for
  557. ** pcfp - pointer to FOLDERPAIR to examine
  558. **
  559. ** Returns:
  560. **
  561. ** Side Effects: none
  562. **
  563. ** Folder pairs are searched by:
  564. ** 1) path
  565. */
  566. PRIVATE_CODE COMPARISONRESULT FolderPairSearchCmp(PCVOID hpath, PCVOID pcfp)
  567. {
  568. ASSERT(IS_VALID_HANDLE((HPATH)hpath, PATH));
  569. ASSERT(IS_VALID_STRUCT_PTR(pcfp, CFOLDERPAIR));
  570. return(ComparePaths((HPATH)hpath, ((PCFOLDERPAIR)pcfp)->hpath));
  571. }
  572. /*
  573. ** RemoveSourceFolderTwin()
  574. **
  575. **
  576. **
  577. ** Arguments:
  578. **
  579. ** Returns:
  580. **
  581. ** Side Effects: none
  582. */
  583. #pragma warning(disable:4100) /* "unreferenced formal parameter" warning */
  584. PRIVATE_CODE BOOL RemoveSourceFolderTwin(POBJECTTWIN pot, PVOID pv)
  585. {
  586. ASSERT(IS_VALID_STRUCT_PTR(pot, COBJECTTWIN));
  587. ASSERT(! pv);
  588. if (EVAL(pot->ulcSrcFolderTwins > 0))
  589. pot->ulcSrcFolderTwins--;
  590. /*
  591. * If there are no more source folder twins for this object twin, and this
  592. * object twin is not a separate "orphan" object twin, wipe it out.
  593. */
  594. if (! pot->ulcSrcFolderTwins &&
  595. IsStubFlagClear(&(pot->stub), STUB_FL_FROM_OBJECT_TWIN))
  596. EVAL(DestroyStub(&(pot->stub)) == TR_SUCCESS);
  597. return(TRUE);
  598. }
  599. #pragma warning(default:4100) /* "unreferenced formal parameter" warning */
  600. /*
  601. ** UnlinkHalfOfFolderPair()
  602. **
  603. ** Unlinks one half of a pair of folder twins.
  604. **
  605. ** Arguments: pfp - pointer to folder pair half to unlink
  606. **
  607. ** Returns: void
  608. **
  609. ** Side Effects: Removes a source folder twin from each of the object twin's
  610. ** in the folder pair's list of generated object twins. May
  611. ** cause object twins and twin families to be destroyed.
  612. */
  613. PRIVATE_CODE void UnlinkHalfOfFolderPair(PFOLDERPAIR pfp)
  614. {
  615. HPTRARRAY hpaFolderPairs;
  616. ARRAYINDEX aiUnlink;
  617. ASSERT(IS_VALID_STRUCT_PTR(pfp, CFOLDERPAIR));
  618. TRACE_OUT((TEXT("UnlinkHalfOfFolderPair(): Unlinking folder twin %s."),
  619. DebugGetPathString(pfp->hpath)));
  620. /* Search for the folder pair to be unlinked. */
  621. hpaFolderPairs = GetBriefcaseFolderPairPtrArray(pfp->pfpd->hbr);
  622. if (EVAL(SearchSortedArray(hpaFolderPairs, &FolderPairSortCmp, pfp,
  623. &aiUnlink)))
  624. {
  625. /* Unlink folder pair. */
  626. ASSERT(GetPtr(hpaFolderPairs, aiUnlink) == pfp);
  627. DeletePtr(hpaFolderPairs, aiUnlink);
  628. /*
  629. * Don't mark folder pair stub unlinked here. Let caller do that after
  630. * both folder pair halves have been unlinked.
  631. */
  632. /* Remove a source folder twin from all generated object twins. */
  633. EVAL(EnumGeneratedObjectTwins(pfp, &RemoveSourceFolderTwin, NULL));
  634. }
  635. return;
  636. }
  637. /*
  638. ** FolderTwinIntersectsFolder()
  639. **
  640. **
  641. **
  642. ** Arguments:
  643. **
  644. ** Returns:
  645. **
  646. ** Side Effects: none
  647. */
  648. PRIVATE_CODE BOOL FolderTwinIntersectsFolder(PCFOLDERPAIR pcfp, HPATH hpathFolder)
  649. {
  650. BOOL bResult;
  651. ASSERT(IS_VALID_STRUCT_PTR(pcfp, CFOLDERPAIR));
  652. ASSERT(IS_VALID_HANDLE(hpathFolder, PATH));
  653. if (IsStubFlagSet(&(pcfp->stub), STUB_FL_SUBTREE))
  654. bResult = IsPathPrefix(hpathFolder, pcfp->hpath);
  655. else
  656. bResult = (ComparePaths(hpathFolder, pcfp->hpath) == CR_EQUAL);
  657. return(bResult);
  658. }
  659. /*
  660. ** CreateListOfFolderTwins()
  661. **
  662. ** Creates a list of folder twins from a block of folder pairs.
  663. **
  664. ** Arguments: aiFirst - index of first folder pair in the array of folder
  665. ** pairs
  666. ** hpathFolder - folder that list of folder twins is to be
  667. ** created for
  668. ** ppftHead - pointer to PFOLDERTWIN to be filled in with
  669. ** pointer to first folder twin in new list
  670. ** paic - pointer to ARRAYINDEX to be filled in with number of
  671. ** folder twins in new list
  672. **
  673. ** Returns: TWINRESULT
  674. **
  675. ** Side Effects: none
  676. */
  677. PRIVATE_CODE TWINRESULT CreateListOfFolderTwins(HBRFCASE hbr, ARRAYINDEX aiFirst,
  678. HPATH hpathFolder,
  679. PFOLDERTWIN *ppftHead,
  680. PARRAYINDEX paic)
  681. {
  682. TWINRESULT tr;
  683. PFOLDERPAIR pfp;
  684. HPATH hpath;
  685. ARRAYINDEX aicPtrs;
  686. ARRAYINDEX ai;
  687. PFOLDERTWIN pftHead;
  688. HPTRARRAY hpaFolderTwins;
  689. ASSERT(IS_VALID_HANDLE(hbr, BRFCASE));
  690. ASSERT(IS_VALID_HANDLE(hpathFolder, PATH));
  691. ASSERT(IS_VALID_WRITE_PTR(ppftHead, PFOLDERTWIN));
  692. ASSERT(IS_VALID_WRITE_PTR(paic, ARRAYINDEX));
  693. /*
  694. * Get the handle to the common folder that the list of folder twins is
  695. * being prepared for.
  696. */
  697. hpaFolderTwins = GetBriefcaseFolderPairPtrArray(hbr);
  698. pfp = GetPtr(hpaFolderTwins, aiFirst);
  699. hpath = pfp->hpath;
  700. /*
  701. * Add the other half of each matching folder pair to the folder twin list
  702. * as a folder twin.
  703. */
  704. aicPtrs = GetPtrCount(hpaFolderTwins);
  705. ASSERT(aicPtrs > 0);
  706. ASSERT(! (aicPtrs % 2));
  707. ASSERT(aiFirst >= 0);
  708. ASSERT(aiFirst < aicPtrs);
  709. /* Start with an empty list of folder twins. */
  710. pftHead = NULL;
  711. /*
  712. * A pointer to the first folder pair is already in pfp, but we'll look it
  713. * up again.
  714. */
  715. TRACE_OUT((TEXT("CreateListOfFolderTwins(): Creating list of folder twins of folder %s."),
  716. DebugGetPathString(hpath)));
  717. tr = TR_SUCCESS;
  718. for (ai = aiFirst; ai < aicPtrs && tr == TR_SUCCESS; ai++)
  719. {
  720. pfp = GetPtr(hpaFolderTwins, ai);
  721. if (ComparePaths(pfp->hpath, hpathFolder) == CR_EQUAL)
  722. tr = AddFolderTwinToList(pfp, pftHead, &pftHead);
  723. else
  724. break;
  725. }
  726. TRACE_OUT((TEXT("CreateListOfFolderTwins(): Finished creating list of folder twins of folder %s."),
  727. DebugGetPathString(hpath)));
  728. if (tr == TR_SUCCESS)
  729. {
  730. /* Success! Fill in the result parameters. */
  731. *ppftHead = pftHead;
  732. *paic = ai - aiFirst;
  733. }
  734. else
  735. /* Free any folder twins that have been added to the list. */
  736. DestroyListOfFolderTwins(pftHead);
  737. return(tr);
  738. }
  739. /*
  740. ** DestroyListOfFolderTwins()
  741. **
  742. ** Wipes out the folder twins in a folder twin list.
  743. **
  744. ** Arguments: pftHead - pointer to first folder twin in list
  745. **
  746. ** Returns: TWINRESULT
  747. **
  748. ** Side Effects: none
  749. */
  750. PRIVATE_CODE void DestroyListOfFolderTwins(PFOLDERTWIN pftHead)
  751. {
  752. while (pftHead)
  753. {
  754. PFOLDERTWIN pftOldHead;
  755. ASSERT(IS_VALID_STRUCT_PTR(pftHead, CFOLDERTWIN));
  756. UnlockStub(&(((PFOLDERPAIR)(pftHead->hftSrc))->stub));
  757. UnlockStub(&(((PFOLDERPAIR)(pftHead->hftOther))->stub));
  758. pftOldHead = pftHead;
  759. pftHead = (PFOLDERTWIN)(pftHead->pcftNext);
  760. FreeMemory((LPTSTR)(pftOldHead->pcszSrcFolder));
  761. FreeMemory((LPTSTR)(pftOldHead->pcszOtherFolder));
  762. FreeMemory(pftOldHead);
  763. }
  764. return;
  765. }
  766. /*
  767. ** AddFolderTwinToList()
  768. **
  769. ** Adds a folder twin to a list of folder twins.
  770. **
  771. ** Arguments: pfpSrc - pointer to source folder pair to be added
  772. ** pftHead - pointer to head of folder twin list, may be NULL
  773. ** ppft - pointer to PFOLDERTWIN to be filled in with pointer
  774. ** to new folder twin, ppft may be &pftHead
  775. **
  776. ** Returns: TWINRESULT
  777. **
  778. ** Side Effects: none
  779. */
  780. PRIVATE_CODE TWINRESULT AddFolderTwinToList(PFOLDERPAIR pfpSrc,
  781. PFOLDERTWIN pftHead,
  782. PFOLDERTWIN *ppft)
  783. {
  784. TWINRESULT tr = TR_OUT_OF_MEMORY;
  785. PFOLDERTWIN pftNew;
  786. ASSERT(IS_VALID_STRUCT_PTR(pfpSrc, CFOLDERPAIR));
  787. ASSERT(! pftHead || IS_VALID_STRUCT_PTR(pftHead, CFOLDERTWIN));
  788. ASSERT(IS_VALID_WRITE_PTR(ppft, PFOLDERTWIN));
  789. /* Try to create a new FOLDERTWIN structure. */
  790. if (AllocateMemory(sizeof(*pftNew), &pftNew))
  791. {
  792. LPTSTR pszFirstFolder;
  793. if (AllocatePathString(pfpSrc->hpath, &pszFirstFolder))
  794. {
  795. LPTSTR pszSecondFolder;
  796. if (AllocatePathString(pfpSrc->pfpOther->hpath, &pszSecondFolder))
  797. {
  798. /* Fill in FOLDERTWIN structure fields. */
  799. pftNew->pcftNext = pftHead;
  800. pftNew->hftSrc = (HFOLDERTWIN)pfpSrc;
  801. pftNew->hvidSrc = (HVOLUMEID)(pfpSrc->hpath);
  802. pftNew->pcszSrcFolder = pszFirstFolder;
  803. pftNew->hftOther = (HFOLDERTWIN)(pfpSrc->pfpOther);
  804. pftNew->hvidOther = (HVOLUMEID)(pfpSrc->pfpOther->hpath);
  805. pftNew->pcszOtherFolder = pszSecondFolder;
  806. pftNew->pcszName = GetString(pfpSrc->pfpd->hsName);
  807. pftNew->dwFlags = 0;
  808. if (IsStubFlagSet(&(pfpSrc->stub), STUB_FL_SUBTREE))
  809. pftNew->dwFlags = FT_FL_SUBTREE;
  810. LockStub(&(pfpSrc->stub));
  811. LockStub(&(pfpSrc->pfpOther->stub));
  812. *ppft = pftNew;
  813. tr = TR_SUCCESS;
  814. TRACE_OUT((TEXT("AddFolderTwinToList(): Added folder twin %s of folder %s matching objects %s."),
  815. pftNew->pcszSrcFolder,
  816. pftNew->pcszOtherFolder,
  817. pftNew->pcszName));
  818. }
  819. else
  820. {
  821. FreeMemory(pszFirstFolder);
  822. ADDFOLDERTWINTOLIST_BAIL:
  823. FreeMemory(pftNew);
  824. }
  825. }
  826. else
  827. goto ADDFOLDERTWINTOLIST_BAIL;
  828. }
  829. ASSERT(tr != TR_SUCCESS ||
  830. IS_VALID_STRUCT_PTR(*ppft, CFOLDERTWIN));
  831. return(tr);
  832. }
  833. /*
  834. ** TransplantFolderPair()
  835. **
  836. **
  837. **
  838. ** Arguments:
  839. **
  840. ** Returns: TWINRESULT
  841. **
  842. ** Side Effects: none
  843. */
  844. PRIVATE_CODE TWINRESULT TransplantFolderPair(PFOLDERPAIR pfp,
  845. HPATH hpathOldFolder,
  846. HPATH hpathNewFolder)
  847. {
  848. TWINRESULT tr;
  849. ASSERT(IS_VALID_STRUCT_PTR(pfp, CFOLDERPAIR));
  850. ASSERT(IS_VALID_HANDLE(hpathOldFolder, PATH));
  851. ASSERT(IS_VALID_HANDLE(hpathNewFolder, PATH));
  852. /* Is this folder pair rooted in the renamed folder's subtree? */
  853. if (IsPathPrefix(pfp->hpath, hpathOldFolder))
  854. {
  855. TCHAR rgchPathSuffix[MAX_PATH_LEN];
  856. LPCTSTR pcszSubPath;
  857. HPATH hpathNew;
  858. /* Yes. Change the folder pair's root. */
  859. pcszSubPath = FindChildPathSuffix(hpathOldFolder, pfp->hpath,
  860. rgchPathSuffix);
  861. if (AddChildPath(GetBriefcasePathList(pfp->pfpd->hbr), hpathNewFolder,
  862. pcszSubPath, &hpathNew))
  863. {
  864. if (IsStubFlagSet(&(pfp->stub), STUB_FL_SUBTREE))
  865. {
  866. ASSERT(IsStubFlagSet(&(pfp->pfpOther->stub), STUB_FL_SUBTREE));
  867. BeginTranslateFolder(pfp);
  868. tr = CheckForSubtreeCycles(
  869. GetBriefcaseFolderPairPtrArray(pfp->pfpd->hbr), hpathNew,
  870. pfp->pfpOther->hpath, pfp->pfpd->hsName);
  871. EndTranslateFolder(pfp);
  872. }
  873. else
  874. tr = TR_SUCCESS;
  875. if (tr == TR_SUCCESS)
  876. {
  877. TRACE_OUT((TEXT("TransplantFolderPair(): Transplanted folder twin %s to %s."),
  878. DebugGetPathString(pfp->hpath),
  879. DebugGetPathString(hpathNew)));
  880. DeletePath(pfp->hpath);
  881. pfp->hpath = hpathNew;
  882. }
  883. else
  884. DeletePath(hpathNew);
  885. }
  886. else
  887. tr = TR_OUT_OF_MEMORY;
  888. }
  889. else
  890. tr = TR_SUCCESS;
  891. return(tr);
  892. }
  893. /*
  894. ** WriteFolderPair()
  895. **
  896. **
  897. **
  898. ** Arguments:
  899. **
  900. ** Returns: TWINRESULT
  901. **
  902. ** Side Effects: none
  903. */
  904. PRIVATE_CODE TWINRESULT WriteFolderPair(HCACHEDFILE hcf, PFOLDERPAIR pfp)
  905. {
  906. TWINRESULT tr;
  907. DBFOLDERTWIN dbft;
  908. ASSERT(IS_VALID_HANDLE(hcf, CACHEDFILE));
  909. ASSERT(IS_VALID_STRUCT_PTR(pfp, CFOLDERPAIR));
  910. /* Set up folder pair database structure. */
  911. dbft.dwStubFlags = (pfp->stub.dwFlags & DB_STUB_FLAGS_MASK);
  912. dbft.hpath1 = pfp->hpath;
  913. dbft.hpath2 = pfp->pfpOther->hpath;
  914. dbft.hsName = pfp->pfpd->hsName;
  915. dbft.dwAttributes = pfp->pfpd->dwAttributes;
  916. /* Save folder pair database structure. */
  917. if (WriteToCachedFile(hcf, (PCVOID)&dbft, sizeof(dbft), NULL))
  918. tr = TR_SUCCESS;
  919. else
  920. tr = TR_BRIEFCASE_WRITE_FAILED;
  921. return(tr);
  922. }
  923. /*
  924. ** ReadFolderPair()
  925. **
  926. **
  927. **
  928. ** Arguments:
  929. **
  930. ** Returns: TWINRESULT
  931. **
  932. ** Side Effects: none
  933. */
  934. PRIVATE_CODE TWINRESULT ReadFolderPair(HCACHEDFILE hcf, HBRFCASE hbr,
  935. HHANDLETRANS hhtFolderTrans,
  936. HHANDLETRANS hhtNameTrans)
  937. {
  938. TWINRESULT tr = TR_CORRUPT_BRIEFCASE;
  939. DBFOLDERTWIN dbft;
  940. DWORD dwcbRead;
  941. ASSERT(IS_VALID_HANDLE(hcf, CACHEDFILE));
  942. ASSERT(IS_VALID_HANDLE(hbr, BRFCASE));
  943. ASSERT(IS_VALID_HANDLE(hhtFolderTrans, HANDLETRANS));
  944. ASSERT(IS_VALID_HANDLE(hhtNameTrans, HANDLETRANS));
  945. if (ReadFromCachedFile(hcf, &dbft, sizeof(dbft), &dwcbRead) &&
  946. dwcbRead == sizeof(dbft))
  947. {
  948. INEWFOLDERTWIN inft;
  949. if (TranslateHandle(hhtFolderTrans, (HGENERIC)(dbft.hpath1), (PHGENERIC)&(inft.hpathFirst)))
  950. {
  951. if (TranslateHandle(hhtFolderTrans, (HGENERIC)(dbft.hpath2), (PHGENERIC)&(inft.hpathSecond)))
  952. {
  953. if (TranslateHandle(hhtNameTrans, (HGENERIC)(dbft.hsName), (PHGENERIC)&(inft.hsName)))
  954. {
  955. PFOLDERPAIR pfp;
  956. inft.dwAttributes = dbft.dwAttributes;
  957. inft.hbr = hbr;
  958. if (IS_FLAG_SET(dbft.dwStubFlags, STUB_FL_SUBTREE))
  959. inft.dwFlags = NFT_FL_SUBTREE;
  960. else
  961. inft.dwFlags = 0;
  962. if (CreateFolderPair(&inft, &pfp))
  963. tr = TR_SUCCESS;
  964. else
  965. tr = TR_OUT_OF_MEMORY;
  966. }
  967. }
  968. }
  969. }
  970. return(tr);
  971. }
  972. #ifdef VSTF
  973. /*
  974. ** IsValidPCNEWFOLDERTWIN()
  975. **
  976. **
  977. **
  978. ** Arguments:
  979. **
  980. ** Returns:
  981. **
  982. ** Side Effects: none
  983. */
  984. PRIVATE_CODE BOOL IsValidPCNEWFOLDERTWIN(PCNEWFOLDERTWIN pcnft)
  985. {
  986. return(IS_VALID_READ_PTR(pcnft, CNEWFOLDERTWIN) &&
  987. EVAL(pcnft->ulSize == sizeof(*pcnft)) &&
  988. IS_VALID_STRING_PTR(pcnft->pcszFolder1, CSTR) &&
  989. IS_VALID_STRING_PTR(pcnft->pcszFolder2, CSTR) &&
  990. IS_VALID_STRING_PTR(pcnft->pcszName, CSTR) &&
  991. FLAGS_ARE_VALID(pcnft->dwAttributes, ALL_FILE_ATTRIBUTES) &&
  992. FLAGS_ARE_VALID(pcnft->dwFlags, ALL_NFT_FLAGS));
  993. }
  994. /*
  995. ** IsValidPCFOLDERTWINLIST()
  996. **
  997. **
  998. **
  999. ** Arguments:
  1000. **
  1001. ** Returns:
  1002. **
  1003. ** Side Effects: none
  1004. */
  1005. PRIVATE_CODE BOOL IsValidPCFOLDERTWINLIST(PCFOLDERTWINLIST pcftl)
  1006. {
  1007. BOOL bResult = FALSE;
  1008. if (IS_VALID_READ_PTR(pcftl, CFOLDERTWINLIST) &&
  1009. IS_VALID_HANDLE(pcftl->hbr, BRFCASE))
  1010. {
  1011. PCFOLDERTWIN pcft;
  1012. ULONG ulcFolderTwins = 0;
  1013. for (pcft = pcftl->pcftFirst;
  1014. pcft && IS_VALID_STRUCT_PTR(pcft, CFOLDERTWIN);
  1015. pcft = pcft->pcftNext)
  1016. {
  1017. ASSERT(ulcFolderTwins < ULONG_MAX);
  1018. ulcFolderTwins++;
  1019. }
  1020. if (! pcft && EVAL(ulcFolderTwins == pcftl->ulcItems))
  1021. bResult = TRUE;
  1022. }
  1023. return(bResult);
  1024. }
  1025. /*
  1026. ** IsValidPCFOLDERTWIN()
  1027. **
  1028. **
  1029. **
  1030. ** Arguments:
  1031. **
  1032. ** Returns:
  1033. **
  1034. ** Side Effects: none
  1035. */
  1036. PRIVATE_CODE BOOL IsValidPCFOLDERTWIN(PCFOLDERTWIN pcft)
  1037. {
  1038. /* dwUser may be any value. */
  1039. return(IS_VALID_READ_PTR(pcft, CFOLDERTWIN) &&
  1040. IS_VALID_HANDLE(pcft->hftSrc, FOLDERTWIN) &&
  1041. IS_VALID_HANDLE(pcft->hvidSrc, VOLUMEID) &&
  1042. IS_VALID_STRING_PTR(pcft->pcszSrcFolder, CSTR) &&
  1043. IS_VALID_HANDLE(pcft->hftOther, FOLDERTWIN) &&
  1044. IS_VALID_HANDLE(pcft->hvidOther, VOLUMEID) &&
  1045. IS_VALID_STRING_PTR(pcft->pcszOtherFolder, CSTR) &&
  1046. IS_VALID_STRING_PTR(pcft->pcszName, CSTR) &&
  1047. FLAGS_ARE_VALID(pcft->dwFlags, ALL_FT_FLAGS));
  1048. }
  1049. /*
  1050. ** IsValidFolderPairHalf()
  1051. **
  1052. **
  1053. **
  1054. ** Arguments:
  1055. **
  1056. ** Returns:
  1057. **
  1058. ** Side Effects: none
  1059. */
  1060. PRIVATE_CODE BOOL IsValidFolderPairHalf(PCFOLDERPAIR pcfp)
  1061. {
  1062. return(IS_VALID_READ_PTR(pcfp, CFOLDERPAIR) &&
  1063. IS_VALID_STRUCT_PTR(&(pcfp->stub), CSTUB) &&
  1064. FLAGS_ARE_VALID(GetStubFlags(&(pcfp->stub)), ALL_FOLDER_TWIN_FLAGS) &&
  1065. IS_VALID_HANDLE(pcfp->hpath, PATH) &&
  1066. IS_VALID_STRUCT_PTR(pcfp->pfpd, CFOLDERPAIRDATA) &&
  1067. (IsStubFlagSet(&(pcfp->stub), STUB_FL_BEING_DELETED) ||
  1068. IS_VALID_READ_PTR(pcfp->pfpOther, CFOLDERPAIR)));
  1069. }
  1070. /*
  1071. ** IsValidPCFOLDERPAIRDATA()
  1072. **
  1073. **
  1074. **
  1075. ** Arguments:
  1076. **
  1077. ** Returns:
  1078. **
  1079. ** Side Effects: none
  1080. */
  1081. PRIVATE_CODE BOOL IsValidPCFOLDERPAIRDATA(PCFOLDERPAIRDATA pcfpd)
  1082. {
  1083. /* Don't validate hbr. */
  1084. return(IS_VALID_READ_PTR(pcfpd, CFOLDERPAIRDATA) &&
  1085. IS_VALID_HANDLE(pcfpd->hsName, STRING));
  1086. }
  1087. #endif
  1088. #ifdef DEBUG
  1089. /*
  1090. ** IsValidPCINEWFOLDERTWIN()
  1091. **
  1092. **
  1093. **
  1094. ** Arguments:
  1095. **
  1096. ** Returns:
  1097. **
  1098. ** Side Effects: none
  1099. */
  1100. PRIVATE_CODE BOOL IsValidPCINEWFOLDERTWIN(PCINEWFOLDERTWIN pcinft)
  1101. {
  1102. return(IS_VALID_READ_PTR(pcinft, CINEWFOLDERTWIN) &&
  1103. IS_VALID_HANDLE(pcinft->hpathFirst, PATH) &&
  1104. IS_VALID_HANDLE(pcinft->hpathSecond, PATH) &&
  1105. IS_VALID_HANDLE(pcinft->hsName, STRING) &&
  1106. FLAGS_ARE_VALID(pcinft->dwAttributes, ALL_FILE_ATTRIBUTES) &&
  1107. FLAGS_ARE_VALID(pcinft->dwFlags, ALL_NFT_FLAGS) &&
  1108. IS_VALID_HANDLE(pcinft->hbr, BRFCASE));
  1109. }
  1110. /*
  1111. ** AreFolderPairsValid()
  1112. **
  1113. **
  1114. **
  1115. ** Arguments:
  1116. **
  1117. ** Returns:
  1118. **
  1119. ** Side Effects: none
  1120. */
  1121. PRIVATE_CODE BOOL AreFolderPairsValid(HPTRARRAY hpaFolderPairs)
  1122. {
  1123. ARRAYINDEX aicPtrs;
  1124. ARRAYINDEX ai;
  1125. ASSERT(IS_VALID_HANDLE(hpaFolderPairs, PTRARRAY));
  1126. aicPtrs = GetPtrCount(hpaFolderPairs);
  1127. ASSERT(! (aicPtrs % 2));
  1128. for (ai = 0;
  1129. ai < aicPtrs && IS_VALID_STRUCT_PTR(GetPtr(hpaFolderPairs, ai), CFOLDERPAIR);
  1130. ai++)
  1131. ;
  1132. return(ai == aicPtrs);
  1133. }
  1134. #endif
  1135. /****************************** Public Functions *****************************/
  1136. /*
  1137. ** CreateFolderPairPtrArray()
  1138. **
  1139. **
  1140. **
  1141. ** Arguments:
  1142. **
  1143. ** Returns:
  1144. **
  1145. ** Side Effects: none
  1146. */
  1147. PUBLIC_CODE BOOL CreateFolderPairPtrArray(PHPTRARRAY phpa)
  1148. {
  1149. NEWPTRARRAY npa;
  1150. ASSERT(IS_VALID_WRITE_PTR(phpa, HPTRARRAY));
  1151. /* Try to create a folder pair pointer array. */
  1152. npa.aicInitialPtrs = NUM_START_FOLDER_TWIN_PTRS;
  1153. npa.aicAllocGranularity = NUM_FOLDER_TWIN_PTRS_TO_ADD;
  1154. npa.dwFlags = NPA_FL_SORTED_ADD;
  1155. return(CreatePtrArray(&npa, phpa));
  1156. }
  1157. /*
  1158. ** DestroyFolderPairPtrArray()
  1159. **
  1160. **
  1161. **
  1162. ** Arguments:
  1163. **
  1164. ** Returns:
  1165. **
  1166. ** Side Effects: none
  1167. */
  1168. PUBLIC_CODE void DestroyFolderPairPtrArray(HPTRARRAY hpa)
  1169. {
  1170. ARRAYINDEX aicPtrs;
  1171. ARRAYINDEX ai;
  1172. ASSERT(IS_VALID_HANDLE(hpa, PTRARRAY));
  1173. /* Free all folder pairs in pointer array. */
  1174. aicPtrs = GetPtrCount(hpa);
  1175. ASSERT(! (aicPtrs % 2));
  1176. for (ai = 0; ai < aicPtrs; ai++)
  1177. {
  1178. PFOLDERPAIR pfp;
  1179. PFOLDERPAIR pfpOther;
  1180. PFOLDERPAIRDATA pfpd;
  1181. BOOL bDeleteFolderPairData;
  1182. pfp = GetPtr(hpa, ai);
  1183. ASSERT(IS_VALID_STRUCT_PTR(pfp, CFOLDERPAIR));
  1184. /* Copy fields needed after folder pair half's demise. */
  1185. pfpOther = pfp->pfpOther;
  1186. pfpd = pfp->pfpd;
  1187. bDeleteFolderPairData = IsStubFlagSet(&(pfp->stub), STUB_FL_BEING_DELETED);
  1188. DestroyHalfOfFolderPair(pfp);
  1189. /* Has the other half of this folder pair already been destroyed? */
  1190. if (bDeleteFolderPairData)
  1191. /* Yes. Destroy the pair's shared data. */
  1192. DestroySharedFolderPairData(pfpd);
  1193. }
  1194. /* Now wipe out the pointer array. */
  1195. DestroyPtrArray(hpa);
  1196. return;
  1197. }
  1198. /*
  1199. ** LockFolderPair()
  1200. **
  1201. **
  1202. **
  1203. ** Arguments:
  1204. **
  1205. ** Returns:
  1206. **
  1207. ** Side Effects: none
  1208. */
  1209. PUBLIC_CODE void LockFolderPair(PFOLDERPAIR pfp)
  1210. {
  1211. ASSERT(IS_VALID_STRUCT_PTR(pfp, CFOLDERPAIR));
  1212. ASSERT(IsStubFlagClear(&(pfp->stub), STUB_FL_UNLINKED));
  1213. ASSERT(IsStubFlagClear(&(pfp->pfpOther->stub), STUB_FL_UNLINKED));
  1214. ASSERT(pfp->stub.ulcLock < ULONG_MAX);
  1215. pfp->stub.ulcLock++;
  1216. ASSERT(pfp->pfpOther->stub.ulcLock < ULONG_MAX);
  1217. pfp->pfpOther->stub.ulcLock++;
  1218. return;
  1219. }
  1220. /*
  1221. ** UnlockFolderPair()
  1222. **
  1223. **
  1224. **
  1225. ** Arguments:
  1226. **
  1227. ** Returns:
  1228. **
  1229. ** Side Effects: none
  1230. */
  1231. PUBLIC_CODE void UnlockFolderPair(PFOLDERPAIR pfp)
  1232. {
  1233. ASSERT(IS_VALID_STRUCT_PTR(pfp, CFOLDERPAIR));
  1234. if (EVAL(pfp->stub.ulcLock > 0))
  1235. pfp->stub.ulcLock--;
  1236. if (EVAL(pfp->pfpOther->stub.ulcLock > 0))
  1237. pfp->pfpOther->stub.ulcLock--;
  1238. if (! pfp->stub.ulcLock &&
  1239. IsStubFlagSet(&(pfp->stub), STUB_FL_UNLINKED))
  1240. {
  1241. ASSERT(! pfp->pfpOther->stub.ulcLock);
  1242. ASSERT(IsStubFlagSet(&(pfp->pfpOther->stub), STUB_FL_UNLINKED));
  1243. DestroyFolderPair(pfp);
  1244. }
  1245. return;
  1246. }
  1247. /*
  1248. ** UnlinkFolderPair()
  1249. **
  1250. ** Unlinks a folder pair.
  1251. **
  1252. ** Arguments: pfp - pointer to folder pair to be unlinked
  1253. **
  1254. ** Returns: TWINRESULT
  1255. **
  1256. ** Side Effects: none
  1257. */
  1258. PUBLIC_CODE TWINRESULT UnlinkFolderPair(PFOLDERPAIR pfp)
  1259. {
  1260. ASSERT(IS_VALID_STRUCT_PTR(pfp, CFOLDERPAIR));
  1261. ASSERT(IsStubFlagClear(&(pfp->stub), STUB_FL_UNLINKED));
  1262. ASSERT(IsStubFlagClear(&(pfp->pfpOther->stub), STUB_FL_UNLINKED));
  1263. /* Unlink both halves of the folder pair. */
  1264. UnlinkHalfOfFolderPair(pfp);
  1265. UnlinkHalfOfFolderPair(pfp->pfpOther);
  1266. SetStubFlag(&(pfp->stub), STUB_FL_UNLINKED);
  1267. SetStubFlag(&(pfp->pfpOther->stub), STUB_FL_UNLINKED);
  1268. return(TR_SUCCESS);
  1269. }
  1270. /*
  1271. ** DestroyFolderPair()
  1272. **
  1273. ** Destroys a folder pair.
  1274. **
  1275. ** Arguments: pfp - pointer to folder pair to destroy
  1276. **
  1277. ** Returns: void
  1278. **
  1279. ** Side Effects: none
  1280. */
  1281. PUBLIC_CODE void DestroyFolderPair(PFOLDERPAIR pfp)
  1282. {
  1283. PFOLDERPAIRDATA pfpd;
  1284. ASSERT(IS_VALID_STRUCT_PTR(pfp, CFOLDERPAIR));
  1285. /* Destroy both FOLDERPAIR halves, and shared data. */
  1286. pfpd = pfp->pfpd;
  1287. DestroyHalfOfFolderPair(pfp->pfpOther);
  1288. DestroyHalfOfFolderPair(pfp);
  1289. DestroySharedFolderPairData(pfpd);
  1290. return;
  1291. }
  1292. /*
  1293. ** MyTranslateFolder()
  1294. **
  1295. **
  1296. **
  1297. ** Arguments:
  1298. **
  1299. ** Returns:
  1300. **
  1301. ** Side Effects: none
  1302. */
  1303. PUBLIC_CODE TWINRESULT MyTranslateFolder(HBRFCASE hbr, HPATH hpathOld,
  1304. HPATH hpathNew)
  1305. {
  1306. TWINRESULT tr = TR_SUCCESS;
  1307. HPTRARRAY hpaFolderPairs;
  1308. ARRAYINDEX aicPtrs;
  1309. ARRAYINDEX ai;
  1310. ASSERT(IS_VALID_HANDLE(hbr, BRFCASE));
  1311. ASSERT(IS_VALID_HANDLE(hpathOld, PATH));
  1312. ASSERT(IS_VALID_HANDLE(hpathNew, PATH));
  1313. /*
  1314. * Change folders of all folder pairs rooted in pcszOldFolder's subtree to
  1315. * being rooted in pcszNewFolder's subtree.
  1316. */
  1317. hpaFolderPairs = GetBriefcaseFolderPairPtrArray(hbr);
  1318. aicPtrs = GetPtrCount(hpaFolderPairs);
  1319. ASSERT(! (aicPtrs % 2));
  1320. for (ai = 0; ai < aicPtrs; ai++)
  1321. {
  1322. tr = TransplantFolderPair(GetPtr(hpaFolderPairs, ai), hpathOld,
  1323. hpathNew);
  1324. if (tr != TR_SUCCESS)
  1325. break;
  1326. }
  1327. if (tr == TR_SUCCESS)
  1328. {
  1329. HPTRARRAY hpaTwinFamilies;
  1330. /* Restore folder pair array to sorted order. */
  1331. SortPtrArray(hpaFolderPairs, &FolderPairSortCmp);
  1332. TRACE_OUT((TEXT("MyTranslateFolder(): Sorted folder pair array after folder translation.")));
  1333. /*
  1334. * Change folders of all object twins in pcszOldFolder's old subtree to
  1335. * being in pcszNewFolder's subtree.
  1336. */
  1337. hpaTwinFamilies = GetBriefcaseTwinFamilyPtrArray(hbr);
  1338. aicPtrs = GetPtrCount(hpaTwinFamilies);
  1339. for (ai = 0; ai < aicPtrs; ai++)
  1340. {
  1341. PTWINFAMILY ptf;
  1342. BOOL bContinue;
  1343. HNODE hnode;
  1344. ptf = GetPtr(hpaTwinFamilies, ai);
  1345. ASSERT(IS_VALID_STRUCT_PTR(ptf, CTWINFAMILY));
  1346. /*
  1347. * Walk each twin family's list of object twins looking for object
  1348. * twins in the translated folder's subtree.
  1349. */
  1350. for (bContinue = GetFirstNode(ptf->hlistObjectTwins, &hnode);
  1351. bContinue;
  1352. bContinue = GetNextNode(hnode, &hnode))
  1353. {
  1354. POBJECTTWIN pot;
  1355. pot = (POBJECTTWIN)GetNodeData(hnode);
  1356. tr = TransplantObjectTwin(pot, hpathOld, hpathNew);
  1357. if (tr != TR_SUCCESS)
  1358. break;
  1359. }
  1360. if (tr != TR_SUCCESS)
  1361. break;
  1362. }
  1363. /* Twin family array is still in sorted order. */
  1364. }
  1365. return(tr);
  1366. }
  1367. /*
  1368. ** ApplyNewObjectTwinsToFolderTwins()
  1369. **
  1370. **
  1371. **
  1372. ** Arguments:
  1373. **
  1374. ** Returns:
  1375. **
  1376. ** Side Effects: Adds new spin-off object twins to hlistNewObjectTwins as they
  1377. ** are created.
  1378. **
  1379. ** N.b., new object twins may have been added to hlistNewObjectTwins even if
  1380. ** FALSE is returned. Clean-up of these new object twins in case of failure is
  1381. ** the caller's responsibility.
  1382. **
  1383. ** A new object twin may generate more new object twins, implied by existing
  1384. ** folder twins. E.g., consider the following scenario:
  1385. **
  1386. ** 1) Folder twins (c:\, d:\, *.*) and (d:\, e:\, *.*) exist.
  1387. ** 2) Files c:\foo, d:\foo, and e:\foo do not exist.
  1388. ** 3) File e:\foo is created.
  1389. ** 4) New object twin e:\foo is added.
  1390. ** 5) d:\foo must be added as a new object twin from the e:\foo object twin
  1391. ** because of the (d:\, e:\, *.*) folder twin.
  1392. ** 6) c:\foo must be added as a new object twin from the d:\foo object twin
  1393. ** because of the (c:\, d:\, *.*) folder twin.
  1394. **
  1395. ** So we see that new object twin e:\foo must generate two more new object
  1396. ** twins, d:\foo and c:\foo, implied by the two existing folder twins,
  1397. ** (c:\, d:\, *.*) and (d:\, e:\, *.*).
  1398. */
  1399. PUBLIC_CODE BOOL ApplyNewObjectTwinsToFolderTwins(HLIST hlistNewObjectTwins)
  1400. {
  1401. BOOL bResult = TRUE;
  1402. BOOL bContinue;
  1403. HNODE hnode;
  1404. ASSERT(IS_VALID_HANDLE(hlistNewObjectTwins, LIST));
  1405. /*
  1406. * Don't use WalkList() here because we want to insert new nodes in
  1407. * hlistNewObjectTwins after the current node.
  1408. */
  1409. for (bContinue = GetFirstNode(hlistNewObjectTwins, &hnode);
  1410. bContinue && bResult;
  1411. bContinue = GetNextNode(hnode, &hnode))
  1412. {
  1413. POBJECTTWIN pot;
  1414. HPATHLIST hpl;
  1415. HPTRARRAY hpaFolderPairs;
  1416. ARRAYINDEX aicPtrs;
  1417. ARRAYINDEX ai;
  1418. pot = GetNodeData(hnode);
  1419. ASSERT(! pot->ulcSrcFolderTwins);
  1420. TRACE_OUT((TEXT("ApplyNewObjectTwinsToFolderTwins(): Applying new object twin %s\\%s."),
  1421. DebugGetPathString(pot->hpath),
  1422. GetString(pot->ptfParent->hsName)));
  1423. /*
  1424. * Assume that hpl, hpaFolderPairs, and aicPtrs don't change during this
  1425. * loop. Calculate them outside the loop.
  1426. */
  1427. hpl = GetBriefcasePathList(pot->ptfParent->hbr);
  1428. hpaFolderPairs = GetBriefcaseFolderPairPtrArray(pot->ptfParent->hbr);
  1429. aicPtrs = GetPtrCount(hpaFolderPairs);
  1430. ASSERT(! (aicPtrs % 2));
  1431. for (ai = 0; ai < aicPtrs; ai++)
  1432. {
  1433. PFOLDERPAIR pfp;
  1434. pfp = GetPtr(hpaFolderPairs, ai);
  1435. if (FolderTwinGeneratesObjectTwin(pfp, pot->hpath,
  1436. GetString(pot->ptfParent->hsName)))
  1437. {
  1438. HPATH hpathMatchingFolder;
  1439. HNODE hnodeUnused;
  1440. ASSERT(pot->ulcSrcFolderTwins < ULONG_MAX);
  1441. pot->ulcSrcFolderTwins++;
  1442. /*
  1443. * Append the generated object twin's subpath to the matching
  1444. * folder twin's base path for subtree twins.
  1445. */
  1446. if (BuildPathForMatchingObjectTwin(pfp, pot, hpl,
  1447. &hpathMatchingFolder))
  1448. {
  1449. /*
  1450. * We don't want to collapse any twin families if the matching
  1451. * object twin is found in a different twin family. This will
  1452. * be done by ApplyNewFolderTwinsToTwinFamilies() for spin-off
  1453. * object twins generated by new folder twins.
  1454. *
  1455. * Spin-off object twins created by new object twins never
  1456. * require collapsing twin families. For a spin-off object twin
  1457. * generated by a new object twin to collapse twin families,
  1458. * there would have to have been separate twin families
  1459. * connected by a folder twin. But if those twin families were
  1460. * already connected by a folder twin, they would not be
  1461. * separate because they would already have been collapsed by
  1462. * ApplyNewFolderTwinsToTwinFamilies() when the connecting
  1463. * folder twin was added.
  1464. */
  1465. if (! FindObjectTwin(pot->ptfParent->hbr, hpathMatchingFolder,
  1466. GetString(pot->ptfParent->hsName),
  1467. &hnodeUnused))
  1468. {
  1469. POBJECTTWIN potNew;
  1470. /*
  1471. * CreateObjectTwin() ASSERT()s that an object twin for
  1472. * hpathMatchingFolder is not found, so we don't need to do
  1473. * that here.
  1474. */
  1475. if (CreateObjectTwin(pot->ptfParent, hpathMatchingFolder,
  1476. &potNew))
  1477. {
  1478. /*
  1479. * Add the new object twin to hlistNewObjectTwins after
  1480. * the new object twin currently being processed to make
  1481. * certain that it gets processed in the outside loop
  1482. * through hlistNewObjectTwins.
  1483. */
  1484. if (! InsertNodeAfter(hnode, NULL, potNew, &hnodeUnused))
  1485. {
  1486. DestroyStub(&(potNew->stub));
  1487. bResult = FALSE;
  1488. break;
  1489. }
  1490. }
  1491. }
  1492. DeletePath(hpathMatchingFolder);
  1493. }
  1494. else
  1495. {
  1496. bResult = FALSE;
  1497. break;
  1498. }
  1499. }
  1500. }
  1501. }
  1502. return(bResult);
  1503. }
  1504. /*
  1505. ** BuildPathForMatchingObjectTwin()
  1506. **
  1507. **
  1508. **
  1509. ** Arguments:
  1510. **
  1511. ** Returns:
  1512. **
  1513. ** Side Effects: Path is added to object twin's briefcase's path list.
  1514. */
  1515. PUBLIC_CODE BOOL BuildPathForMatchingObjectTwin(PCFOLDERPAIR pcfp,
  1516. PCOBJECTTWIN pcot,
  1517. HPATHLIST hpl, PHPATH phpath)
  1518. {
  1519. BOOL bResult;
  1520. ASSERT(IS_VALID_STRUCT_PTR(pcfp, CFOLDERPAIR));
  1521. ASSERT(IS_VALID_STRUCT_PTR(pcot, COBJECTTWIN));
  1522. ASSERT(IS_VALID_HANDLE(hpl, PATHLIST));
  1523. ASSERT(IS_VALID_WRITE_PTR(phpath, HPATH));
  1524. ASSERT(FolderTwinGeneratesObjectTwin(pcfp, pcot->hpath, GetString(pcot->ptfParent->hsName)));
  1525. /* Is the generating folder twin a subtree twin? */
  1526. if (IsStubFlagSet(&(pcfp->stub), STUB_FL_SUBTREE))
  1527. {
  1528. TCHAR rgchPathSuffix[MAX_PATH_LEN];
  1529. LPCTSTR pcszSubPath;
  1530. /*
  1531. * Yes. Append the object twin's subpath to the subtree twin's base
  1532. * path.
  1533. */
  1534. pcszSubPath = FindChildPathSuffix(pcfp->hpath, pcot->hpath,
  1535. rgchPathSuffix);
  1536. bResult = AddChildPath(hpl, pcfp->pfpOther->hpath, pcszSubPath, phpath);
  1537. }
  1538. else
  1539. /* No. Just use the matching folder twin's folder. */
  1540. bResult = CopyPath(pcfp->pfpOther->hpath, hpl, phpath);
  1541. return(bResult);
  1542. }
  1543. /*
  1544. ** EnumGeneratedObjectTwins()
  1545. **
  1546. **
  1547. **
  1548. ** Arguments:
  1549. **
  1550. ** Returns: FALSE if callback aborted. TRUE if not.
  1551. **
  1552. ** Side Effects: none
  1553. */
  1554. PUBLIC_CODE BOOL EnumGeneratedObjectTwins(PCFOLDERPAIR pcfp,
  1555. ENUMGENERATEDOBJECTTWINSPROC egotp,
  1556. PVOID pvRefData)
  1557. {
  1558. BOOL bResult = TRUE;
  1559. HPTRARRAY hpaTwinFamilies;
  1560. ARRAYINDEX aicPtrs;
  1561. ARRAYINDEX ai;
  1562. /* pvRefData may be any value. */
  1563. ASSERT(IS_VALID_STRUCT_PTR(pcfp, CFOLDERPAIR));
  1564. ASSERT(IS_VALID_CODE_PTR(egotp, ENUMGENERATEDOBJECTTWINPROC));
  1565. /*
  1566. * Walk the array of twin families, looking for twin families whose names
  1567. * intersect the given folder twin's name specification.
  1568. */
  1569. hpaTwinFamilies = GetBriefcaseTwinFamilyPtrArray(pcfp->pfpd->hbr);
  1570. aicPtrs = GetPtrCount(hpaTwinFamilies);
  1571. ai = 0;
  1572. while (ai < aicPtrs)
  1573. {
  1574. PTWINFAMILY ptf;
  1575. LPCTSTR pcszName;
  1576. ptf = GetPtr(hpaTwinFamilies, ai);
  1577. ASSERT(IS_VALID_STRUCT_PTR(ptf, CTWINFAMILY));
  1578. ASSERT(IsStubFlagClear(&(ptf->stub), STUB_FL_UNLINKED));
  1579. /*
  1580. * Does the twin family's name match the folder twin's name
  1581. * specification?
  1582. */
  1583. pcszName = GetString(ptf->hsName);
  1584. if (IsFolderObjectTwinName(pcszName) ||
  1585. NamesIntersect(pcszName, GetString(pcfp->pfpd->hsName)))
  1586. {
  1587. BOOL bContinue;
  1588. HNODE hnodePrev;
  1589. /* Yes. Look for a matching folder. */
  1590. /* Lock the twin family so it isn't deleted out from under us. */
  1591. LockStub(&(ptf->stub));
  1592. /*
  1593. * Walk each twin family's list of object twins looking for object
  1594. * twins in the given folder twin's subtree.
  1595. */
  1596. bContinue = GetFirstNode(ptf->hlistObjectTwins, &hnodePrev);
  1597. while (bContinue)
  1598. {
  1599. HNODE hnodeNext;
  1600. POBJECTTWIN pot;
  1601. bContinue = GetNextNode(hnodePrev, &hnodeNext);
  1602. pot = (POBJECTTWIN)GetNodeData(hnodePrev);
  1603. ASSERT(IS_VALID_STRUCT_PTR(pot, COBJECTTWIN));
  1604. if (FolderTwinIntersectsFolder(pcfp, pot->hpath))
  1605. {
  1606. /*
  1607. * A given object twin should only be generated by one of the
  1608. * folder twins in a pair of folder twins.
  1609. */
  1610. ASSERT(! FolderTwinGeneratesObjectTwin(pcfp->pfpOther, pot->hpath, GetString(pot->ptfParent->hsName)));
  1611. bResult = (*egotp)(pot, pvRefData);
  1612. if (! bResult)
  1613. break;
  1614. }
  1615. hnodePrev = hnodeNext;
  1616. }
  1617. /* Was the twin family unlinked? */
  1618. if (IsStubFlagClear(&(ptf->stub), STUB_FL_UNLINKED))
  1619. /* No. */
  1620. ai++;
  1621. else
  1622. {
  1623. /* Yes. */
  1624. aicPtrs--;
  1625. ASSERT(aicPtrs == GetPtrCount(hpaTwinFamilies));
  1626. TRACE_OUT((TEXT("EnumGeneratedObjectTwins(): Twin family for object %s unlinked by callback."),
  1627. GetString(ptf->hsName)));
  1628. }
  1629. UnlockStub(&(ptf->stub));
  1630. if (! bResult)
  1631. break;
  1632. }
  1633. else
  1634. /* No. Skip it. */
  1635. ai++;
  1636. }
  1637. return(bResult);
  1638. }
  1639. /*
  1640. ** EnumGeneratingFolderTwins()
  1641. **
  1642. **
  1643. **
  1644. ** Arguments:
  1645. **
  1646. ** Returns: FALSE if callback aborted. TRUE if not.
  1647. **
  1648. ** Side Effects: none
  1649. **
  1650. ** N.b., if the egftp callback removes a pair of folder twins, it must remove
  1651. ** the pair from the first folder twin encountered. If it removes the pair of
  1652. ** folder twins from the second folder twin encountered, a folder twin will be
  1653. ** skipped.
  1654. */
  1655. PUBLIC_CODE BOOL EnumGeneratingFolderTwins(PCOBJECTTWIN pcot,
  1656. ENUMGENERATINGFOLDERTWINSPROC egftp,
  1657. PVOID pvRefData,
  1658. PULONG pulcGeneratingFolderTwins)
  1659. {
  1660. BOOL bResult = TRUE;
  1661. HPTRARRAY hpaFolderPairs;
  1662. ARRAYINDEX aicPtrs;
  1663. ARRAYINDEX ai;
  1664. /* pvRefData may be any value. */
  1665. ASSERT(IS_VALID_STRUCT_PTR(pcot, COBJECTTWIN));
  1666. ASSERT(IS_VALID_CODE_PTR(egftp, ENUMGENERATINGFOLDERTWINSPROC));
  1667. ASSERT(IS_VALID_WRITE_PTR(pulcGeneratingFolderTwins, ULONG));
  1668. *pulcGeneratingFolderTwins = 0;
  1669. hpaFolderPairs = GetBriefcaseFolderPairPtrArray(pcot->ptfParent->hbr);
  1670. aicPtrs = GetPtrCount(hpaFolderPairs);
  1671. ASSERT(! (aicPtrs % 2));
  1672. ai = 0;
  1673. while (ai < aicPtrs)
  1674. {
  1675. PFOLDERPAIR pfp;
  1676. pfp = GetPtr(hpaFolderPairs, ai);
  1677. if (FolderTwinGeneratesObjectTwin(pfp, pcot->hpath,
  1678. GetString(pcot->ptfParent->hsName)))
  1679. {
  1680. ASSERT(! FolderTwinGeneratesObjectTwin(pfp->pfpOther, pcot->hpath, GetString(pcot->ptfParent->hsName)));
  1681. ASSERT(*pulcGeneratingFolderTwins < ULONG_MAX);
  1682. (*pulcGeneratingFolderTwins)++;
  1683. /*
  1684. * Lock the pair of folder twins so they don't get deleted out from
  1685. * under us.
  1686. */
  1687. LockStub(&(pfp->stub));
  1688. bResult = (*egftp)(pfp, pvRefData);
  1689. if (IsStubFlagSet(&(pfp->stub), STUB_FL_UNLINKED))
  1690. {
  1691. WARNING_OUT((TEXT("EnumGeneratingFolderTwins(): Folder twin pair unlinked during callback.")));
  1692. aicPtrs -= 2;
  1693. ASSERT(! (aicPtrs % 2));
  1694. ASSERT(aicPtrs == GetPtrCount(hpaFolderPairs));
  1695. }
  1696. else
  1697. ai++;
  1698. UnlockStub(&(pfp->stub));
  1699. if (! bResult)
  1700. break;
  1701. }
  1702. else
  1703. ai++;
  1704. }
  1705. return(bResult);
  1706. }
  1707. /*
  1708. ** FolderTwinGeneratesObjectTwin()
  1709. **
  1710. **
  1711. **
  1712. ** Arguments:
  1713. **
  1714. ** Returns:
  1715. **
  1716. ** Side Effects: none
  1717. **
  1718. ** A folder twin or subtree twin is said to generate an object twin when the
  1719. ** following conditions are met:
  1720. **
  1721. ** 1) The folder twin or subtree twin is on the same volume as the object twin.
  1722. **
  1723. ** 2) The name of the object twin (literal) intersects the objects matched by
  1724. ** the folder twin or subtree twin (literal or wildcard).
  1725. **
  1726. ** 3) The folder twin's folder exactly matches the object twin's folder, or the
  1727. ** subtree twin's root folder is a path prefix of the object twin's folder.
  1728. */
  1729. PUBLIC_CODE BOOL FolderTwinGeneratesObjectTwin(PCFOLDERPAIR pcfp,
  1730. HPATH hpathFolder,
  1731. LPCTSTR pcszName)
  1732. {
  1733. ASSERT(IS_VALID_STRUCT_PTR(pcfp, CFOLDERPAIR));
  1734. ASSERT(IS_VALID_HANDLE(hpathFolder, PATH));
  1735. ASSERT(IS_VALID_STRING_PTR(pcszName, CSTR));
  1736. return(FolderTwinIntersectsFolder(pcfp, hpathFolder) &&
  1737. (IsFolderObjectTwinName(pcszName) ||
  1738. NamesIntersect(pcszName, GetString(pcfp->pfpd->hsName))));
  1739. }
  1740. /*
  1741. ** IsValidHFOLDERTWIN()
  1742. **
  1743. **
  1744. **
  1745. ** Arguments:
  1746. **
  1747. ** Returns:
  1748. **
  1749. ** Side Effects: none
  1750. */
  1751. PUBLIC_CODE BOOL IsValidHFOLDERTWIN(HFOLDERTWIN hft)
  1752. {
  1753. return(IS_VALID_STRUCT_PTR((PFOLDERPAIR)hft, CFOLDERPAIR));
  1754. }
  1755. #ifdef VSTF
  1756. /*
  1757. ** IsValidPCFOLDERPAIR()
  1758. **
  1759. **
  1760. **
  1761. ** Arguments:
  1762. **
  1763. ** Returns:
  1764. **
  1765. ** Side Effects: none
  1766. */
  1767. PUBLIC_CODE BOOL IsValidPCFOLDERPAIR(PCFOLDERPAIR pcfp)
  1768. {
  1769. BOOL bResult = FALSE;
  1770. /* All the fields of an unlinked folder pair should be valid. */
  1771. if (EVAL(IsValidFolderPairHalf(pcfp)))
  1772. {
  1773. if (IsStubFlagSet(&(pcfp->stub), STUB_FL_BEING_DELETED))
  1774. bResult = TRUE;
  1775. else if (EVAL(IsValidFolderPairHalf(pcfp->pfpOther)) &&
  1776. EVAL(pcfp->pfpOther->pfpOther == pcfp) &&
  1777. EVAL(pcfp->pfpd == pcfp->pfpOther->pfpd) &&
  1778. EVAL(pcfp->stub.ulcLock == pcfp->pfpOther->stub.ulcLock))
  1779. {
  1780. BOOL bUnlinked;
  1781. BOOL bOtherUnlinked;
  1782. /*
  1783. * Neither or both folder pair halves may be unlinked, but not only
  1784. * one.
  1785. */
  1786. bUnlinked = IsStubFlagSet(&(pcfp->stub), STUB_FL_UNLINKED);
  1787. bOtherUnlinked = IsStubFlagSet(&(pcfp->pfpOther->stub), STUB_FL_UNLINKED);
  1788. if (EVAL((bUnlinked && bOtherUnlinked) ||
  1789. (! bUnlinked && ! bOtherUnlinked)))
  1790. bResult = TRUE;
  1791. }
  1792. }
  1793. return(bResult);
  1794. }
  1795. #endif
  1796. /*
  1797. ** WriteFolderPairList()
  1798. **
  1799. **
  1800. **
  1801. ** Arguments:
  1802. **
  1803. ** Returns: TWINRESULT
  1804. **
  1805. ** Side Effects: none
  1806. */
  1807. PUBLIC_CODE TWINRESULT WriteFolderPairList(HCACHEDFILE hcf,
  1808. HPTRARRAY hpaFolderPairs)
  1809. {
  1810. TWINRESULT tr = TR_BRIEFCASE_WRITE_FAILED;
  1811. DWORD dwcbDBFolderTwinListHeaderOffset;
  1812. ASSERT(IS_VALID_HANDLE(hcf, CACHEDFILE));
  1813. ASSERT(IS_VALID_HANDLE(hpaFolderPairs, PTRARRAY));
  1814. /* Save initial file position. */
  1815. dwcbDBFolderTwinListHeaderOffset = GetCachedFilePointerPosition(hcf);
  1816. if (dwcbDBFolderTwinListHeaderOffset != INVALID_SEEK_POSITION)
  1817. {
  1818. DBFOLDERTWINLISTHEADER dbftlh;
  1819. /* Leave space for folder twin data header. */
  1820. ZeroMemory(&dbftlh, sizeof(dbftlh));
  1821. if (WriteToCachedFile(hcf, (PCVOID)&dbftlh, sizeof(dbftlh), NULL))
  1822. {
  1823. ARRAYINDEX aicPtrs;
  1824. ARRAYINDEX ai;
  1825. tr = TR_SUCCESS;
  1826. /* Mark all folder pairs unused. */
  1827. ClearFlagInArrayOfStubs(hpaFolderPairs, STUB_FL_USED);
  1828. aicPtrs = GetPtrCount(hpaFolderPairs);
  1829. ASSERT(! (aicPtrs % 2));
  1830. /* Write all folder pairs. */
  1831. for (ai = 0; ai < aicPtrs; ai++)
  1832. {
  1833. PFOLDERPAIR pfp;
  1834. pfp = GetPtr(hpaFolderPairs, ai);
  1835. ASSERT(IS_VALID_STRUCT_PTR(pfp, CFOLDERPAIR));
  1836. if (IsStubFlagClear(&(pfp->stub), STUB_FL_USED))
  1837. {
  1838. ASSERT(IsStubFlagClear(&(pfp->pfpOther->stub), STUB_FL_USED));
  1839. tr = WriteFolderPair(hcf, pfp);
  1840. if (tr == TR_SUCCESS)
  1841. {
  1842. SetStubFlag(&(pfp->stub), STUB_FL_USED);
  1843. SetStubFlag(&(pfp->pfpOther->stub), STUB_FL_USED);
  1844. }
  1845. else
  1846. break;
  1847. }
  1848. }
  1849. /* Save folder twin data header. */
  1850. if (tr == TR_SUCCESS)
  1851. {
  1852. ASSERT(! (aicPtrs % 2));
  1853. dbftlh.lcFolderPairs = aicPtrs / 2;
  1854. tr = WriteDBSegmentHeader(hcf, dwcbDBFolderTwinListHeaderOffset,
  1855. &dbftlh, sizeof(dbftlh));
  1856. if (tr == TR_SUCCESS)
  1857. TRACE_OUT((TEXT("WriteFolderPairList(): Wrote %ld folder pairs."),
  1858. dbftlh.lcFolderPairs));
  1859. }
  1860. }
  1861. }
  1862. return(tr);
  1863. }
  1864. /*
  1865. ** ReadFolderPairList()
  1866. **
  1867. **
  1868. **
  1869. ** Arguments:
  1870. **
  1871. ** Returns: TWINRESULT
  1872. **
  1873. ** Side Effects: none
  1874. */
  1875. PUBLIC_CODE TWINRESULT ReadFolderPairList(HCACHEDFILE hcf, HBRFCASE hbr,
  1876. HHANDLETRANS hhtFolderTrans,
  1877. HHANDLETRANS hhtNameTrans)
  1878. {
  1879. TWINRESULT tr;
  1880. DBFOLDERTWINLISTHEADER dbftlh;
  1881. DWORD dwcbRead;
  1882. ASSERT(IS_VALID_HANDLE(hcf, CACHEDFILE));
  1883. ASSERT(IS_VALID_HANDLE(hbr, BRFCASE));
  1884. ASSERT(IS_VALID_HANDLE(hhtFolderTrans, HANDLETRANS));
  1885. ASSERT(IS_VALID_HANDLE(hhtNameTrans, HANDLETRANS));
  1886. if (ReadFromCachedFile(hcf, &dbftlh, sizeof(dbftlh), &dwcbRead) &&
  1887. dwcbRead == sizeof(dbftlh))
  1888. {
  1889. LONG l;
  1890. tr = TR_SUCCESS;
  1891. TRACE_OUT((TEXT("ReadFolderPairList(): Reading %ld folder pairs."),
  1892. dbftlh.lcFolderPairs));
  1893. for (l = 0; l < dbftlh.lcFolderPairs && tr == TR_SUCCESS; l++)
  1894. tr = ReadFolderPair(hcf, hbr, hhtFolderTrans, hhtNameTrans);
  1895. ASSERT(tr != TR_SUCCESS || AreFolderPairsValid(GetBriefcaseFolderPairPtrArray(hbr)));
  1896. }
  1897. else
  1898. tr = TR_CORRUPT_BRIEFCASE;
  1899. return(tr);
  1900. }
  1901. /***************************** Exported Functions ****************************/
  1902. /******************************************************************************
  1903. @doc SYNCENGAPI
  1904. @api TWINRESULT | AddFolderTwin | Twins two folders.
  1905. @parm HBRFCASE | hbr | A handle to the open briefcase that the new folder twins
  1906. are to be added to.
  1907. @parm PCNEWFOLDERTWIN | pcnft | A pointer to a CNEWFOLDERTWIN describing the
  1908. two folders to be twinned.
  1909. @parm PHFOLDERTWIN | phft | A pointer to an HFOLDERTWIN to be filled in with
  1910. a handle to the new folder twins. *phft is only valid if TR_SUCCESS or
  1911. TR_DUPLICATE_TWIN is returned.
  1912. @rdesc If the folder twins were added successfully, TR_SUCCESS is returned, and
  1913. *phFolderTwin contains a handle to the new folder twins. Otherwise, the
  1914. folder twins were not added successfully, the return value indicates the error
  1915. that occurred, and *phFolderTwin is undefined. If one or both of the volumes
  1916. specified by the NEWFOLDERTWIN structure is not present, TR_UNAVAILABLE_VOLUME
  1917. will be returned, and the folder twin will not be added.
  1918. @comm Once the caller is finshed with the twin handle returned by
  1919. AddFolderTwin(), ReleaseTwinHandle() should be called to release the twin
  1920. handle. N.b., DeleteTwin() does not release a twin handle returned by
  1921. AddFolderTwin().
  1922. @xref ReleaseTwinHandle DeleteTwin
  1923. ******************************************************************************/
  1924. SYNCENGAPI TWINRESULT WINAPI AddFolderTwin(HBRFCASE hbr, PCNEWFOLDERTWIN pcnft,
  1925. PHFOLDERTWIN phft)
  1926. {
  1927. TWINRESULT tr;
  1928. if (BeginExclusiveBriefcaseAccess())
  1929. {
  1930. DebugEntry(AddFolderTwin);
  1931. #ifdef EXPV
  1932. /* Verify parameters. */
  1933. if (IS_VALID_HANDLE(hbr, BRFCASE) &&
  1934. IS_VALID_STRUCT_PTR(pcnft, CNEWFOLDERTWIN) &&
  1935. EVAL(pcnft->ulSize == sizeof(*pcnft)) &&
  1936. IS_VALID_WRITE_PTR(phft, HFOLDERTWIN))
  1937. #endif
  1938. {
  1939. INEWFOLDERTWIN inft;
  1940. InvalidatePathListInfo(GetBriefcasePathList(hbr));
  1941. tr = MakeINewFolderTwin(hbr, pcnft, &inft);
  1942. if (tr == TR_SUCCESS)
  1943. {
  1944. PFOLDERPAIR pfp;
  1945. ASSERT(! IS_ATTR_DIR(pcnft->dwAttributes));
  1946. tr = TwinFolders(&inft, &pfp);
  1947. if (tr == TR_SUCCESS ||
  1948. tr == TR_DUPLICATE_TWIN)
  1949. {
  1950. LockStub(&(pfp->stub));
  1951. *phft = (HFOLDERTWIN)pfp;
  1952. }
  1953. ReleaseINewFolderTwin(&inft);
  1954. }
  1955. }
  1956. #ifdef EXPV
  1957. else
  1958. tr = TR_INVALID_PARAMETER;
  1959. #endif
  1960. DebugExitTWINRESULT(AddFolderTwin, tr);
  1961. EndExclusiveBriefcaseAccess();
  1962. }
  1963. else
  1964. tr = TR_REENTERED;
  1965. return(tr);
  1966. }
  1967. /******************************************************************************
  1968. @doc SYNCENGAPI
  1969. @api TWINRESULT | IsFolderTwin | Determines whether or not a folder is a
  1970. folder twin.
  1971. @parm HBRFCASE | hbr | A handle to the open briefcase to check for the folder
  1972. twin.
  1973. @parm PCSTR | pcszFolder | A pointer to a string indicating the folder in
  1974. question.
  1975. @parm PBOOL | pbIsFolderTwin | A pointer to a BOOL to be filled in with TRUE
  1976. if the folder is a folder twin, or FALSE if not. *pbIsFolderTwin is only
  1977. valid if TR_SUCCESS is returned.
  1978. @rdesc If the lookup was successful, TR_SUCCESS is returned. Otherwise, the
  1979. lookup was not successful, and the return value indicates the error that
  1980. occurred.
  1981. @xref CreateFolderTwinList DestroyFolderTwinList
  1982. ******************************************************************************/
  1983. SYNCENGAPI TWINRESULT WINAPI IsFolderTwin(HBRFCASE hbr, LPCTSTR pcszFolder,
  1984. PBOOL pbIsFolderTwin)
  1985. {
  1986. TWINRESULT tr;
  1987. if (BeginExclusiveBriefcaseAccess())
  1988. {
  1989. DebugEntry(IsFolderTwin);
  1990. #ifdef EXPV
  1991. /* Verify parameters. */
  1992. if (IS_VALID_HANDLE(hbr, BRFCASE) &&
  1993. IS_VALID_STRING_PTR(pcszFolder, CSTR) &&
  1994. IS_VALID_WRITE_PTR(pbIsFolderTwin, BOOL))
  1995. #endif
  1996. {
  1997. HPATH hpath;
  1998. InvalidatePathListInfo(GetBriefcasePathList(hbr));
  1999. tr = TranslatePATHRESULTToTWINRESULT(
  2000. AddPath(GetBriefcasePathList(hbr), pcszFolder, &hpath));
  2001. if (tr == TR_SUCCESS)
  2002. {
  2003. ARRAYINDEX aiFirst;
  2004. /* Search for folder pair referencing given folder. */
  2005. *pbIsFolderTwin = SearchSortedArray(
  2006. GetBriefcaseFolderPairPtrArray(hbr),
  2007. &FolderPairSearchCmp, hpath, &aiFirst);
  2008. if (*pbIsFolderTwin)
  2009. TRACE_OUT((TEXT("IsFolderTwin(): %s is a folder twin."),
  2010. DebugGetPathString(hpath)));
  2011. else
  2012. TRACE_OUT((TEXT("IsFolderTwin(): %s is not a folder twin."),
  2013. DebugGetPathString(hpath)));
  2014. DeletePath(hpath);
  2015. }
  2016. }
  2017. #ifdef EXPV
  2018. else
  2019. tr = TR_INVALID_PARAMETER;
  2020. #endif
  2021. DebugExitTWINRESULT(IsFolderTwin, tr);
  2022. EndExclusiveBriefcaseAccess();
  2023. }
  2024. else
  2025. tr = TR_REENTERED;
  2026. return(tr);
  2027. }
  2028. /******************************************************************************
  2029. @doc SYNCENGAPI
  2030. @api TWINRESULT | CreateFolderTwinList | Creates a list of the folder twins of
  2031. a given folder.
  2032. @parm HBRFCASE | hbr | A handle to the open briefcase that the folder twin list
  2033. is to be created from.
  2034. @parm PCSTR | pcszFolder | A pointer to a string indicating the folder whose
  2035. folder twins are to be listed.
  2036. @parm PFOLDERTWINLIST | ppftl | A pointer to an PFOLDERTWINLIST to be
  2037. filled in with a pointer to the new list of folder twins. *ppFolderTwinList
  2038. is only valid if TR_SUCCESS is returned.
  2039. @rdesc If the folder twin list was created successfully, TR_SUCCESS is
  2040. returned. Otherwise, the folder twin list was not created successfully, and
  2041. the return value indicates the error that occurred.
  2042. @xref DestroyFolderTwinList IsFolderTwin
  2043. ******************************************************************************/
  2044. SYNCENGAPI TWINRESULT WINAPI CreateFolderTwinList(HBRFCASE hbr,
  2045. LPCTSTR pcszFolder,
  2046. PFOLDERTWINLIST *ppftl)
  2047. {
  2048. TWINRESULT tr;
  2049. if (BeginExclusiveBriefcaseAccess())
  2050. {
  2051. DebugEntry(CreateFolderTwinList);
  2052. #ifdef EXPV
  2053. /* Verify parameters. */
  2054. if (IS_VALID_HANDLE(hbr, BRFCASE) &&
  2055. IS_VALID_STRING_PTR(pcszFolder, CSTR) &&
  2056. IS_VALID_WRITE_PTR(ppftl, PFOLDERTWINLIST))
  2057. #endif
  2058. {
  2059. HPATH hpath;
  2060. InvalidatePathListInfo(GetBriefcasePathList(hbr));
  2061. tr = TranslatePATHRESULTToTWINRESULT(
  2062. AddPath(GetBriefcasePathList(hbr), pcszFolder, &hpath));
  2063. if (tr == TR_SUCCESS)
  2064. {
  2065. PFOLDERTWINLIST pftlNew;
  2066. /* Try to create a new folder twin list. */
  2067. if (AllocateMemory(sizeof(*pftlNew), &pftlNew))
  2068. {
  2069. ARRAYINDEX ai;
  2070. /* Initialize FOLDERTWINLIST structure fields. */
  2071. pftlNew->ulcItems = 0;
  2072. pftlNew->pcftFirst = NULL;
  2073. pftlNew->hbr = hbr;
  2074. /* Search for first folder pair referencing given folder. */
  2075. if (SearchSortedArray(GetBriefcaseFolderPairPtrArray(hbr),
  2076. &FolderPairSearchCmp, hpath, &ai))
  2077. {
  2078. PFOLDERTWIN pftHead;
  2079. ARRAYINDEX aicFolderTwins;
  2080. tr = CreateListOfFolderTwins(hbr, ai, hpath, &pftHead, &aicFolderTwins);
  2081. if (tr == TR_SUCCESS)
  2082. {
  2083. /* Success! Update parent folder twin list fields. */
  2084. pftlNew->pcftFirst = pftHead;
  2085. pftlNew->ulcItems = aicFolderTwins;
  2086. }
  2087. else
  2088. /* Free data structure, ignoring return value. */
  2089. FreeMemory(pftlNew);
  2090. }
  2091. else
  2092. tr = TR_SUCCESS;
  2093. /* Return pointer to new FOLDERTWINLIST. */
  2094. if (tr == TR_SUCCESS)
  2095. {
  2096. *ppftl = pftlNew;
  2097. ASSERT(IS_VALID_STRUCT_PTR(*ppftl, CFOLDERTWINLIST));
  2098. }
  2099. }
  2100. else
  2101. tr = TR_OUT_OF_MEMORY;
  2102. DeletePath(hpath);
  2103. }
  2104. }
  2105. #ifdef EXPV
  2106. else
  2107. tr = TR_INVALID_PARAMETER;
  2108. #endif
  2109. DebugExitTWINRESULT(CreateFolderTwinList, tr);
  2110. EndExclusiveBriefcaseAccess();
  2111. }
  2112. else
  2113. tr = TR_REENTERED;
  2114. return(tr);
  2115. }
  2116. /******************************************************************************
  2117. @doc SYNCENGAPI
  2118. @api TWINRESULT | DestroyFolderTwinList | Destroys a folder twin list created
  2119. by CreateFolderTwinList().
  2120. @parm PFOLDERTWINLIST | pftl | A pointer to the folder twin list to be
  2121. destroyed. The FOLDERTWINLIST pointed to by pftl is not valid after
  2122. DestroyFolderTwinList() is called.
  2123. @rdesc If the folder twin list was deleted successfully, TR_SUCCESS is
  2124. returned. Otherwise, the folder twin list was not deleted successfully, and
  2125. the return value indicates the error that occurred.
  2126. @xref CreateFolderTwinList IsFolderTwin
  2127. ******************************************************************************/
  2128. SYNCENGAPI TWINRESULT WINAPI DestroyFolderTwinList(PFOLDERTWINLIST pftl)
  2129. {
  2130. TWINRESULT tr;
  2131. if (BeginExclusiveBriefcaseAccess())
  2132. {
  2133. DebugEntry(DestroyFolderTwinList);
  2134. #ifdef EXPV
  2135. /* Verify parameters. */
  2136. if (IS_VALID_STRUCT_PTR(pftl, CFOLDERTWINLIST))
  2137. #endif
  2138. {
  2139. DestroyListOfFolderTwins((PFOLDERTWIN)(pftl->pcftFirst));
  2140. FreeMemory(pftl);
  2141. tr = TR_SUCCESS;
  2142. }
  2143. #ifdef EXPV
  2144. else
  2145. tr = TR_INVALID_PARAMETER;
  2146. #endif
  2147. DebugExitTWINRESULT(DestroyFolderTwinList, tr);
  2148. EndExclusiveBriefcaseAccess();
  2149. }
  2150. else
  2151. tr = TR_REENTERED;
  2152. return(tr);
  2153. }