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.

3727 lines
99 KiB

  1. /*
  2. * twin.c - Twin ADT module.
  3. */
  4. /*
  5. */
  6. /* Headers
  7. **********/
  8. #include "project.h"
  9. #pragma hdrstop
  10. #include "stub.h"
  11. #include "oleutil.h"
  12. /* Constants
  13. ************/
  14. /* twin family pointer array allocation constants */
  15. #define NUM_START_TWIN_FAMILY_PTRS (16)
  16. #define NUM_TWIN_FAMILY_PTRS_TO_ADD (16)
  17. /* Types
  18. ********/
  19. /* twin families database structure header */
  20. typedef struct _twinfamiliesdbheader
  21. {
  22. /* number of twin families */
  23. LONG lcTwinFamilies;
  24. }
  25. TWINFAMILIESDBHEADER;
  26. DECLARE_STANDARD_TYPES(TWINFAMILIESDBHEADER);
  27. /* individual twin family database structure header */
  28. typedef struct _twinfamilydbheader
  29. {
  30. /* stub flags */
  31. DWORD dwStubFlags;
  32. /* old string handle of name */
  33. HSTRING hsName;
  34. /* number of object twins in family */
  35. LONG lcObjectTwins;
  36. }
  37. TWINFAMILYDBHEADER;
  38. DECLARE_STANDARD_TYPES(TWINFAMILYDBHEADER);
  39. /* object twin database structure */
  40. typedef struct _dbobjecttwin
  41. {
  42. /* stub flags */
  43. DWORD dwStubFlags;
  44. /* old handle to folder string */
  45. HPATH hpath;
  46. /* time stamp at last reconciliation */
  47. FILESTAMP fsLastRec;
  48. }
  49. DBOBJECTTWIN;
  50. DECLARE_STANDARD_TYPES(DBOBJECTTWIN);
  51. /* GenerateSpinOffObjectTwin() callback structure */
  52. typedef struct _spinoffobjecttwininfo
  53. {
  54. PCFOLDERPAIR pcfp;
  55. HLIST hlistNewObjectTwins;
  56. }
  57. SPINOFFOBJECTTWININFO;
  58. DECLARE_STANDARD_TYPES(SPINOFFOBJECTTWININFO);
  59. typedef void (CALLBACK *COPYOBJECTTWINPROC)(POBJECTTWIN, PCDBOBJECTTWIN);
  60. /***************************** Private Functions *****************************/
  61. /* Module Prototypes
  62. ********************/
  63. PRIVATE_CODE TWINRESULT TwinJustTheseTwoObjects(HBRFCASE, HPATH, HPATH, LPCTSTR, POBJECTTWIN *, POBJECTTWIN *, HLIST);
  64. PRIVATE_CODE BOOL CreateTwinFamily(HBRFCASE, LPCTSTR, PTWINFAMILY *);
  65. PRIVATE_CODE void CollapseTwinFamilies(PTWINFAMILY, PTWINFAMILY);
  66. PRIVATE_CODE BOOL GenerateSpinOffObjectTwin(PVOID, PVOID);
  67. PRIVATE_CODE BOOL BuildBradyBunch(PVOID, PVOID);
  68. PRIVATE_CODE BOOL CreateObjectTwinAndAddToList(PTWINFAMILY, HPATH, HLIST, POBJECTTWIN *, PHNODE);
  69. PRIVATE_CODE BOOL CreateListOfGeneratedObjectTwins(PCFOLDERPAIR, PHLIST);
  70. PRIVATE_CODE void NotifyNewObjectTwins(HLIST, HCLSIFACECACHE);
  71. PRIVATE_CODE HRESULT NotifyOneNewObjectTwin(PINotifyReplica, PCOBJECTTWIN, LPCTSTR);
  72. PRIVATE_CODE HRESULT CreateOtherReplicaMonikers(PCOBJECTTWIN, PULONG, PIMoniker **);
  73. PRIVATE_CODE COMPARISONRESULT TwinFamilySortCmp(PCVOID, PCVOID);
  74. PRIVATE_CODE COMPARISONRESULT TwinFamilySearchCmp(PCVOID, PCVOID);
  75. PRIVATE_CODE BOOL ObjectTwinSearchCmp(PCVOID, PCVOID);
  76. PRIVATE_CODE TWINRESULT WriteTwinFamily(HCACHEDFILE, PCTWINFAMILY);
  77. PRIVATE_CODE TWINRESULT WriteObjectTwin(HCACHEDFILE, PCOBJECTTWIN);
  78. PRIVATE_CODE TWINRESULT ReadTwinFamily(HCACHEDFILE, HBRFCASE, PCDBVERSION, HHANDLETRANS, HHANDLETRANS);
  79. PRIVATE_CODE TWINRESULT ReadObjectTwin(HCACHEDFILE, PCDBVERSION, PTWINFAMILY, HHANDLETRANS);
  80. PRIVATE_CODE void CopyTwinFamilyInfo(PTWINFAMILY, PCTWINFAMILYDBHEADER);
  81. PRIVATE_CODE void CopyObjectTwinInfo(POBJECTTWIN, PCDBOBJECTTWIN);
  82. PRIVATE_CODE void CopyM8ObjectTwinInfo(POBJECTTWIN, PCDBOBJECTTWIN);
  83. PRIVATE_CODE BOOL DestroyObjectTwinStubWalker(PVOID, PVOID);
  84. PRIVATE_CODE BOOL MarkObjectTwinNeverReconciledWalker(PVOID, PVOID);
  85. PRIVATE_CODE BOOL LookForSrcFolderTwinsWalker(PVOID, PVOID);
  86. PRIVATE_CODE BOOL IncrementSrcFolderTwinsWalker(PVOID, PVOID);
  87. PRIVATE_CODE BOOL ClearSrcFolderTwinsWalker(PVOID, PVOID);
  88. PRIVATE_CODE BOOL SetTwinFamilyWalker(PVOID, PVOID);
  89. PRIVATE_CODE BOOL InsertNodeAtFrontWalker(POBJECTTWIN, PVOID);
  90. #ifdef VSTF
  91. PRIVATE_CODE BOOL IsValidObjectTwinWalker(PVOID, PVOID);
  92. PRIVATE_CODE BOOL IsValidPCNEWOBJECTTWIN(PCNEWOBJECTTWIN);
  93. PRIVATE_CODE BOOL IsValidPCSPINOFFOBJECTTWININFO(PCSPINOFFOBJECTTWININFO);
  94. #endif
  95. #ifdef DEBUG
  96. PRIVATE_CODE BOOL AreTwinFamiliesValid(HPTRARRAY);
  97. #endif
  98. /*
  99. ** TwinJustTheseTwoObjects()
  100. **
  101. **
  102. **
  103. ** Arguments:
  104. **
  105. ** Returns:
  106. **
  107. ** Side Effects: none
  108. */
  109. PRIVATE_CODE TWINRESULT TwinJustTheseTwoObjects(HBRFCASE hbr, HPATH hpathFolder1,
  110. HPATH hpathFolder2, LPCTSTR pcszName,
  111. POBJECTTWIN *ppot1,
  112. POBJECTTWIN *ppot2,
  113. HLIST hlistNewObjectTwins)
  114. {
  115. TWINRESULT tr = TR_OUT_OF_MEMORY;
  116. HNODE hnodeSearch;
  117. BOOL bFound1;
  118. BOOL bFound2;
  119. ASSERT(IS_VALID_HANDLE(hbr, BRFCASE));
  120. ASSERT(IS_VALID_HANDLE(hpathFolder1, PATH));
  121. ASSERT(IS_VALID_HANDLE(hpathFolder2, PATH));
  122. ASSERT(IS_VALID_STRING_PTR(pcszName, CSTR));
  123. ASSERT(IS_VALID_WRITE_PTR(ppot1, POBJECTTWIN));
  124. ASSERT(IS_VALID_WRITE_PTR(ppot2, POBJECTTWIN));
  125. ASSERT(IS_VALID_HANDLE(hlistNewObjectTwins, LIST));
  126. /* Determine twin families of existing object twins. */
  127. bFound1 = FindObjectTwin(hbr, hpathFolder1, pcszName, &hnodeSearch);
  128. if (bFound1)
  129. *ppot1 = (POBJECTTWIN)GetNodeData(hnodeSearch);
  130. bFound2 = FindObjectTwin(hbr, hpathFolder2, pcszName, &hnodeSearch);
  131. if (bFound2)
  132. *ppot2 = (POBJECTTWIN)GetNodeData(hnodeSearch);
  133. /* Take action based upon existence of two object twins. */
  134. if (! bFound1 && ! bFound2)
  135. {
  136. PTWINFAMILY ptfNew;
  137. /* Neither object is already present. Create a new twin family. */
  138. if (CreateTwinFamily(hbr, pcszName, &ptfNew))
  139. {
  140. HNODE hnodeNew1;
  141. if (CreateObjectTwinAndAddToList(ptfNew, hpathFolder1,
  142. hlistNewObjectTwins, ppot1,
  143. &hnodeNew1))
  144. {
  145. HNODE hnodeNew2;
  146. if (CreateObjectTwinAndAddToList(ptfNew, hpathFolder2,
  147. hlistNewObjectTwins, ppot2,
  148. &hnodeNew2))
  149. {
  150. TRACE_OUT((TEXT("TwinJustTheseTwoObjects(): Created a twin family for object %s in folders %s and %s."),
  151. pcszName,
  152. DebugGetPathString(hpathFolder1),
  153. DebugGetPathString(hpathFolder2)));
  154. ASSERT(IsStubFlagClear(&(ptfNew->stub), STUB_FL_DELETION_PENDING));
  155. tr = TR_SUCCESS;
  156. }
  157. else
  158. {
  159. DeleteNode(hnodeNew1);
  160. DestroyStub(&((*ppot1)->stub));
  161. TWINJUSTTHESETWOOBJECTS_BAIL:
  162. DestroyStub(&(ptfNew->stub));
  163. }
  164. }
  165. else
  166. goto TWINJUSTTHESETWOOBJECTS_BAIL;
  167. }
  168. }
  169. else if (bFound1 && bFound2)
  170. {
  171. /*
  172. * Both objects are already present. Are they members of the same twin
  173. * family?
  174. */
  175. if ((*ppot1)->ptfParent == (*ppot2)->ptfParent)
  176. {
  177. /* Yes, same twin family. Complain that these twins already exist. */
  178. TRACE_OUT((TEXT("TwinJustTheseTwoObjects(): Object %s is already twinned in folders %s and %s."),
  179. pcszName,
  180. DebugGetPathString(hpathFolder1),
  181. DebugGetPathString(hpathFolder2)));
  182. tr = TR_DUPLICATE_TWIN;
  183. }
  184. else
  185. {
  186. /*
  187. * No, different twin families. Collapse the two families.
  188. *
  189. * "That's the way they became the Brady bunch..."
  190. *
  191. * *ppot1 and *ppot2 remain valid across this call.
  192. */
  193. TRACE_OUT((TEXT("TwinJustTheseTwoObjects(): Collapsing separate twin families for object %s in folders %s and %s."),
  194. pcszName,
  195. DebugGetPathString(hpathFolder1),
  196. DebugGetPathString(hpathFolder2)));
  197. CollapseTwinFamilies((*ppot1)->ptfParent, (*ppot2)->ptfParent);
  198. tr = TR_SUCCESS;
  199. }
  200. }
  201. else
  202. {
  203. PTWINFAMILY ptfParent;
  204. HNODE hnodeUnused;
  205. /*
  206. * Only one of the two objects is present. Add the new object twin
  207. * to the existing object twin's family.
  208. */
  209. if (bFound1)
  210. {
  211. /* First object is already a twin. */
  212. ptfParent = (*ppot1)->ptfParent;
  213. if (CreateObjectTwinAndAddToList(ptfParent, hpathFolder2,
  214. hlistNewObjectTwins, ppot2,
  215. &hnodeUnused))
  216. {
  217. TRACE_OUT((TEXT("TwinJustTheseTwoObjects(): Adding twin of object %s\\%s to existing twin family including %s\\%s."),
  218. DebugGetPathString(hpathFolder2),
  219. pcszName,
  220. DebugGetPathString(hpathFolder1),
  221. pcszName));
  222. tr = TR_SUCCESS;
  223. }
  224. }
  225. else
  226. {
  227. /* Second object is already a twin. */
  228. ptfParent = (*ppot2)->ptfParent;
  229. if (CreateObjectTwinAndAddToList(ptfParent, hpathFolder1,
  230. hlistNewObjectTwins, ppot1,
  231. &hnodeUnused))
  232. {
  233. TRACE_OUT((TEXT("TwinJustTheseTwoObjects(): Adding twin of object %s\\%s to existing twin family including %s\\%s."),
  234. DebugGetPathString(hpathFolder1),
  235. pcszName,
  236. DebugGetPathString(hpathFolder2),
  237. pcszName));
  238. tr = TR_SUCCESS;
  239. }
  240. }
  241. }
  242. ASSERT((tr != TR_SUCCESS && tr != TR_DUPLICATE_TWIN) ||
  243. IS_VALID_STRUCT_PTR(*ppot1, COBJECTTWIN) && IS_VALID_STRUCT_PTR(*ppot2, COBJECTTWIN));
  244. return(tr);
  245. }
  246. /*
  247. ** CreateTwinFamily()
  248. **
  249. ** Creates a new empty twin family, and adds it to a briefcase.
  250. **
  251. ** Arguments:
  252. **
  253. ** Returns: TWINRESULT
  254. **
  255. ** Side Effects: none
  256. */
  257. PRIVATE_CODE BOOL CreateTwinFamily(HBRFCASE hbr, LPCTSTR pcszName, PTWINFAMILY *pptf)
  258. {
  259. BOOL bResult = FALSE;
  260. PTWINFAMILY ptfNew;
  261. ASSERT(IS_VALID_HANDLE(hbr, BRFCASE));
  262. ASSERT(IS_VALID_STRING_PTR(pcszName, CSTR));
  263. ASSERT(IS_VALID_WRITE_PTR(pptf, PTWINFAMILY));
  264. /* Try to create a new TWINFAMILY structure. */
  265. if (AllocateMemory(sizeof(*ptfNew), &ptfNew))
  266. {
  267. NEWLIST nl;
  268. HLIST hlistObjectTwins;
  269. /* Create a list of object twins for the new twin family. */
  270. nl.dwFlags = 0;
  271. if (CreateList(&nl, &hlistObjectTwins))
  272. {
  273. HSTRING hsName;
  274. /* Add the object name to the name string table. */
  275. if (AddString(pcszName, GetBriefcaseNameStringTable(hbr),
  276. GetHashBucketIndex, &hsName))
  277. {
  278. ARRAYINDEX aiUnused;
  279. /* Fill in TWINFAMILY fields. */
  280. InitStub(&(ptfNew->stub), ST_TWINFAMILY);
  281. ptfNew->hsName = hsName;
  282. ptfNew->hlistObjectTwins = hlistObjectTwins;
  283. ptfNew->hbr = hbr;
  284. MarkTwinFamilyNeverReconciled(ptfNew);
  285. /* Add the twin family to the briefcase's list of twin families. */
  286. if (AddPtr(GetBriefcaseTwinFamilyPtrArray(hbr), TwinFamilySortCmp, ptfNew, &aiUnused))
  287. {
  288. *pptf = ptfNew;
  289. bResult = TRUE;
  290. ASSERT(IS_VALID_STRUCT_PTR(*pptf, CTWINFAMILY));
  291. }
  292. else
  293. {
  294. DeleteString(hsName);
  295. CREATETWINFAMILY_BAIL1:
  296. DestroyList(hlistObjectTwins);
  297. CREATETWINFAMILY_BAIL2:
  298. FreeMemory(ptfNew);
  299. }
  300. }
  301. else
  302. goto CREATETWINFAMILY_BAIL1;
  303. }
  304. else
  305. goto CREATETWINFAMILY_BAIL2;
  306. }
  307. return(bResult);
  308. }
  309. /*
  310. ** CollapseTwinFamilies()
  311. **
  312. ** Collapses two twin families into one. N.b., this function should only be
  313. ** called on two twin families with the same object name!
  314. **
  315. ** Arguments: ptf1 - pointer to destination twin family
  316. ** ptf2 - pointer to source twin family
  317. **
  318. ** Returns: void
  319. **
  320. ** Side Effects: Twin family *ptf2 is destroyed.
  321. */
  322. PRIVATE_CODE void CollapseTwinFamilies(PTWINFAMILY ptf1, PTWINFAMILY ptf2)
  323. {
  324. ASSERT(IS_VALID_STRUCT_PTR(ptf1, CTWINFAMILY));
  325. ASSERT(IS_VALID_STRUCT_PTR(ptf2, CTWINFAMILY));
  326. ASSERT(CompareNameStringsByHandle(ptf1->hsName, ptf2->hsName) == CR_EQUAL);
  327. /* Use the first twin family as the collapsed twin family. */
  328. /*
  329. * Change the parent twin family of the object twins in the second twin
  330. * family to the first twin family.
  331. */
  332. EVAL(WalkList(ptf2->hlistObjectTwins, &SetTwinFamilyWalker, ptf1));
  333. /* Append object list from second twin family on to first. */
  334. AppendList(ptf1->hlistObjectTwins, ptf2->hlistObjectTwins);
  335. MarkTwinFamilyNeverReconciled(ptf1);
  336. /* Wipe out the old twin family. */
  337. DestroyStub(&(ptf2->stub));
  338. ASSERT(IS_VALID_STRUCT_PTR(ptf1, CTWINFAMILY));
  339. return;
  340. }
  341. /*
  342. ** GenerateSpinOffObjectTwin()
  343. **
  344. **
  345. **
  346. ** Arguments:
  347. **
  348. ** Returns:
  349. **
  350. ** Side Effects: none
  351. */
  352. PRIVATE_CODE BOOL GenerateSpinOffObjectTwin(PVOID pot, PVOID pcsooti)
  353. {
  354. BOOL bResult;
  355. HPATH hpathMatchingFolder;
  356. HNODE hnodeUnused;
  357. ASSERT(IS_VALID_STRUCT_PTR(pot, COBJECTTWIN));
  358. ASSERT(IS_VALID_STRUCT_PTR(pcsooti, CSPINOFFOBJECTTWININFO));
  359. /*
  360. * Append the generated object twin's subpath to the matching folder twin's
  361. * base path for subtree twins.
  362. */
  363. if (BuildPathForMatchingObjectTwin(
  364. ((PCSPINOFFOBJECTTWININFO)pcsooti)->pcfp, pot,
  365. GetBriefcasePathList(((POBJECTTWIN)pot)->ptfParent->hbr),
  366. &hpathMatchingFolder))
  367. {
  368. /*
  369. * Does this generated object twin's twin family already contain an
  370. * object twin generated by the other half of the pair of folder twins?
  371. */
  372. if (! SearchUnsortedList(((POBJECTTWIN)pot)->ptfParent->hlistObjectTwins,
  373. &ObjectTwinSearchCmp, hpathMatchingFolder,
  374. &hnodeUnused))
  375. {
  376. /*
  377. * No. Does the other object twin already exist in a different twin
  378. * family?
  379. */
  380. if (FindObjectTwin(((POBJECTTWIN)pot)->ptfParent->hbr,
  381. hpathMatchingFolder,
  382. GetString(((POBJECTTWIN)pot)->ptfParent->hsName),
  383. &hnodeUnused))
  384. {
  385. /* Yes. */
  386. ASSERT(((PCOBJECTTWIN)GetNodeData(hnodeUnused))->ptfParent != ((POBJECTTWIN)pot)->ptfParent);
  387. bResult = TRUE;
  388. }
  389. else
  390. {
  391. POBJECTTWIN potNew;
  392. /*
  393. * No. Create a new object twin, and add it to the bookkeeping
  394. * list of new object twins.
  395. */
  396. bResult = CreateObjectTwinAndAddToList(
  397. ((POBJECTTWIN)pot)->ptfParent, hpathMatchingFolder,
  398. ((PCSPINOFFOBJECTTWININFO)pcsooti)->hlistNewObjectTwins,
  399. &potNew, &hnodeUnused);
  400. #ifdef DEBUG
  401. if (bResult)
  402. {
  403. TRACE_OUT((TEXT("GenerateSpinOffObjectTwin(): Generated spin-off object twin for object %s\\%s."),
  404. DebugGetPathString(potNew->hpath),
  405. GetString(potNew->ptfParent->hsName)));
  406. }
  407. #endif
  408. }
  409. }
  410. else
  411. bResult = TRUE;
  412. DeletePath(hpathMatchingFolder);
  413. }
  414. else
  415. bResult = FALSE;
  416. return(bResult);
  417. }
  418. /*
  419. ** BuildBradyBunch()
  420. **
  421. **
  422. **
  423. ** Arguments:
  424. **
  425. ** Returns:
  426. **
  427. ** Side Effects: none
  428. */
  429. PRIVATE_CODE BOOL BuildBradyBunch(PVOID pot, PVOID pcfp)
  430. {
  431. BOOL bResult;
  432. HPATH hpathMatchingFolder;
  433. HNODE hnodeOther;
  434. ASSERT(IS_VALID_STRUCT_PTR(pot, COBJECTTWIN));
  435. ASSERT(IS_VALID_STRUCT_PTR(pcfp, CFOLDERPAIR));
  436. /*
  437. * Append the generated object twin's subpath to the matching folder twin's
  438. * base path for subtree twins.
  439. */
  440. bResult = BuildPathForMatchingObjectTwin(
  441. pcfp, pot,
  442. GetBriefcasePathList(((POBJECTTWIN)pot)->ptfParent->hbr),
  443. &hpathMatchingFolder);
  444. if (bResult)
  445. {
  446. /*
  447. * Does this generated object twin's twin family already contain an object
  448. * twin generated by the other half of the pair of folder twins?
  449. */
  450. if (! SearchUnsortedList(((POBJECTTWIN)pot)->ptfParent->hlistObjectTwins,
  451. &ObjectTwinSearchCmp, hpathMatchingFolder,
  452. &hnodeOther))
  453. {
  454. /*
  455. * The other object twin should already exist in a different twin family.
  456. */
  457. if (EVAL(FindObjectTwin(((POBJECTTWIN)pot)->ptfParent->hbr,
  458. hpathMatchingFolder,
  459. GetString(((POBJECTTWIN)pot)->ptfParent->hsName),
  460. &hnodeOther)))
  461. {
  462. PCOBJECTTWIN pcotOther;
  463. pcotOther = (PCOBJECTTWIN)GetNodeData(hnodeOther);
  464. if (EVAL(pcotOther->ptfParent != ((POBJECTTWIN)pot)->ptfParent))
  465. {
  466. /* It does. Crush them. */
  467. CollapseTwinFamilies(((POBJECTTWIN)pot)->ptfParent,
  468. pcotOther->ptfParent);
  469. TRACE_OUT((TEXT("BuildBradyBunch(): Collapsed separate twin families for object %s\\%s and %s\\%s."),
  470. DebugGetPathString(((POBJECTTWIN)pot)->hpath),
  471. GetString(((POBJECTTWIN)pot)->ptfParent->hsName),
  472. DebugGetPathString(pcotOther->hpath),
  473. GetString(pcotOther->ptfParent->hsName)));
  474. }
  475. }
  476. }
  477. DeletePath(hpathMatchingFolder);
  478. }
  479. return(bResult);
  480. }
  481. /*
  482. ** CreateObjectTwinAndAddToList()
  483. **
  484. **
  485. **
  486. ** Arguments:
  487. **
  488. ** Returns:
  489. **
  490. ** Side Effects: none
  491. */
  492. PRIVATE_CODE BOOL CreateObjectTwinAndAddToList(PTWINFAMILY ptf, HPATH hpathFolder,
  493. HLIST hlistObjectTwins,
  494. POBJECTTWIN *ppot, PHNODE phnode)
  495. {
  496. BOOL bResult = FALSE;
  497. ASSERT(IS_VALID_STRUCT_PTR(ptf, CTWINFAMILY));
  498. ASSERT(IS_VALID_HANDLE(hpathFolder, PATH));
  499. ASSERT(IS_VALID_HANDLE(hlistObjectTwins, LIST));
  500. ASSERT(IS_VALID_WRITE_PTR(ppot, POBJECTTWIN));
  501. ASSERT(IS_VALID_WRITE_PTR(phnode, HNODE));
  502. if (CreateObjectTwin(ptf, hpathFolder, ppot))
  503. {
  504. if (InsertNodeAtFront(hlistObjectTwins, NULL, *ppot, phnode))
  505. bResult = TRUE;
  506. else
  507. DestroyStub(&((*ppot)->stub));
  508. }
  509. return(bResult);
  510. }
  511. /*
  512. ** CreateListOfGeneratedObjectTwins()
  513. **
  514. **
  515. **
  516. ** Arguments:
  517. **
  518. ** Returns:
  519. **
  520. ** Side Effects: none
  521. */
  522. PRIVATE_CODE BOOL CreateListOfGeneratedObjectTwins(PCFOLDERPAIR pcfp,
  523. PHLIST phlistGeneratedObjectTwins)
  524. {
  525. NEWLIST nl;
  526. BOOL bResult = FALSE;
  527. ASSERT(IS_VALID_STRUCT_PTR(pcfp, CFOLDERPAIR));
  528. ASSERT(IS_VALID_WRITE_PTR(phlistGeneratedObjectTwins, HLIST));
  529. nl.dwFlags = 0;
  530. if (CreateList(&nl, phlistGeneratedObjectTwins))
  531. {
  532. if (EnumGeneratedObjectTwins(pcfp, &InsertNodeAtFrontWalker, *phlistGeneratedObjectTwins))
  533. bResult = TRUE;
  534. else
  535. DestroyList(*phlistGeneratedObjectTwins);
  536. }
  537. return(bResult);
  538. }
  539. /*
  540. ** NotifyNewObjectTwins()
  541. **
  542. **
  543. **
  544. ** Arguments:
  545. **
  546. ** Returns:
  547. **
  548. ** Side Effects: none
  549. */
  550. PRIVATE_CODE void NotifyNewObjectTwins(HLIST hlistNewObjectTwins,
  551. HCLSIFACECACHE hcic)
  552. {
  553. BOOL bContinue;
  554. HNODE hnode;
  555. ASSERT(IS_VALID_HANDLE(hlistNewObjectTwins, LIST));
  556. ASSERT(IS_VALID_HANDLE(hcic, CLSIFACECACHE));
  557. for (bContinue = GetFirstNode(hlistNewObjectTwins, &hnode);
  558. bContinue;
  559. bContinue = GetNextNode(hnode, &hnode))
  560. {
  561. PCOBJECTTWIN pcot;
  562. TCHAR rgchPath[MAX_PATH_LEN];
  563. CLSID clsidReplicaNotification;
  564. pcot = (PCOBJECTTWIN)GetNodeData(hnode);
  565. rgchPath[0] = TEXT('\0');
  566. GetPathString(pcot->hpath, rgchPath, ARRAYSIZE(rgchPath));
  567. CatPath(rgchPath, GetString(pcot->ptfParent->hsName), ARRAYSIZE(rgchPath));
  568. ASSERT(lstrlen(rgchPath) < ARRAYSIZE(rgchPath));
  569. if (SUCCEEDED(GetReplicaNotificationClassID(rgchPath,
  570. &clsidReplicaNotification)))
  571. {
  572. PINotifyReplica pinr;
  573. if (SUCCEEDED(GetClassInterface(hcic, &clsidReplicaNotification,
  574. &IID_INotifyReplica, &pinr)))
  575. /* Ignore return value. */
  576. NotifyOneNewObjectTwin(pinr, pcot, rgchPath);
  577. else
  578. TRACE_OUT((TEXT("NotifyNewObjectTwins(): Failed to get INotifyReplica for replica %s."),
  579. rgchPath));
  580. }
  581. else
  582. TRACE_OUT((TEXT("NotifyNewObjectTwins(): Failed to get replica notification class ID for replica %s."),
  583. rgchPath));
  584. }
  585. return;
  586. }
  587. /*
  588. ** NotifyOneNewObjectTwin()
  589. **
  590. **
  591. **
  592. ** Arguments:
  593. **
  594. ** Returns:
  595. **
  596. ** Side Effects: none
  597. */
  598. PRIVATE_CODE HRESULT NotifyOneNewObjectTwin(PINotifyReplica pinr, PCOBJECTTWIN pcot,
  599. LPCTSTR pcszPath)
  600. {
  601. HRESULT hr;
  602. HSTGIFACE hstgi;
  603. ASSERT(IS_VALID_STRUCT_PTR(pinr, CINotifyReplica));
  604. ASSERT(IS_VALID_STRUCT_PTR(pcot, COBJECTTWIN));
  605. ASSERT(IS_VALID_STRING_PTR(pcszPath, CSTR));
  606. hr = GetStorageInterface((PIUnknown)pinr, &hstgi);
  607. if (SUCCEEDED(hr))
  608. {
  609. hr = LoadFromStorage(hstgi, pcszPath);
  610. if (SUCCEEDED(hr))
  611. {
  612. ULONG ulcOtherReplicas;
  613. PIMoniker *ppimkOtherReplicas;
  614. /*
  615. * RAIDRAID: (16270) (Performance) We may create a file moniker for
  616. * the same object twin multiple times here.
  617. */
  618. hr = CreateOtherReplicaMonikers(pcot, &ulcOtherReplicas,
  619. &ppimkOtherReplicas);
  620. if (SUCCEEDED(hr))
  621. {
  622. hr = pinr->lpVtbl->YouAreAReplica(pinr, ulcOtherReplicas,
  623. ppimkOtherReplicas);
  624. if (SUCCEEDED(hr))
  625. {
  626. hr = SaveToStorage(hstgi);
  627. if (SUCCEEDED(hr))
  628. TRACE_OUT((TEXT("NotifyOneNewObjectTwin(): Replica %s successfully notified."),
  629. pcszPath));
  630. else
  631. WARNING_OUT((TEXT("NotifyOneNewObjectTwin(): Failed to save replica %s to storage."),
  632. pcszPath));
  633. }
  634. else
  635. WARNING_OUT((TEXT("NotifyOneNewObjectTwin(): Failed to notify replica %s."),
  636. pcszPath));
  637. ReleaseIUnknowns(ulcOtherReplicas,
  638. (PIUnknown *)ppimkOtherReplicas);
  639. }
  640. else
  641. WARNING_OUT((TEXT("NotifyOneNewObjectTwin(): Failed to create monikers for other replicas of replica %s."),
  642. pcszPath));
  643. }
  644. else
  645. WARNING_OUT((TEXT("NotifyOneNewObjectTwin(): Failed to load replica %s from storage."),
  646. pcszPath));
  647. ReleaseStorageInterface(hstgi);
  648. }
  649. else
  650. WARNING_OUT((TEXT("NotifyOneNewObjectTwin(): Failed to get storage interface for replica %s."),
  651. pcszPath));
  652. return(hr);
  653. }
  654. /*
  655. ** CreateOtherReplicaMonikers()
  656. **
  657. **
  658. **
  659. ** Arguments:
  660. **
  661. ** Returns:
  662. **
  663. ** Side Effects: none
  664. */
  665. PRIVATE_CODE HRESULT CreateOtherReplicaMonikers(PCOBJECTTWIN pcotMaster,
  666. PULONG pulcOtherReplicas,
  667. PIMoniker **pppimk)
  668. {
  669. HRESULT hr;
  670. HLIST hlist;
  671. ULONG ulcOtherReplicas;
  672. ASSERT(IS_VALID_STRUCT_PTR(pcotMaster, COBJECTTWIN));
  673. ASSERT(IS_VALID_WRITE_PTR(pulcOtherReplicas, ULONG));
  674. ASSERT(IS_VALID_WRITE_PTR(pppimk, PIMoniker *));
  675. hlist = pcotMaster->ptfParent->hlistObjectTwins;
  676. ulcOtherReplicas = GetNodeCount(hlist);
  677. ASSERT(ulcOtherReplicas > 0);
  678. ulcOtherReplicas--;
  679. if (AllocateMemory(ulcOtherReplicas * sizeof(**pppimk), (PVOID *)pppimk))
  680. {
  681. BOOL bContinue;
  682. HNODE hnode;
  683. hr = S_OK;
  684. *pulcOtherReplicas = 0;
  685. for (bContinue = GetFirstNode(hlist, &hnode);
  686. bContinue;
  687. bContinue = GetNextNode(hnode, &hnode))
  688. {
  689. PCOBJECTTWIN pcot;
  690. pcot = (PCOBJECTTWIN)GetNodeData(hnode);
  691. if (pcot != pcotMaster)
  692. {
  693. TCHAR rgchPath[MAX_PATH_LEN];
  694. rgchPath[0] = TEXT('\0');
  695. GetPathString(pcot->hpath, rgchPath, ARRAYSIZE(rgchPath));
  696. hr = MyCreateFileMoniker(rgchPath,
  697. GetString(pcot->ptfParent->hsName),
  698. &((*pppimk)[*pulcOtherReplicas]));
  699. if (SUCCEEDED(hr))
  700. {
  701. ASSERT(*pulcOtherReplicas < ulcOtherReplicas);
  702. (*pulcOtherReplicas)++;
  703. }
  704. else
  705. break;
  706. }
  707. }
  708. if (FAILED(hr))
  709. ReleaseIUnknowns(*pulcOtherReplicas, *(PIUnknown **)pppimk);
  710. }
  711. else
  712. hr = E_OUTOFMEMORY;
  713. return(hr);
  714. }
  715. /*
  716. ** TwinFamilySortCmp()
  717. **
  718. ** Pointer comparison function used to sort the global array of twin families.
  719. **
  720. ** Arguments: pctf1 - pointer to TWINFAMILY describing first twin family
  721. ** pctf2 - pointer to TWINFAMILY describing second twin family
  722. **
  723. ** Returns:
  724. **
  725. ** Side Effects: none
  726. **
  727. ** Twin families are sorted by:
  728. ** 1) name string
  729. ** 2) pointer value
  730. */
  731. PRIVATE_CODE COMPARISONRESULT TwinFamilySortCmp(PCVOID pctf1, PCVOID pctf2)
  732. {
  733. COMPARISONRESULT cr;
  734. ASSERT(IS_VALID_STRUCT_PTR(pctf1, CTWINFAMILY));
  735. ASSERT(IS_VALID_STRUCT_PTR(pctf2, CTWINFAMILY));
  736. cr = CompareNameStringsByHandle(((PCTWINFAMILY)pctf1)->hsName, ((PCTWINFAMILY)pctf2)->hsName);
  737. if (cr == CR_EQUAL)
  738. /* Same name strings. Now sort by pointer value. */
  739. cr = ComparePointers(pctf1, pctf2);
  740. return(cr);
  741. }
  742. /*
  743. ** TwinFamilySearchCmp()
  744. **
  745. ** Pointer comparison function used to search the global array of twin families
  746. ** for the first twin family for a given name.
  747. **
  748. ** Arguments: pcszName - name string to search for
  749. ** pctf - pointer to TWINFAMILY to examine
  750. **
  751. ** Returns:
  752. **
  753. ** Side Effects: none
  754. **
  755. ** Twin families are searched by:
  756. ** 1) name string
  757. */
  758. PRIVATE_CODE COMPARISONRESULT TwinFamilySearchCmp(PCVOID pcszName, PCVOID pctf)
  759. {
  760. ASSERT(IS_VALID_STRING_PTR(pcszName, CSTR));
  761. ASSERT(IS_VALID_STRUCT_PTR(pctf, CTWINFAMILY));
  762. return(CompareNameStrings(pcszName, GetString(((PCTWINFAMILY)pctf)->hsName)));
  763. }
  764. /*
  765. ** ObjectTwinSearchCmp()
  766. **
  767. **
  768. **
  769. ** Arguments:
  770. **
  771. ** Returns:
  772. **
  773. ** Side Effects: none
  774. */
  775. PRIVATE_CODE BOOL ObjectTwinSearchCmp(PCVOID hpath, PCVOID pcot)
  776. {
  777. ASSERT(IS_VALID_HANDLE((HPATH)hpath, PATH));
  778. ASSERT(IS_VALID_STRUCT_PTR(pcot, COBJECTTWIN));
  779. return(ComparePaths((HPATH)hpath, ((PCOBJECTTWIN)pcot)->hpath));
  780. }
  781. /*
  782. ** WriteTwinFamily()
  783. **
  784. **
  785. **
  786. ** Arguments:
  787. **
  788. ** Returns: TWINRESULT
  789. **
  790. ** Side Effects: none
  791. */
  792. PRIVATE_CODE TWINRESULT WriteTwinFamily(HCACHEDFILE hcf, PCTWINFAMILY pctf)
  793. {
  794. TWINRESULT tr = TR_BRIEFCASE_WRITE_FAILED;
  795. DWORD dwcbTwinFamilyDBHeaderOffset;
  796. ASSERT(IS_VALID_HANDLE(hcf, CACHEDFILE));
  797. ASSERT(IS_VALID_STRUCT_PTR(pctf, CTWINFAMILY));
  798. /* Save initial file poisition. */
  799. dwcbTwinFamilyDBHeaderOffset = GetCachedFilePointerPosition(hcf);
  800. if (dwcbTwinFamilyDBHeaderOffset != INVALID_SEEK_POSITION)
  801. {
  802. TWINFAMILYDBHEADER tfdbh;
  803. /* Leave space for the twin family's header. */
  804. ZeroMemory(&tfdbh, sizeof(tfdbh));
  805. if (WriteToCachedFile(hcf, (PCVOID)&tfdbh, sizeof(tfdbh), NULL))
  806. {
  807. BOOL bContinue;
  808. HNODE hnode;
  809. LONG lcObjectTwins = 0;
  810. /* Save twin family's object twins. */
  811. ASSERT(GetNodeCount(pctf->hlistObjectTwins) >= 2);
  812. tr = TR_SUCCESS;
  813. for (bContinue = GetFirstNode(pctf->hlistObjectTwins, &hnode);
  814. bContinue;
  815. bContinue = GetNextNode(hnode, &hnode))
  816. {
  817. POBJECTTWIN pot;
  818. pot = (POBJECTTWIN)GetNodeData(hnode);
  819. tr = WriteObjectTwin(hcf, pot);
  820. if (tr == TR_SUCCESS)
  821. {
  822. ASSERT(lcObjectTwins < LONG_MAX);
  823. lcObjectTwins++;
  824. }
  825. else
  826. break;
  827. }
  828. /* Save twin family's database header. */
  829. if (tr == TR_SUCCESS)
  830. {
  831. ASSERT(lcObjectTwins >= 2);
  832. tfdbh.dwStubFlags = (pctf->stub.dwFlags & DB_STUB_FLAGS_MASK);
  833. tfdbh.hsName = pctf->hsName;
  834. tfdbh.lcObjectTwins = lcObjectTwins;
  835. tr = WriteDBSegmentHeader(hcf, dwcbTwinFamilyDBHeaderOffset, &tfdbh, sizeof(tfdbh));
  836. }
  837. }
  838. }
  839. return(tr);
  840. }
  841. /*
  842. ** WriteObjectTwin()
  843. **
  844. **
  845. **
  846. ** Arguments:
  847. **
  848. ** Returns: TWINRESULT
  849. **
  850. ** Side Effects: none
  851. */
  852. PRIVATE_CODE TWINRESULT WriteObjectTwin(HCACHEDFILE hcf, PCOBJECTTWIN pcot)
  853. {
  854. TWINRESULT tr;
  855. DBOBJECTTWIN dbot;
  856. ASSERT(IS_VALID_HANDLE(hcf, CACHEDFILE));
  857. ASSERT(IS_VALID_STRUCT_PTR(pcot, COBJECTTWIN));
  858. /* Set up object twin database structure. */
  859. dbot.dwStubFlags = (pcot->stub.dwFlags & DB_STUB_FLAGS_MASK);
  860. dbot.hpath = pcot->hpath;
  861. dbot.hpath = pcot->hpath;
  862. dbot.fsLastRec = pcot->fsLastRec;
  863. /* Save object twin database structure. */
  864. if (WriteToCachedFile(hcf, (PCVOID)&dbot, sizeof(dbot), NULL))
  865. tr = TR_SUCCESS;
  866. else
  867. tr = TR_BRIEFCASE_WRITE_FAILED;
  868. return(tr);
  869. }
  870. /*
  871. ** ReadTwinFamily()
  872. **
  873. **
  874. **
  875. ** Arguments:
  876. **
  877. ** Returns: TWINRESULT
  878. **
  879. ** Side Effects: none
  880. */
  881. PRIVATE_CODE TWINRESULT ReadTwinFamily(HCACHEDFILE hcf, HBRFCASE hbr,
  882. PCDBVERSION pcdbver,
  883. HHANDLETRANS hhtFolderTrans,
  884. HHANDLETRANS hhtNameTrans)
  885. {
  886. TWINRESULT tr = TR_CORRUPT_BRIEFCASE;
  887. TWINFAMILYDBHEADER tfdbh;
  888. DWORD dwcbRead;
  889. ASSERT(IS_VALID_HANDLE(hcf, CACHEDFILE));
  890. ASSERT(IS_VALID_HANDLE(hbr, BRFCASE));
  891. ASSERT(IS_VALID_READ_PTR(pcdbver, DBVERSION));
  892. ASSERT(IS_VALID_HANDLE(hhtFolderTrans, HANDLETRANS));
  893. ASSERT(IS_VALID_HANDLE(hhtNameTrans, HANDLETRANS));
  894. if (ReadFromCachedFile(hcf, &tfdbh, sizeof(tfdbh), &dwcbRead) &&
  895. dwcbRead == sizeof(tfdbh))
  896. {
  897. if (tfdbh.lcObjectTwins >= 2)
  898. {
  899. HSTRING hsName;
  900. if (TranslateHandle(hhtNameTrans, (HGENERIC)(tfdbh.hsName), (PHGENERIC)&hsName))
  901. {
  902. PTWINFAMILY ptfParent;
  903. if (CreateTwinFamily(hbr, GetString(hsName), &ptfParent))
  904. {
  905. LONG l;
  906. CopyTwinFamilyInfo(ptfParent, &tfdbh);
  907. tr = TR_SUCCESS;
  908. for (l = tfdbh.lcObjectTwins;
  909. l > 0 && tr == TR_SUCCESS;
  910. l--)
  911. tr = ReadObjectTwin(hcf, pcdbver, ptfParent, hhtFolderTrans);
  912. if (tr != TR_SUCCESS)
  913. DestroyStub(&(ptfParent->stub));
  914. }
  915. else
  916. tr = TR_OUT_OF_MEMORY;
  917. }
  918. }
  919. }
  920. return(tr);
  921. }
  922. /*
  923. ** ReadObjectTwin()
  924. **
  925. **
  926. **
  927. ** Arguments:
  928. **
  929. ** Returns:
  930. **
  931. ** Side Effects: none
  932. */
  933. PRIVATE_CODE TWINRESULT ReadObjectTwin(HCACHEDFILE hcf,
  934. PCDBVERSION pcdbver,
  935. PTWINFAMILY ptfParent,
  936. HHANDLETRANS hhtFolderTrans)
  937. {
  938. TWINRESULT tr;
  939. DBOBJECTTWIN dbot;
  940. DWORD dwcbRead;
  941. HPATH hpath;
  942. DWORD dwcbSize;
  943. COPYOBJECTTWINPROC pfnCopy;
  944. ASSERT(IS_VALID_HANDLE(hcf, CACHEDFILE));
  945. ASSERT(IS_VALID_READ_PTR(pcdbver, DBVERSION));
  946. ASSERT(IS_VALID_STRUCT_PTR(ptfParent, CTWINFAMILY));
  947. ASSERT(IS_VALID_HANDLE(hhtFolderTrans, HANDLETRANS));
  948. if (HEADER_M8_MINOR_VER == pcdbver->dwMinorVer)
  949. {
  950. /* The M8 database does not have the ftModLocal in the FILESTAMP
  951. ** structure.
  952. */
  953. dwcbSize = sizeof(dbot) - sizeof(FILETIME);
  954. pfnCopy = CopyM8ObjectTwinInfo;
  955. }
  956. else
  957. {
  958. ASSERT(HEADER_MINOR_VER == pcdbver->dwMinorVer);
  959. dwcbSize = sizeof(dbot);
  960. pfnCopy = CopyObjectTwinInfo;
  961. }
  962. if ((ReadFromCachedFile(hcf, &dbot, dwcbSize, &dwcbRead) &&
  963. dwcbRead == dwcbSize) &&
  964. TranslateHandle(hhtFolderTrans, (HGENERIC)(dbot.hpath), (PHGENERIC)&hpath))
  965. {
  966. POBJECTTWIN pot;
  967. /* Create the new object twin and add it to the twin family. */
  968. if (CreateObjectTwin(ptfParent, hpath, &pot))
  969. {
  970. pfnCopy(pot, &dbot);
  971. tr = TR_SUCCESS;
  972. }
  973. else
  974. tr = TR_OUT_OF_MEMORY;
  975. }
  976. else
  977. tr = TR_CORRUPT_BRIEFCASE;
  978. return(tr);
  979. }
  980. /*
  981. ** CopyTwinFamilyInfo()
  982. **
  983. **
  984. **
  985. ** Arguments:
  986. **
  987. ** Returns: TWINRESULT
  988. **
  989. ** Side Effects: none
  990. */
  991. PRIVATE_CODE void CopyTwinFamilyInfo(PTWINFAMILY ptf,
  992. PCTWINFAMILYDBHEADER pctfdbh)
  993. {
  994. ASSERT(IS_VALID_WRITE_PTR(ptf, TWINFAMILY));
  995. ASSERT(IS_VALID_READ_PTR(pctfdbh, CTWINFAMILYDBHEADER));
  996. ptf->stub.dwFlags = pctfdbh->dwStubFlags;
  997. return;
  998. }
  999. /*
  1000. ** CopyObjectTwinInfo()
  1001. **
  1002. **
  1003. **
  1004. ** Arguments:
  1005. **
  1006. ** Returns: TWINRESULT
  1007. **
  1008. ** Side Effects: none
  1009. */
  1010. PRIVATE_CODE void CopyObjectTwinInfo(POBJECTTWIN pot, PCDBOBJECTTWIN pcdbot)
  1011. {
  1012. ASSERT(IS_VALID_WRITE_PTR(pot, OBJECTTWIN));
  1013. ASSERT(IS_VALID_READ_PTR(pcdbot, CDBOBJECTTWIN));
  1014. pot->stub.dwFlags = pcdbot->dwStubFlags;
  1015. pot->fsLastRec = pcdbot->fsLastRec;
  1016. return;
  1017. }
  1018. /*
  1019. ** CopyM8ObjectTwinInfo()
  1020. **
  1021. **
  1022. **
  1023. ** Arguments:
  1024. **
  1025. ** Returns: TWINRESULT
  1026. **
  1027. ** Side Effects: none
  1028. */
  1029. PRIVATE_CODE void CopyM8ObjectTwinInfo(POBJECTTWIN pot, PCDBOBJECTTWIN pcdbot)
  1030. {
  1031. ASSERT(IS_VALID_WRITE_PTR(pot, OBJECTTWIN));
  1032. ASSERT(IS_VALID_READ_PTR(pcdbot, CDBOBJECTTWIN));
  1033. pot->stub.dwFlags = pcdbot->dwStubFlags;
  1034. pot->fsLastRec = pcdbot->fsLastRec;
  1035. /* The pot->fsLastRec.ftModLocal field is invalid, so fill it in */
  1036. if ( !FileTimeToLocalFileTime(&pot->fsLastRec.ftMod, &pot->fsLastRec.ftModLocal) )
  1037. {
  1038. /* Just copy the time if FileTimeToLocalFileTime failed */
  1039. pot->fsLastRec.ftModLocal = pot->fsLastRec.ftMod;
  1040. }
  1041. return;
  1042. }
  1043. #pragma warning(disable:4100) /* "unreferenced formal parameter" warning */
  1044. /*
  1045. ** DestroyObjectTwinStubWalker()
  1046. **
  1047. **
  1048. **
  1049. ** Arguments:
  1050. **
  1051. ** Returns:
  1052. **
  1053. ** Side Effects: none
  1054. */
  1055. PRIVATE_CODE BOOL DestroyObjectTwinStubWalker(PVOID pot, PVOID pvUnused)
  1056. {
  1057. ASSERT(IS_VALID_STRUCT_PTR(pot, COBJECTTWIN));
  1058. ASSERT(! pvUnused);
  1059. /*
  1060. * Set ulcSrcFolderTwins to 0 so UnlinkObjectTwin() succeeds.
  1061. * DestroyStub() will unlink and destroy any new twin family created.
  1062. */
  1063. ((POBJECTTWIN)pot)->ulcSrcFolderTwins = 0;
  1064. DestroyStub(&(((POBJECTTWIN)pot)->stub));
  1065. return(TRUE);
  1066. }
  1067. /*
  1068. ** MarkObjectTwinNeverReconciledWalker()
  1069. **
  1070. **
  1071. **
  1072. ** Arguments:
  1073. **
  1074. ** Returns:
  1075. **
  1076. ** Side Effects: none
  1077. */
  1078. PRIVATE_CODE BOOL MarkObjectTwinNeverReconciledWalker(PVOID pot, PVOID pvUnused)
  1079. {
  1080. ASSERT(IS_VALID_STRUCT_PTR(pot, COBJECTTWIN));
  1081. ASSERT(! pvUnused);
  1082. MarkObjectTwinNeverReconciled(pot);
  1083. return(TRUE);
  1084. }
  1085. /*
  1086. ** LookForSrcFolderTwinsWalker()
  1087. **
  1088. **
  1089. **
  1090. ** Arguments:
  1091. **
  1092. ** Returns:
  1093. **
  1094. ** Side Effects: none
  1095. */
  1096. PRIVATE_CODE BOOL LookForSrcFolderTwinsWalker(PVOID pot, PVOID pvUnused)
  1097. {
  1098. ASSERT(IS_VALID_STRUCT_PTR(pot, COBJECTTWIN));
  1099. ASSERT(! pvUnused);
  1100. return(! ((POBJECTTWIN)pot)->ulcSrcFolderTwins);
  1101. }
  1102. /*
  1103. ** IncrementSrcFolderTwinsWalker()
  1104. **
  1105. **
  1106. **
  1107. ** Arguments:
  1108. **
  1109. ** Returns:
  1110. **
  1111. ** Side Effects: none
  1112. */
  1113. PRIVATE_CODE BOOL IncrementSrcFolderTwinsWalker(PVOID pot, PVOID pvUnused)
  1114. {
  1115. ASSERT(IS_VALID_STRUCT_PTR(pot, COBJECTTWIN));
  1116. ASSERT(! pvUnused);
  1117. ASSERT(((POBJECTTWIN)pot)->ulcSrcFolderTwins < ULONG_MAX);
  1118. ((POBJECTTWIN)pot)->ulcSrcFolderTwins++;
  1119. return(TRUE);
  1120. }
  1121. /*
  1122. ** ClearSrcFolderTwinsWalker()
  1123. **
  1124. **
  1125. **
  1126. ** Arguments:
  1127. **
  1128. ** Returns:
  1129. **
  1130. ** Side Effects: none
  1131. */
  1132. PRIVATE_CODE BOOL ClearSrcFolderTwinsWalker(PVOID pot, PVOID pvUnused)
  1133. {
  1134. ASSERT(IS_VALID_STRUCT_PTR(pot, COBJECTTWIN));
  1135. ASSERT(! pvUnused);
  1136. ((POBJECTTWIN)pot)->ulcSrcFolderTwins = 0;
  1137. return(TRUE);
  1138. }
  1139. #pragma warning(default:4100) /* "unreferenced formal parameter" warning */
  1140. /*
  1141. ** SetTwinFamilyWalker()
  1142. **
  1143. **
  1144. **
  1145. ** Arguments:
  1146. **
  1147. ** Returns:
  1148. **
  1149. ** Side Effects: none
  1150. */
  1151. PRIVATE_CODE BOOL SetTwinFamilyWalker(PVOID pot, PVOID ptfParent)
  1152. {
  1153. ASSERT(IS_VALID_STRUCT_PTR(pot, COBJECTTWIN));
  1154. ASSERT(IS_VALID_STRUCT_PTR(ptfParent, CTWINFAMILY));
  1155. ((POBJECTTWIN)pot)->ptfParent = ptfParent;
  1156. return(TRUE);
  1157. }
  1158. /*
  1159. ** InsertNodeAtFrontWalker()
  1160. **
  1161. **
  1162. **
  1163. ** Arguments:
  1164. **
  1165. ** Returns:
  1166. **
  1167. ** Side Effects: none
  1168. */
  1169. PRIVATE_CODE BOOL InsertNodeAtFrontWalker(POBJECTTWIN pot, PVOID hlist)
  1170. {
  1171. HNODE hnodeUnused;
  1172. ASSERT(IS_VALID_STRUCT_PTR(pot, COBJECTTWIN));
  1173. ASSERT(IS_VALID_HANDLE(hlist, LIST));
  1174. return(InsertNodeAtFront(hlist, NULL, pot, &hnodeUnused));
  1175. }
  1176. #ifdef VSTF
  1177. /*
  1178. ** IsValidObjectTwinWalker()
  1179. **
  1180. **
  1181. **
  1182. ** Arguments:
  1183. **
  1184. ** Returns:
  1185. **
  1186. ** Side Effects: none
  1187. */
  1188. PRIVATE_CODE BOOL IsValidObjectTwinWalker(PVOID pcot, PVOID pctfParent)
  1189. {
  1190. return(IS_VALID_STRUCT_PTR(pcot, COBJECTTWIN) &&
  1191. EVAL(((PCOBJECTTWIN)pcot)->ptfParent == pctfParent) &&
  1192. EVAL(IsStubFlagClear(&(((PCOBJECTTWIN)pcot)->stub), STUB_FL_KEEP) ||
  1193. IsStubFlagSet(&(((PCTWINFAMILY)pctfParent)->stub),
  1194. STUB_FL_DELETION_PENDING)));
  1195. }
  1196. /*
  1197. ** IsValidPCNEWOBJECTTWIN()
  1198. **
  1199. **
  1200. **
  1201. ** Arguments:
  1202. **
  1203. ** Returns:
  1204. **
  1205. ** Side Effects: none
  1206. */
  1207. PRIVATE_CODE BOOL IsValidPCNEWOBJECTTWIN(PCNEWOBJECTTWIN pcnot)
  1208. {
  1209. return(IS_VALID_READ_PTR(pcnot, CNEWOBJECTTWIN) &&
  1210. EVAL(pcnot->ulSize == sizeof(*pcnot)) &&
  1211. IS_VALID_STRING_PTR(pcnot->pcszFolder1, CSTR) &&
  1212. IS_VALID_STRING_PTR(pcnot->pcszFolder2, CSTR) &&
  1213. IS_VALID_STRING_PTR(pcnot->pcszName, CSTR));
  1214. }
  1215. /*
  1216. ** IsValidPCSPINOFFOBJECTTWININFO()
  1217. **
  1218. **
  1219. **
  1220. ** Arguments:
  1221. **
  1222. ** Returns:
  1223. **
  1224. ** Side Effects: none
  1225. */
  1226. PRIVATE_CODE BOOL IsValidPCSPINOFFOBJECTTWININFO(PCSPINOFFOBJECTTWININFO pcsooti)
  1227. {
  1228. return(IS_VALID_READ_PTR(pcsooti, CSPINOFFOBJECTTWININFO) &&
  1229. IS_VALID_STRUCT_PTR(pcsooti->pcfp, CFOLDERPAIR) &&
  1230. IS_VALID_HANDLE(pcsooti->hlistNewObjectTwins, LIST));
  1231. }
  1232. #endif
  1233. #ifdef DEBUG
  1234. /*
  1235. ** AreTwinFamiliesValid()
  1236. **
  1237. **
  1238. **
  1239. ** Arguments:
  1240. **
  1241. ** Returns:
  1242. **
  1243. ** Side Effects: none
  1244. */
  1245. PRIVATE_CODE BOOL AreTwinFamiliesValid(HPTRARRAY hpaTwinFamilies)
  1246. {
  1247. ARRAYINDEX aicPtrs;
  1248. ARRAYINDEX ai;
  1249. ASSERT(IS_VALID_HANDLE(hpaTwinFamilies, PTRARRAY));
  1250. aicPtrs = GetPtrCount(hpaTwinFamilies);
  1251. for (ai = 0; ai < aicPtrs; ai++)
  1252. {
  1253. PCTWINFAMILY pctf;
  1254. pctf = GetPtr(hpaTwinFamilies, ai);
  1255. if (! IS_VALID_STRUCT_PTR(pctf, CTWINFAMILY) ||
  1256. ! EVAL(GetNodeCount(pctf->hlistObjectTwins) >= 2))
  1257. break;
  1258. }
  1259. return(ai == aicPtrs);
  1260. }
  1261. #endif
  1262. /****************************** Public Functions *****************************/
  1263. /*
  1264. ** CompareNameStrings()
  1265. **
  1266. **
  1267. **
  1268. ** Arguments:
  1269. **
  1270. ** Returns:
  1271. **
  1272. ** Side Effects: none
  1273. */
  1274. PUBLIC_CODE COMPARISONRESULT CompareNameStrings(LPCTSTR pcszFirst, LPCTSTR pcszSecond)
  1275. {
  1276. ASSERT(IS_VALID_STRING_PTR(pcszFirst, CSTR));
  1277. ASSERT(IS_VALID_STRING_PTR(pcszSecond, CSTR));
  1278. return(MapIntToComparisonResult(lstrcmpi(pcszFirst, pcszSecond)));
  1279. }
  1280. /*
  1281. ** CompareNameStringsByHandle()
  1282. **
  1283. **
  1284. **
  1285. ** Arguments:
  1286. **
  1287. ** Returns:
  1288. **
  1289. ** Side Effects: none
  1290. */
  1291. PUBLIC_CODE COMPARISONRESULT CompareNameStringsByHandle(HSTRING hsFirst,
  1292. HSTRING hsSecond)
  1293. {
  1294. ASSERT(IS_VALID_HANDLE(hsFirst, STRING));
  1295. ASSERT(IS_VALID_HANDLE(hsSecond, STRING));
  1296. return(CompareStringsI(hsFirst, hsSecond));
  1297. }
  1298. /*
  1299. ** TranslatePATHRESULTToTWINRESULT()
  1300. **
  1301. **
  1302. **
  1303. ** Arguments:
  1304. **
  1305. ** Returns:
  1306. **
  1307. ** Side Effects: none
  1308. */
  1309. PUBLIC_CODE TWINRESULT TranslatePATHRESULTToTWINRESULT(PATHRESULT pr)
  1310. {
  1311. TWINRESULT tr;
  1312. switch (pr)
  1313. {
  1314. case PR_SUCCESS:
  1315. tr = TR_SUCCESS;
  1316. break;
  1317. case PR_UNAVAILABLE_VOLUME:
  1318. tr = TR_UNAVAILABLE_VOLUME;
  1319. break;
  1320. case PR_OUT_OF_MEMORY:
  1321. tr = TR_OUT_OF_MEMORY;
  1322. break;
  1323. default:
  1324. ASSERT(pr == PR_INVALID_PATH);
  1325. tr = TR_INVALID_PARAMETER;
  1326. break;
  1327. }
  1328. return(tr);
  1329. }
  1330. /*
  1331. ** CreateTwinFamilyPtrArray()
  1332. **
  1333. **
  1334. **
  1335. ** Arguments:
  1336. **
  1337. ** Returns:
  1338. **
  1339. ** Side Effects: none
  1340. */
  1341. PUBLIC_CODE BOOL CreateTwinFamilyPtrArray(PHPTRARRAY phpa)
  1342. {
  1343. NEWPTRARRAY npa;
  1344. ASSERT(IS_VALID_WRITE_PTR(phpa, HPTRARRAY));
  1345. /* Try to create a twin family pointer array. */
  1346. npa.aicInitialPtrs = NUM_START_TWIN_FAMILY_PTRS;
  1347. npa.aicAllocGranularity = NUM_TWIN_FAMILY_PTRS_TO_ADD;
  1348. npa.dwFlags = NPA_FL_SORTED_ADD;
  1349. return(CreatePtrArray(&npa, phpa));
  1350. }
  1351. /*
  1352. ** DestroyTwinFamilyPtrArray()
  1353. **
  1354. **
  1355. **
  1356. ** Arguments:
  1357. **
  1358. ** Returns:
  1359. **
  1360. ** Side Effects: none
  1361. */
  1362. PUBLIC_CODE void DestroyTwinFamilyPtrArray(HPTRARRAY hpa)
  1363. {
  1364. ARRAYINDEX aicPtrs;
  1365. ARRAYINDEX ai;
  1366. ASSERT(IS_VALID_HANDLE(hpa, PTRARRAY));
  1367. /* First free all twin families in pointer array. */
  1368. aicPtrs = GetPtrCount(hpa);
  1369. for (ai = 0; ai < aicPtrs; ai++)
  1370. DestroyTwinFamily(GetPtr(hpa, ai));
  1371. /* Now wipe out the pointer array. */
  1372. DestroyPtrArray(hpa);
  1373. return;
  1374. }
  1375. /*
  1376. ** GetTwinBriefcase()
  1377. **
  1378. **
  1379. **
  1380. ** Arguments:
  1381. **
  1382. ** Returns:
  1383. **
  1384. ** Side Effects: none
  1385. */
  1386. PUBLIC_CODE HBRFCASE GetTwinBriefcase(HTWIN htwin)
  1387. {
  1388. HBRFCASE hbr;
  1389. ASSERT(IS_VALID_HANDLE(htwin, TWIN));
  1390. switch (((PSTUB)htwin)->st)
  1391. {
  1392. case ST_OBJECTTWIN:
  1393. hbr = ((PCOBJECTTWIN)htwin)->ptfParent->hbr;
  1394. break;
  1395. case ST_TWINFAMILY:
  1396. hbr = ((PCTWINFAMILY)htwin)->hbr;
  1397. break;
  1398. case ST_FOLDERPAIR:
  1399. hbr = ((PCFOLDERPAIR)htwin)->pfpd->hbr;
  1400. break;
  1401. default:
  1402. ERROR_OUT((TEXT("GetTwinBriefcase() called on unrecognized stub type %d."),
  1403. ((PSTUB)htwin)->st));
  1404. hbr = NULL;
  1405. break;
  1406. }
  1407. return(hbr);
  1408. }
  1409. /*
  1410. ** FindObjectTwinInList()
  1411. **
  1412. **
  1413. **
  1414. ** Arguments:
  1415. **
  1416. ** Returns:
  1417. **
  1418. ** Side Effects: none
  1419. */
  1420. PUBLIC_CODE BOOL FindObjectTwinInList(HLIST hlist, HPATH hpath, PHNODE phnode)
  1421. {
  1422. ASSERT(IS_VALID_HANDLE(hlist, LIST));
  1423. ASSERT(IS_VALID_HANDLE(hpath, PATH));
  1424. ASSERT(IS_VALID_WRITE_PTR(phnode, HNODE));
  1425. return(SearchUnsortedList(hlist, &ObjectTwinSearchCmp, hpath, phnode));
  1426. }
  1427. /*
  1428. ** EnumTwins()
  1429. **
  1430. ** Enumerates folder twins and twin families in a briefcase.
  1431. **
  1432. ** Arguments:
  1433. **
  1434. ** Returns: TRUE if halted. FALSE if not.
  1435. **
  1436. ** Side Effects: none
  1437. */
  1438. PUBLIC_CODE BOOL EnumTwins(HBRFCASE hbr, ENUMTWINSPROC etp, LPARAM lpData,
  1439. PHTWIN phtwinStop)
  1440. {
  1441. HPTRARRAY hpa;
  1442. ARRAYINDEX aicPtrs;
  1443. ARRAYINDEX ai;
  1444. ASSERT(IS_VALID_HANDLE(hbr, BRFCASE));
  1445. ASSERT(IS_VALID_CODE_PTR(etp, ENUMTWINSPROC));
  1446. ASSERT(IS_VALID_WRITE_PTR(phtwinStop, HTWIN));
  1447. /* Enumerate folder pairs. */
  1448. *phtwinStop = NULL;
  1449. hpa = GetBriefcaseFolderPairPtrArray(hbr);
  1450. aicPtrs = GetPtrCount(hpa);
  1451. for (ai = 0; ai < aicPtrs; ai++)
  1452. {
  1453. PCFOLDERPAIR pcfp;
  1454. pcfp = GetPtr(hpa, ai);
  1455. ASSERT(IS_VALID_STRUCT_PTR(pcfp, CFOLDERPAIR));
  1456. if (! (*etp)((HTWIN)pcfp, lpData))
  1457. {
  1458. *phtwinStop = (HTWIN)pcfp;
  1459. break;
  1460. }
  1461. }
  1462. if (! *phtwinStop)
  1463. {
  1464. /* Enumerate twin families. */
  1465. hpa = GetBriefcaseTwinFamilyPtrArray(hbr);
  1466. aicPtrs = GetPtrCount(hpa);
  1467. for (ai = 0; ai < aicPtrs; ai++)
  1468. {
  1469. PCTWINFAMILY pctf;
  1470. pctf = GetPtr(hpa, ai);
  1471. ASSERT(IS_VALID_STRUCT_PTR(pctf, CTWINFAMILY));
  1472. if (! (*etp)((HTWIN)pctf, lpData))
  1473. {
  1474. *phtwinStop = (HTWIN)pctf;
  1475. break;
  1476. }
  1477. }
  1478. }
  1479. return(*phtwinStop != NULL);
  1480. }
  1481. /*
  1482. ** FindObjectTwin()
  1483. **
  1484. ** Looks for a twin family containing a specified object twin.
  1485. **
  1486. ** Arguments: hpathFolder - folder containing object
  1487. ** pcszName - name of object
  1488. **
  1489. ** Returns: Handle to list node containing pointer to object twin if
  1490. ** found, or NULL if not found.
  1491. **
  1492. ** Side Effects: none
  1493. */
  1494. PUBLIC_CODE BOOL FindObjectTwin(HBRFCASE hbr, HPATH hpathFolder,
  1495. LPCTSTR pcszName, PHNODE phnode)
  1496. {
  1497. BOOL bFound = FALSE;
  1498. HPTRARRAY hpaTwinFamilies;
  1499. ARRAYINDEX aiFirst;
  1500. ASSERT(IS_VALID_HANDLE(hbr, BRFCASE));
  1501. ASSERT(IS_VALID_HANDLE(hpathFolder, PATH));
  1502. ASSERT(IS_VALID_STRING_PTR(pcszName, CSTR));
  1503. ASSERT(IS_VALID_WRITE_PTR(phnode, HNODE));
  1504. /* Search for a matching twin family. */
  1505. *phnode = NULL;
  1506. hpaTwinFamilies = GetBriefcaseTwinFamilyPtrArray(hbr);
  1507. if (SearchSortedArray(hpaTwinFamilies, &TwinFamilySearchCmp, pcszName,
  1508. &aiFirst))
  1509. {
  1510. ARRAYINDEX aicPtrs;
  1511. ARRAYINDEX ai;
  1512. PTWINFAMILY ptf;
  1513. /*
  1514. * aiFirst holds the index of the first twin family with a common object
  1515. * name matching pcszName.
  1516. */
  1517. /*
  1518. * Now search each of these twin families for a folder matching
  1519. * pcszFolder.
  1520. */
  1521. aicPtrs = GetPtrCount(hpaTwinFamilies);
  1522. ASSERT(aicPtrs > 0);
  1523. ASSERT(aiFirst >= 0);
  1524. ASSERT(aiFirst < aicPtrs);
  1525. for (ai = aiFirst; ai < aicPtrs; ai++)
  1526. {
  1527. ptf = GetPtr(hpaTwinFamilies, ai);
  1528. ASSERT(IS_VALID_STRUCT_PTR(ptf, CTWINFAMILY));
  1529. /* Is this a twin family of objects of the given name? */
  1530. if (CompareNameStrings(GetString(ptf->hsName), pcszName) == CR_EQUAL)
  1531. {
  1532. bFound = SearchUnsortedList(ptf->hlistObjectTwins,
  1533. &ObjectTwinSearchCmp, hpathFolder,
  1534. phnode);
  1535. if (bFound)
  1536. break;
  1537. }
  1538. else
  1539. /* No. Stop searching. */
  1540. break;
  1541. }
  1542. }
  1543. return(bFound);
  1544. }
  1545. /*
  1546. ** TwinObjects()
  1547. **
  1548. ** Twins two objects.
  1549. **
  1550. ** Arguments:
  1551. **
  1552. ** Returns: TWINRESULT
  1553. **
  1554. ** Side Effects: none
  1555. **
  1556. ** N.b., *ppot1 and *ppot2 are valid if TR_SUCCESS or TR_DUPLICATE_TWIN is
  1557. ** returned.
  1558. */
  1559. PUBLIC_CODE TWINRESULT TwinObjects(HBRFCASE hbr, HCLSIFACECACHE hcic,
  1560. HPATH hpathFolder1, HPATH hpathFolder2,
  1561. LPCTSTR pcszName, POBJECTTWIN *ppot1,
  1562. POBJECTTWIN *ppot2)
  1563. {
  1564. TWINRESULT tr;
  1565. ASSERT(IS_VALID_HANDLE(hbr, BRFCASE));
  1566. ASSERT(IS_VALID_HANDLE(hcic, CLSIFACECACHE));
  1567. ASSERT(IS_VALID_HANDLE(hpathFolder1, PATH));
  1568. ASSERT(IS_VALID_HANDLE(hpathFolder2, PATH));
  1569. ASSERT(IS_VALID_STRING_PTR(pcszName, CSTR));
  1570. ASSERT(IS_VALID_WRITE_PTR(ppot1, POBJECTTWIN));
  1571. ASSERT(IS_VALID_WRITE_PTR(ppot2, POBJECTTWIN));
  1572. /* Fail twinning a file to itself. */
  1573. if (ComparePaths(hpathFolder1, hpathFolder2) != CR_EQUAL)
  1574. {
  1575. NEWLIST nl;
  1576. HLIST hlistNewObjectTwins;
  1577. nl.dwFlags = 0;
  1578. if (CreateList(&nl, &hlistNewObjectTwins))
  1579. {
  1580. /* Twin 'em. */
  1581. tr = TwinJustTheseTwoObjects(hbr, hpathFolder1, hpathFolder2,
  1582. pcszName, ppot1, ppot2,
  1583. hlistNewObjectTwins);
  1584. /*
  1585. * Add any new object twins to the lists of generated object twins for
  1586. * all intersecting folder twins. Create new spin-off object twins
  1587. * from the other folder twin connected to each intersecting folder
  1588. * twin. Spin-off object twins are added to the twin family as they
  1589. * are created.
  1590. */
  1591. if (tr == TR_SUCCESS)
  1592. {
  1593. if (ApplyNewObjectTwinsToFolderTwins(hlistNewObjectTwins))
  1594. {
  1595. /*
  1596. * Notify new object twins that they are object twins. Don't
  1597. * notify folder object twins.
  1598. */
  1599. if (*pcszName)
  1600. NotifyNewObjectTwins(hlistNewObjectTwins, hcic);
  1601. }
  1602. else
  1603. tr = TR_OUT_OF_MEMORY;
  1604. }
  1605. if (tr != TR_SUCCESS)
  1606. /*
  1607. * We must maintain a consistent internal state by deleting any new
  1608. * twin family and object twins on failure, independent of source
  1609. * folder twin count.
  1610. */
  1611. EVAL(WalkList(hlistNewObjectTwins, &DestroyObjectTwinStubWalker,
  1612. NULL));
  1613. DestroyList(hlistNewObjectTwins);
  1614. }
  1615. else
  1616. tr = TR_OUT_OF_MEMORY;
  1617. }
  1618. else
  1619. tr = TR_SAME_FOLDER;
  1620. ASSERT((tr != TR_SUCCESS && tr != TR_DUPLICATE_TWIN) ||
  1621. IS_VALID_STRUCT_PTR(*ppot1, COBJECTTWIN) && IS_VALID_STRUCT_PTR(*ppot2, COBJECTTWIN));
  1622. return(tr);
  1623. }
  1624. /*
  1625. ** CreateObjectTwin()
  1626. **
  1627. ** Creates a new object twin, and adds it to a twin family.
  1628. **
  1629. ** Arguments: ptf - pointer to parent twin family
  1630. ** hpathFolder - folder of new object twin
  1631. **
  1632. ** Returns: Pointer to new object twin if successful, or NULL if
  1633. ** unsuccessful.
  1634. **
  1635. ** Side Effects: none
  1636. **
  1637. ** N.b., this function does not first check to see if the object twin already
  1638. ** exists in the family.
  1639. */
  1640. PUBLIC_CODE BOOL CreateObjectTwin(PTWINFAMILY ptf, HPATH hpathFolder,
  1641. POBJECTTWIN *ppot)
  1642. {
  1643. BOOL bResult = FALSE;
  1644. POBJECTTWIN potNew;
  1645. ASSERT(IS_VALID_STRUCT_PTR(ptf, CTWINFAMILY));
  1646. ASSERT(IS_VALID_HANDLE(hpathFolder, PATH));
  1647. ASSERT(IS_VALID_WRITE_PTR(ppot, POBJECTTWIN));
  1648. #ifdef DEBUG
  1649. {
  1650. HNODE hnodeUnused;
  1651. /* Is this object twin already in a twin family? */
  1652. if (FindObjectTwin(ptf->hbr, hpathFolder, GetString(ptf->hsName), &hnodeUnused))
  1653. ERROR_OUT((TEXT("CreateObjectTwin(): An object twin for %s\\%s already exists."),
  1654. DebugGetPathString(hpathFolder),
  1655. GetString(ptf->hsName)));
  1656. }
  1657. #endif
  1658. /* Create a new OBJECTTWIN structure. */
  1659. if (AllocateMemory(sizeof(*potNew), &potNew))
  1660. {
  1661. if (CopyPath(hpathFolder, GetBriefcasePathList(ptf->hbr), &(potNew->hpath)))
  1662. {
  1663. HNODE hnodeUnused;
  1664. /* Fill in new OBJECTTWIN fields. */
  1665. InitStub(&(potNew->stub), ST_OBJECTTWIN);
  1666. potNew->ptfParent = ptf;
  1667. potNew->ulcSrcFolderTwins = 0;
  1668. MarkObjectTwinNeverReconciled(potNew);
  1669. /* Add the object twin to the twin family's list of object twins. */
  1670. if (InsertNodeAtFront(ptf->hlistObjectTwins, NULL, potNew, &hnodeUnused))
  1671. {
  1672. *ppot = potNew;
  1673. bResult = TRUE;
  1674. ASSERT(IS_VALID_STRUCT_PTR(*ppot, COBJECTTWIN));
  1675. }
  1676. else
  1677. {
  1678. DeletePath(potNew->hpath);
  1679. CREATEOBJECTTWIN_BAIL:
  1680. FreeMemory(potNew);
  1681. }
  1682. }
  1683. else
  1684. goto CREATEOBJECTTWIN_BAIL;
  1685. }
  1686. return(bResult);
  1687. }
  1688. /*
  1689. ** UnlinkObjectTwin()
  1690. **
  1691. ** Unlinks an object twin.
  1692. **
  1693. ** Arguments: pot - pointer to object twin to unlink
  1694. **
  1695. ** Returns: TWINRESULT
  1696. **
  1697. ** Side Effects: none
  1698. */
  1699. PUBLIC_CODE TWINRESULT UnlinkObjectTwin(POBJECTTWIN pot)
  1700. {
  1701. TWINRESULT tr;
  1702. ASSERT(IS_VALID_STRUCT_PTR(pot, COBJECTTWIN));
  1703. ASSERT(IsStubFlagClear(&(pot->stub), STUB_FL_UNLINKED));
  1704. TRACE_OUT((TEXT("UnlinkObjectTwin(): Unlinking object twin for folder %s."),
  1705. DebugGetPathString(pot->hpath)));
  1706. /* Is the object twin's twin family being deleted? */
  1707. if (IsStubFlagSet(&(pot->ptfParent->stub), STUB_FL_BEING_DELETED))
  1708. /* Yes. No need to unlink the object twin. */
  1709. tr = TR_SUCCESS;
  1710. else
  1711. {
  1712. /* Are there any folder twin sources left for this object twin? */
  1713. if (! pot->ulcSrcFolderTwins)
  1714. {
  1715. HNODE hnode;
  1716. /*
  1717. * Search the object twin's parent's list of object twins for the
  1718. * object twin to be unlinked.
  1719. */
  1720. if (EVAL(FindObjectTwinInList(pot->ptfParent->hlistObjectTwins, pot->hpath, &hnode)) &&
  1721. EVAL(GetNodeData(hnode) == pot))
  1722. {
  1723. ULONG ulcRemainingObjectTwins;
  1724. /* Unlink the object twin. */
  1725. DeleteNode(hnode);
  1726. SetStubFlag(&(pot->stub), STUB_FL_UNLINKED);
  1727. /*
  1728. * If we have just unlinked the second last object twin in a twin
  1729. * family, destroy the twin family.
  1730. */
  1731. ulcRemainingObjectTwins = GetNodeCount(pot->ptfParent->hlistObjectTwins);
  1732. if (ulcRemainingObjectTwins < 2)
  1733. {
  1734. #ifdef DEBUG
  1735. TCHAR rgchName[MAX_NAME_LEN];
  1736. lstrcpyn(rgchName, GetString(pot->ptfParent->hsName), ARRAYSIZE(rgchName));
  1737. #endif
  1738. /* It's the end of the family line. */
  1739. tr = DestroyStub(&(pot->ptfParent->stub));
  1740. #ifdef DEBUG
  1741. if (tr == TR_SUCCESS)
  1742. TRACE_OUT((TEXT("UnlinkObjectTwin(): Implicitly destroyed twin family for object %s."),
  1743. rgchName));
  1744. #endif
  1745. if (ulcRemainingObjectTwins == 1 &&
  1746. tr == TR_HAS_FOLDER_TWIN_SRC)
  1747. tr = TR_SUCCESS;
  1748. }
  1749. else
  1750. tr = TR_SUCCESS;
  1751. }
  1752. else
  1753. tr = TR_INVALID_PARAMETER;
  1754. ASSERT(tr == TR_SUCCESS);
  1755. }
  1756. else
  1757. tr = TR_HAS_FOLDER_TWIN_SRC;
  1758. }
  1759. return(tr);
  1760. }
  1761. /*
  1762. ** DestroyObjectTwin()
  1763. **
  1764. ** Destroys an object twin.
  1765. **
  1766. ** Arguments: pot - pointer to object twin to destroy
  1767. **
  1768. ** Returns: void
  1769. **
  1770. ** Side Effects: none
  1771. */
  1772. PUBLIC_CODE void DestroyObjectTwin(POBJECTTWIN pot)
  1773. {
  1774. ASSERT(IS_VALID_STRUCT_PTR(pot, COBJECTTWIN));
  1775. TRACE_OUT((TEXT("DestroyObjectTwin(): Destroying object twin for folder %s."),
  1776. DebugGetPathString(pot->hpath)));
  1777. DeletePath(pot->hpath);
  1778. FreeMemory(pot);
  1779. return;
  1780. }
  1781. /*
  1782. ** UnlinkTwinFamily()
  1783. **
  1784. ** Unlinks a twin family.
  1785. **
  1786. ** Arguments: ptf - pointer to twin family to unlink
  1787. **
  1788. ** Returns: TWINRESULT
  1789. **
  1790. ** Side Effects: none
  1791. */
  1792. PUBLIC_CODE TWINRESULT UnlinkTwinFamily(PTWINFAMILY ptf)
  1793. {
  1794. TWINRESULT tr;
  1795. ASSERT(IS_VALID_STRUCT_PTR(ptf, CTWINFAMILY));
  1796. ASSERT(IsStubFlagClear(&(ptf->stub), STUB_FL_UNLINKED));
  1797. ASSERT(IsStubFlagClear(&(ptf->stub), STUB_FL_BEING_DELETED));
  1798. /*
  1799. * A twin family containing object twins generated by folder twins may not
  1800. * be deleted, since those object twins may not be directly deleted.
  1801. */
  1802. if (WalkList(ptf->hlistObjectTwins, &LookForSrcFolderTwinsWalker, NULL))
  1803. {
  1804. HPTRARRAY hpaTwinFamilies;
  1805. ARRAYINDEX aiUnlink;
  1806. TRACE_OUT((TEXT("UnlinkTwinFamily(): Unlinking twin family for object %s."),
  1807. GetString(ptf->hsName)));
  1808. /* Search for the twin family to be unlinked. */
  1809. hpaTwinFamilies = GetBriefcaseTwinFamilyPtrArray(ptf->hbr);
  1810. if (EVAL(SearchSortedArray(hpaTwinFamilies, &TwinFamilySortCmp, ptf,
  1811. &aiUnlink)))
  1812. {
  1813. /* Unlink the twin family. */
  1814. ASSERT(GetPtr(hpaTwinFamilies, aiUnlink) == ptf);
  1815. DeletePtr(hpaTwinFamilies, aiUnlink);
  1816. SetStubFlag(&(ptf->stub), STUB_FL_UNLINKED);
  1817. }
  1818. tr = TR_SUCCESS;
  1819. }
  1820. else
  1821. tr = TR_HAS_FOLDER_TWIN_SRC;
  1822. return(tr);
  1823. }
  1824. /*
  1825. ** DestroyTwinFamily()
  1826. **
  1827. ** Destroys a twin family.
  1828. **
  1829. ** Arguments: ptf - pointer to twin family to destroy
  1830. **
  1831. ** Returns: void
  1832. **
  1833. ** Side Effects: none
  1834. */
  1835. PUBLIC_CODE void DestroyTwinFamily(PTWINFAMILY ptf)
  1836. {
  1837. ASSERT(IS_VALID_STRUCT_PTR(ptf, CTWINFAMILY));
  1838. ASSERT(IsStubFlagClear(&(ptf->stub), STUB_FL_BEING_DELETED));
  1839. TRACE_OUT((TEXT("DestroyTwinFamily(): Destroying twin family for object %s."),
  1840. GetString(ptf->hsName)));
  1841. SetStubFlag(&(ptf->stub), STUB_FL_BEING_DELETED);
  1842. /*
  1843. * Destroy the object twins in the family one by one. Be careful not to use
  1844. * an object twin after it has been destroyed.
  1845. */
  1846. EVAL(WalkList(ptf->hlistObjectTwins, &DestroyObjectTwinStubWalker, NULL));
  1847. /* Destroy TWINFAMILY fields. */
  1848. DestroyList(ptf->hlistObjectTwins);
  1849. DeleteString(ptf->hsName);
  1850. FreeMemory(ptf);
  1851. return;
  1852. }
  1853. /*
  1854. ** MarkTwinFamilyNeverReconciled()
  1855. **
  1856. ** Marks a twin family as never reconciled.
  1857. **
  1858. ** Arguments: ptf - pointer to twin family to be marked never reconciled
  1859. **
  1860. ** Returns: void
  1861. **
  1862. ** Side Effects: Clears the twin family's last reconciliation time stamp.
  1863. ** Marks all the object twins in the family never reconciled.
  1864. */
  1865. PUBLIC_CODE void MarkTwinFamilyNeverReconciled(PTWINFAMILY ptf)
  1866. {
  1867. /*
  1868. * If we're being called from CreateTwinFamily(), the fields we're about to
  1869. * set may currently be invalid. Don't fully verify the TWINFAMILY
  1870. * structure.
  1871. */
  1872. ASSERT(IS_VALID_WRITE_PTR(ptf, TWINFAMILY));
  1873. /* Mark all object twins in twin family as never reconciled. */
  1874. EVAL(WalkList(ptf->hlistObjectTwins, MarkObjectTwinNeverReconciledWalker, NULL));
  1875. return;
  1876. }
  1877. /*
  1878. ** MarkObjectTwinNeverReconciled()
  1879. **
  1880. **
  1881. **
  1882. ** Arguments:
  1883. **
  1884. ** Returns: TWINRESULT
  1885. **
  1886. ** Side Effects: none
  1887. */
  1888. PUBLIC_CODE void MarkObjectTwinNeverReconciled(PVOID pot)
  1889. {
  1890. /*
  1891. * If we're being called from CreateObjectTwin(), the fields we're about to
  1892. * set may currently be invalid. Don't fully verify the OBJECTTWIN
  1893. * structure.
  1894. */
  1895. ASSERT(IS_VALID_WRITE_PTR((PCOBJECTTWIN)pot, COBJECTTWIN));
  1896. ASSERT(IsStubFlagClear(&(((PCOBJECTTWIN)pot)->stub), STUB_FL_NOT_RECONCILED));
  1897. ZeroMemory(&(((POBJECTTWIN)pot)->fsLastRec),
  1898. sizeof(((POBJECTTWIN)pot)->fsLastRec));
  1899. ((POBJECTTWIN)pot)->fsLastRec.fscond = FS_COND_UNAVAILABLE;
  1900. return;
  1901. }
  1902. /*
  1903. ** MarkTwinFamilyDeletionPending()
  1904. **
  1905. **
  1906. **
  1907. ** Arguments:
  1908. **
  1909. ** Returns:
  1910. **
  1911. ** Side Effects: none
  1912. */
  1913. PUBLIC_CODE void MarkTwinFamilyDeletionPending(PTWINFAMILY ptf)
  1914. {
  1915. ASSERT(IS_VALID_STRUCT_PTR(ptf, CTWINFAMILY));
  1916. if (IsStubFlagClear(&(ptf->stub), STUB_FL_DELETION_PENDING))
  1917. TRACE_OUT((TEXT("MarkTwinFamilyDeletionPending(): Deletion now pending for twin family for %s."),
  1918. GetString(ptf->hsName)));
  1919. SetStubFlag(&(ptf->stub), STUB_FL_DELETION_PENDING);
  1920. return;
  1921. }
  1922. /*
  1923. ** UnmarkTwinFamilyDeletionPending()
  1924. **
  1925. **
  1926. **
  1927. ** Arguments:
  1928. **
  1929. ** Returns:
  1930. **
  1931. ** Side Effects: none
  1932. */
  1933. PUBLIC_CODE void UnmarkTwinFamilyDeletionPending(PTWINFAMILY ptf)
  1934. {
  1935. BOOL bContinue;
  1936. HNODE hnode;
  1937. ASSERT(IS_VALID_STRUCT_PTR(ptf, CTWINFAMILY));
  1938. if (IsStubFlagSet(&(ptf->stub), STUB_FL_DELETION_PENDING))
  1939. {
  1940. for (bContinue = GetFirstNode(ptf->hlistObjectTwins, &hnode);
  1941. bContinue;
  1942. bContinue = GetNextNode(hnode, &hnode))
  1943. {
  1944. POBJECTTWIN pot;
  1945. pot = GetNodeData(hnode);
  1946. ClearStubFlag(&(pot->stub), STUB_FL_KEEP);
  1947. }
  1948. ClearStubFlag(&(ptf->stub), STUB_FL_DELETION_PENDING);
  1949. TRACE_OUT((TEXT("UnmarkTwinFamilyDeletionPending(): Deletion no longer pending for twin family for %s."),
  1950. GetString(ptf->hsName)));
  1951. }
  1952. return;
  1953. }
  1954. /*
  1955. ** IsTwinFamilyDeletionPending()
  1956. **
  1957. **
  1958. **
  1959. ** Arguments:
  1960. **
  1961. ** Returns:
  1962. **
  1963. ** Side Effects: none
  1964. */
  1965. PUBLIC_CODE BOOL IsTwinFamilyDeletionPending(PCTWINFAMILY pctf)
  1966. {
  1967. ASSERT(IS_VALID_STRUCT_PTR(pctf, CTWINFAMILY));
  1968. return(IsStubFlagSet(&(pctf->stub), STUB_FL_DELETION_PENDING));
  1969. }
  1970. /*
  1971. ** ClearTwinFamilySrcFolderTwinCount()
  1972. **
  1973. **
  1974. **
  1975. ** Arguments:
  1976. **
  1977. ** Returns:
  1978. **
  1979. ** Side Effects: none
  1980. */
  1981. PUBLIC_CODE void ClearTwinFamilySrcFolderTwinCount(PTWINFAMILY ptf)
  1982. {
  1983. ASSERT(IS_VALID_STRUCT_PTR(ptf, CTWINFAMILY));
  1984. EVAL(WalkList(ptf->hlistObjectTwins, &ClearSrcFolderTwinsWalker, NULL));
  1985. return;
  1986. }
  1987. /*
  1988. ** EnumObjectTwins()
  1989. **
  1990. **
  1991. **
  1992. ** Arguments:
  1993. **
  1994. ** Returns:
  1995. **
  1996. ** Side Effects: none
  1997. */
  1998. PUBLIC_CODE BOOL EnumObjectTwins(HBRFCASE hbr,
  1999. ENUMGENERATEDOBJECTTWINSPROC egotp,
  2000. PVOID pvRefData)
  2001. {
  2002. BOOL bResult = TRUE;
  2003. HPTRARRAY hpaTwinFamilies;
  2004. ARRAYINDEX aicPtrs;
  2005. ARRAYINDEX ai;
  2006. /* pvRefData may be any value. */
  2007. ASSERT(IS_VALID_HANDLE(hbr, BRFCASE));
  2008. ASSERT(IS_VALID_CODE_PTR(egotp, ENUMGENERATEDOBJECTTWINPROC));
  2009. /* Walk the array of twin families. */
  2010. hpaTwinFamilies = GetBriefcaseTwinFamilyPtrArray(hbr);
  2011. aicPtrs = GetPtrCount(hpaTwinFamilies);
  2012. ai = 0;
  2013. while (ai < aicPtrs)
  2014. {
  2015. PTWINFAMILY ptf;
  2016. BOOL bContinue;
  2017. HNODE hnodePrev;
  2018. ptf = GetPtr(hpaTwinFamilies, ai);
  2019. ASSERT(IS_VALID_STRUCT_PTR(ptf, CTWINFAMILY));
  2020. ASSERT(IsStubFlagClear(&(ptf->stub), STUB_FL_UNLINKED));
  2021. /* Lock the twin family so it isn't deleted out from under us. */
  2022. LockStub(&(ptf->stub));
  2023. /*
  2024. * Walk each twin family's list of object twins, calling the callback
  2025. * function with each object twin.
  2026. */
  2027. bContinue = GetFirstNode(ptf->hlistObjectTwins, &hnodePrev);
  2028. while (bContinue)
  2029. {
  2030. HNODE hnodeNext;
  2031. POBJECTTWIN pot;
  2032. bContinue = GetNextNode(hnodePrev, &hnodeNext);
  2033. pot = (POBJECTTWIN)GetNodeData(hnodePrev);
  2034. ASSERT(IS_VALID_STRUCT_PTR(pot, COBJECTTWIN));
  2035. bResult = (*egotp)(pot, pvRefData);
  2036. if (! bResult)
  2037. break;
  2038. hnodePrev = hnodeNext;
  2039. }
  2040. /* Was the twin family unlinked? */
  2041. if (IsStubFlagClear(&(ptf->stub), STUB_FL_UNLINKED))
  2042. /* No. */
  2043. ai++;
  2044. else
  2045. {
  2046. /* Yes. */
  2047. aicPtrs--;
  2048. ASSERT(aicPtrs == GetPtrCount(hpaTwinFamilies));
  2049. TRACE_OUT((TEXT("EnumObjectTwins(): Twin family for object %s unlinked by callback."),
  2050. GetString(ptf->hsName)));
  2051. }
  2052. UnlockStub(&(ptf->stub));
  2053. if (! bResult)
  2054. break;
  2055. }
  2056. return(bResult);
  2057. }
  2058. /*
  2059. ** ApplyNewFolderTwinsToTwinFamilies()
  2060. **
  2061. **
  2062. **
  2063. ** Arguments:
  2064. **
  2065. ** Returns:
  2066. **
  2067. ** Side Effects: none
  2068. **
  2069. ** If FALSE is returned, the array of twin families is in the same state it was
  2070. ** in before ApplyNewFolderTwinsToTwinFamilies() was called. No clean-up is
  2071. ** required by the caller in case of failure.
  2072. **
  2073. ** This function collapses a pair of separate twin families when an object twin
  2074. ** in one twin family intersects one of the folder twins in the pair of new
  2075. ** folder twins and an object twin in the other twin family intersects the
  2076. ** other folder twin in the pair of new folder twins.
  2077. **
  2078. ** This function generates a spinoff object twin when an existing object twin
  2079. ** intersects one of the folder twins in the pair of new folder twins, and no
  2080. ** corresponding object twin for the other folder twin in the pair of new
  2081. ** folder twins exists in the briefcase. The spinoff object twin is added to
  2082. ** the generating object twin's twin family. A spinoff object twins cannot
  2083. ** cause any existing pairs of twin families to be collapsed because the
  2084. ** spinoff object twin did not previously exist in a twin family.
  2085. **
  2086. ** A new folder twin may collapse pairs of existing twin families. E.g.,
  2087. ** consider the following scenario:
  2088. **
  2089. ** 1) Twin families (c:\, d:\, foo), (e:\, f:\, foo), (c:\, d:\, bar), and
  2090. ** (e:\, f:\, bar) exist.
  2091. ** 2) New folder twin (d:\, e:\, *.*) is added.
  2092. ** 3) Twin families (c:\, d:\, foo) and (e:\, f:\, foo) must be collpased into
  2093. ** a single twin family because of the (d:\, e:\, *.*) folder twin.
  2094. ** 4) Twin families (c:\, d:\, bar) and (e:\, f:\, bar) must be collpased into
  2095. ** a single twin family because of the (d:\, e:\, *.*) folder twin.
  2096. **
  2097. ** So we see that new folder twin (d:\, e:\, *.*) must collapse two pairs of
  2098. ** existing twin families a single twin family each. Twin family
  2099. ** (c:\, d:\, foo) plus twin family (e:\, f:\, foo) becomes twin family
  2100. ** (c:\, d:\, e:\, f:\, foo). Twin family (c:\, d:\, bar) plus twin family
  2101. ** (e:\, f:\, bar) becomes twin family (c:\, d:\, e:\, f:\, bar).
  2102. */
  2103. PUBLIC_CODE BOOL ApplyNewFolderTwinsToTwinFamilies(PCFOLDERPAIR pcfp)
  2104. {
  2105. BOOL bResult = FALSE;
  2106. HLIST hlistGeneratedObjectTwins;
  2107. ASSERT(IS_VALID_STRUCT_PTR(pcfp, CFOLDERPAIR));
  2108. /*
  2109. * Create lists to contain existing object twins generated by both folder
  2110. * twins.
  2111. */
  2112. if (CreateListOfGeneratedObjectTwins(pcfp, &hlistGeneratedObjectTwins))
  2113. {
  2114. HLIST hlistOtherGeneratedObjectTwins;
  2115. if (CreateListOfGeneratedObjectTwins(pcfp->pfpOther,
  2116. &hlistOtherGeneratedObjectTwins))
  2117. {
  2118. NEWLIST nl;
  2119. HLIST hlistNewObjectTwins;
  2120. /* Create list to contain spin-off object twins. */
  2121. nl.dwFlags = 0;
  2122. if (CreateList(&nl, &hlistNewObjectTwins))
  2123. {
  2124. SPINOFFOBJECTTWININFO sooti;
  2125. /*
  2126. * Generate list of new object twins generated by new folder twins
  2127. * to seed ApplyNewObjectTwinToFolderTwins().
  2128. */
  2129. sooti.pcfp = pcfp;
  2130. sooti.hlistNewObjectTwins = hlistNewObjectTwins;
  2131. if (WalkList(hlistGeneratedObjectTwins, &GenerateSpinOffObjectTwin,
  2132. &sooti))
  2133. {
  2134. sooti.pcfp = pcfp->pfpOther;
  2135. ASSERT(sooti.hlistNewObjectTwins == hlistNewObjectTwins);
  2136. if (WalkList(hlistOtherGeneratedObjectTwins,
  2137. &GenerateSpinOffObjectTwin, &sooti))
  2138. {
  2139. /*
  2140. * ApplyNewObjectTwinsToFolderTwins() sets ulcSrcFolderTwins
  2141. * for all object twins in hlistNewObjectTwins.
  2142. */
  2143. if (ApplyNewObjectTwinsToFolderTwins(hlistNewObjectTwins))
  2144. {
  2145. /*
  2146. * Collapse separate twin families joined by new folder
  2147. * twin.
  2148. */
  2149. EVAL(WalkList(hlistGeneratedObjectTwins, &BuildBradyBunch,
  2150. (PVOID)pcfp));
  2151. /*
  2152. * We don't need to call BuildBradyBunch() for
  2153. * pcfp->pfpOther and hlistOtherGeneratedObjectTwins since
  2154. * one twin family from each collapsed pair of twin
  2155. * families must come from each list of generated object
  2156. * twins.
  2157. */
  2158. /*
  2159. * Increment source folder twin count for all pre-existing
  2160. * object twins generated by the new folder twins.
  2161. */
  2162. EVAL(WalkList(hlistGeneratedObjectTwins,
  2163. &IncrementSrcFolderTwinsWalker, NULL));
  2164. EVAL(WalkList(hlistOtherGeneratedObjectTwins,
  2165. &IncrementSrcFolderTwinsWalker, NULL));
  2166. bResult = TRUE;
  2167. }
  2168. }
  2169. }
  2170. /* Wipe out any new object twins on failure. */
  2171. if (! bResult)
  2172. EVAL(WalkList(hlistNewObjectTwins, &DestroyObjectTwinStubWalker,
  2173. NULL));
  2174. DestroyList(hlistNewObjectTwins);
  2175. }
  2176. DestroyList(hlistOtherGeneratedObjectTwins);
  2177. }
  2178. DestroyList(hlistGeneratedObjectTwins);
  2179. }
  2180. return(bResult);
  2181. }
  2182. /*
  2183. ** TransplantObjectTwin()
  2184. **
  2185. **
  2186. **
  2187. ** Arguments:
  2188. **
  2189. ** Returns: TWINRESULT
  2190. **
  2191. ** Side Effects: none
  2192. */
  2193. PUBLIC_CODE TWINRESULT TransplantObjectTwin(POBJECTTWIN pot,
  2194. HPATH hpathOldFolder,
  2195. HPATH hpathNewFolder)
  2196. {
  2197. TWINRESULT tr;
  2198. ASSERT(IS_VALID_STRUCT_PTR(pot, COBJECTTWIN));
  2199. ASSERT(IS_VALID_HANDLE(hpathOldFolder, PATH));
  2200. ASSERT(IS_VALID_HANDLE(hpathNewFolder, PATH));
  2201. /* Is this object twin rooted in the renamed folder's subtree? */
  2202. if (IsPathPrefix(pot->hpath, hpathOldFolder))
  2203. {
  2204. TCHAR rgchPathSuffix[MAX_PATH_LEN];
  2205. LPCTSTR pcszSubPath;
  2206. HPATH hpathNew;
  2207. /* Yes. Change the object twin's root. */
  2208. pcszSubPath = FindChildPathSuffix(hpathOldFolder, pot->hpath,
  2209. rgchPathSuffix);
  2210. if (AddChildPath(GetBriefcasePathList(pot->ptfParent->hbr),
  2211. hpathNewFolder, pcszSubPath, &hpathNew))
  2212. {
  2213. TRACE_OUT((TEXT("TransplantObjectTwin(): Transplanted object twin %s\\%s to %s\\%s."),
  2214. DebugGetPathString(pot->hpath),
  2215. GetString(pot->ptfParent->hsName),
  2216. DebugGetPathString(hpathNew),
  2217. GetString(pot->ptfParent->hsName)));
  2218. DeletePath(pot->hpath);
  2219. pot->hpath = hpathNew;
  2220. tr = TR_SUCCESS;
  2221. }
  2222. else
  2223. tr = TR_OUT_OF_MEMORY;
  2224. }
  2225. else
  2226. tr = TR_SUCCESS;
  2227. return(tr);
  2228. }
  2229. /*
  2230. ** IsFolderObjectTwinName()
  2231. **
  2232. **
  2233. **
  2234. ** Arguments:
  2235. **
  2236. ** Returns:
  2237. **
  2238. ** Side Effects: none
  2239. */
  2240. PUBLIC_CODE BOOL IsFolderObjectTwinName(LPCTSTR pcszName)
  2241. {
  2242. ASSERT(IS_VALID_STRING_PTR(pcszName, CSTR));
  2243. return(! *pcszName);
  2244. }
  2245. /*
  2246. ** IsValidHTWIN()
  2247. **
  2248. **
  2249. **
  2250. ** Arguments:
  2251. **
  2252. ** Returns:
  2253. **
  2254. ** Side Effects: none
  2255. */
  2256. PUBLIC_CODE BOOL IsValidHTWIN(HTWIN htwin)
  2257. {
  2258. BOOL bValid = FALSE;
  2259. if (IS_VALID_STRUCT_PTR((PCSTUB)htwin, CSTUB))
  2260. {
  2261. switch (((PSTUB)htwin)->st)
  2262. {
  2263. case ST_OBJECTTWIN:
  2264. bValid = IS_VALID_HANDLE((HOBJECTTWIN)htwin, OBJECTTWIN);
  2265. break;
  2266. case ST_TWINFAMILY:
  2267. bValid = IS_VALID_HANDLE((HTWINFAMILY)htwin, TWINFAMILY);
  2268. break;
  2269. case ST_FOLDERPAIR:
  2270. bValid = IS_VALID_HANDLE((HFOLDERTWIN)htwin, FOLDERTWIN);
  2271. break;
  2272. default:
  2273. ERROR_OUT((TEXT("IsValidHTWIN() called on unrecognized stub type %d."),
  2274. ((PSTUB)htwin)->st));
  2275. break;
  2276. }
  2277. }
  2278. else
  2279. ERROR_OUT((TEXT("IsValidHTWIN() called on bad twin handle %#lx."),
  2280. htwin));
  2281. return(bValid);
  2282. }
  2283. /*
  2284. ** IsValidHTWINFAMILY()
  2285. **
  2286. **
  2287. **
  2288. ** Arguments:
  2289. **
  2290. ** Returns:
  2291. **
  2292. ** Side Effects: none
  2293. */
  2294. PUBLIC_CODE BOOL IsValidHTWINFAMILY(HTWINFAMILY htf)
  2295. {
  2296. return(IS_VALID_STRUCT_PTR((PTWINFAMILY)htf, CTWINFAMILY));
  2297. }
  2298. /*
  2299. ** IsValidHOBJECTTWIN()
  2300. **
  2301. **
  2302. **
  2303. ** Arguments:
  2304. **
  2305. ** Returns:
  2306. **
  2307. ** Side Effects: none
  2308. */
  2309. PUBLIC_CODE BOOL IsValidHOBJECTTWIN(HOBJECTTWIN hot)
  2310. {
  2311. return(IS_VALID_STRUCT_PTR((POBJECTTWIN)hot, COBJECTTWIN));
  2312. }
  2313. #ifdef VSTF
  2314. /*
  2315. ** IsValidPCTWINFAMILY()
  2316. **
  2317. **
  2318. **
  2319. ** Arguments:
  2320. **
  2321. ** Returns:
  2322. **
  2323. ** Side Effects: none
  2324. */
  2325. PUBLIC_CODE BOOL IsValidPCTWINFAMILY(PCTWINFAMILY pctf)
  2326. {
  2327. BOOL bResult;
  2328. /* All the fields of an unlinked twin family should be valid. */
  2329. /* Don't validate hbr. */
  2330. /*
  2331. * In some cases there may be fewer than two object twins in a twin family,
  2332. * e.g., when two twin families are being collapsed, when a twin family is
  2333. * being deleted, and when a twin family is being read in from a database.
  2334. */
  2335. if (IS_VALID_READ_PTR(pctf, CTWINFAMILY) &&
  2336. IS_VALID_STRUCT_PTR(&(pctf->stub), CSTUB) &&
  2337. FLAGS_ARE_VALID(GetStubFlags(&(pctf->stub)), ALL_TWIN_FAMILY_FLAGS) &&
  2338. IS_VALID_HANDLE(pctf->hsName, STRING) &&
  2339. IS_VALID_HANDLE(pctf->hlistObjectTwins, LIST))
  2340. bResult = WalkList(pctf->hlistObjectTwins, &IsValidObjectTwinWalker, (PVOID)pctf);
  2341. else
  2342. bResult = FALSE;
  2343. return(bResult);
  2344. }
  2345. /*
  2346. ** IsValidPCOBJECTTWIN()
  2347. **
  2348. **
  2349. **
  2350. ** Arguments:
  2351. **
  2352. ** Returns:
  2353. **
  2354. ** Side Effects: none
  2355. */
  2356. PUBLIC_CODE BOOL IsValidPCOBJECTTWIN(PCOBJECTTWIN pcot)
  2357. {
  2358. /*
  2359. * All the fields of an unlinked object twin should be valid, except
  2360. * possibly ptfParent and fsCurrent.
  2361. */
  2362. /*
  2363. * Winner of the 1995 "I think the compiler generates better code
  2364. * if its takes up less space on the screen" award.
  2365. *
  2366. * Running up in the "Make the debugger execute 2K of code as an
  2367. * atomic operation while debugger" category.
  2368. *
  2369. */
  2370. return(IS_VALID_READ_PTR(pcot, COBJECTTWIN) &&
  2371. IS_VALID_STRUCT_PTR(&(pcot->stub), CSTUB) &&
  2372. FLAGS_ARE_VALID(GetStubFlags(&(pcot->stub)), ALL_OBJECT_TWIN_FLAGS) &&
  2373. IS_VALID_HANDLE(pcot->hpath, PATH) &&
  2374. (IsStubFlagSet(&(pcot->stub), STUB_FL_UNLINKED) ||
  2375. IS_VALID_READ_PTR(pcot->ptfParent, CTWINFAMILY)) &&
  2376. IS_VALID_STRUCT_PTR(&(pcot->fsLastRec), CFILESTAMP) &&
  2377. (IsStubFlagClear(&(pcot->stub), STUB_FL_FILE_STAMP_VALID) ||
  2378. (IS_VALID_STRUCT_PTR(&(pcot->fsCurrent), CFILESTAMP))) &&
  2379. EVAL(! (! IsReconciledFileStamp(&(pcot->fsLastRec)) &&
  2380. IsStubFlagSet(&(pcot->stub), STUB_FL_NOT_RECONCILED))));
  2381. }
  2382. #endif
  2383. /*
  2384. ** WriteTwinFamilies()
  2385. **
  2386. **
  2387. **
  2388. ** Arguments:
  2389. **
  2390. ** Returns: TWINRESULT
  2391. **
  2392. ** Side Effects: none
  2393. */
  2394. PUBLIC_CODE TWINRESULT WriteTwinFamilies(HCACHEDFILE hcf, HPTRARRAY hpaTwinFamilies)
  2395. {
  2396. TWINRESULT tr = TR_BRIEFCASE_WRITE_FAILED;
  2397. DWORD dwcbTwinFamiliesDBHeaderOffset;
  2398. ASSERT(IS_VALID_HANDLE(hcf, CACHEDFILE));
  2399. ASSERT(IS_VALID_HANDLE(hpaTwinFamilies, PTRARRAY));
  2400. /* Save initial file poisition. */
  2401. dwcbTwinFamiliesDBHeaderOffset = GetCachedFilePointerPosition(hcf);
  2402. if (dwcbTwinFamiliesDBHeaderOffset != INVALID_SEEK_POSITION)
  2403. {
  2404. TWINFAMILIESDBHEADER tfdbh;
  2405. /* Leave space for the twin families' header. */
  2406. ZeroMemory(&tfdbh, sizeof(tfdbh));
  2407. if (WriteToCachedFile(hcf, (PCVOID)&tfdbh, sizeof(tfdbh), NULL))
  2408. {
  2409. ARRAYINDEX aicPtrs;
  2410. ARRAYINDEX ai;
  2411. tr = TR_SUCCESS;
  2412. aicPtrs = GetPtrCount(hpaTwinFamilies);
  2413. for (ai = 0;
  2414. ai < aicPtrs && tr == TR_SUCCESS;
  2415. ai++)
  2416. tr = WriteTwinFamily(hcf, GetPtr(hpaTwinFamilies, ai));
  2417. if (tr == TR_SUCCESS)
  2418. {
  2419. /* Save twin families' header. */
  2420. tfdbh.lcTwinFamilies = aicPtrs;
  2421. tr = WriteDBSegmentHeader(hcf, dwcbTwinFamiliesDBHeaderOffset,
  2422. &tfdbh, sizeof(tfdbh));
  2423. if (tr == TR_SUCCESS)
  2424. TRACE_OUT((TEXT("WriteTwinFamilies(): Wrote %ld twin families."),
  2425. tfdbh.lcTwinFamilies));
  2426. }
  2427. }
  2428. }
  2429. return(tr);
  2430. }
  2431. /*
  2432. ** ReadTwinFamilies()
  2433. **
  2434. **
  2435. **
  2436. ** Arguments:
  2437. **
  2438. ** Returns: TWINRESULT
  2439. **
  2440. ** Side Effects: none
  2441. */
  2442. PUBLIC_CODE TWINRESULT ReadTwinFamilies(HCACHEDFILE hcf, HBRFCASE hbr,
  2443. PCDBVERSION pcdbver,
  2444. HHANDLETRANS hhtFolderTrans,
  2445. HHANDLETRANS hhtNameTrans)
  2446. {
  2447. TWINRESULT tr;
  2448. TWINFAMILIESDBHEADER tfdbh;
  2449. DWORD dwcbRead;
  2450. ASSERT(IS_VALID_HANDLE(hcf, CACHEDFILE));
  2451. ASSERT(IS_VALID_HANDLE(hbr, BRFCASE));
  2452. ASSERT(IS_VALID_READ_PTR(pcdbver, DBVERSION));
  2453. ASSERT(IS_VALID_HANDLE(hhtFolderTrans, HANDLETRANS));
  2454. ASSERT(IS_VALID_HANDLE(hhtNameTrans, HANDLETRANS));
  2455. if (ReadFromCachedFile(hcf, &tfdbh, sizeof(tfdbh), &dwcbRead) &&
  2456. dwcbRead == sizeof(tfdbh))
  2457. {
  2458. LONG l;
  2459. tr = TR_SUCCESS;
  2460. TRACE_OUT((TEXT("ReadTwinFamilies(): Reading %ld twin families."),
  2461. tfdbh.lcTwinFamilies));
  2462. for (l = 0;
  2463. l < tfdbh.lcTwinFamilies && tr == TR_SUCCESS;
  2464. l++)
  2465. tr = ReadTwinFamily(hcf, hbr, pcdbver, hhtFolderTrans, hhtNameTrans);
  2466. ASSERT(AreTwinFamiliesValid(GetBriefcaseTwinFamilyPtrArray(hbr)));
  2467. }
  2468. else
  2469. tr = TR_CORRUPT_BRIEFCASE;
  2470. return(tr);
  2471. }
  2472. /***************************** Exported Functions ****************************/
  2473. /******************************************************************************
  2474. @doc SYNCENGAPI
  2475. @api TWINRESULT | AddObjectTwin | Twins two objects.
  2476. @parm HBRFCASE | hbr | A handle to the open briefcase that the new object twins
  2477. are to be added to.
  2478. @parm PCNEWOBJECTTWIN | pcnot | A pointer to a CNEWOBJECTTWIN describing the
  2479. objects to be twinned.
  2480. @parm PHTWINFAMILY | phtf | A pointer to an HTWINFAMILY to be filled in with
  2481. a handle to the twin family to which the object twins were added. This handle
  2482. may refer to a new or existing twin family. *phtf is only valid if TR_SUCCESS
  2483. is returned.
  2484. @rdesc If the objects were twinned successfully, TR_SUCCESS is returned, and
  2485. *phTwinFamily contains a handle to the associated twin family. Otherwise, the
  2486. objects were not twinned successfully, the return value indicates the error
  2487. that occurred, and *phtf is undefined. If one or both of the volumes
  2488. specified by the NEWOBJECTTWIN structure is not present, TR_UNAVAILABLE_VOLUME
  2489. will be returned, and the object twin will not be added.
  2490. @comm Once the caller is finshed with the twin handle returned by
  2491. AddObjectTwin(), ReleaseTwinHandle() should be called to release the twin
  2492. handle. DeleteTwin() does not release a twin handle returned by
  2493. AddObjectTwin().
  2494. @xref ReleaseTwinHandle DeleteTwin
  2495. ******************************************************************************/
  2496. SYNCENGAPI TWINRESULT WINAPI AddObjectTwin(HBRFCASE hbr, PCNEWOBJECTTWIN pcnot,
  2497. PHTWINFAMILY phtf)
  2498. {
  2499. TWINRESULT tr;
  2500. if (BeginExclusiveBriefcaseAccess())
  2501. {
  2502. DebugEntry(AddObjectTwin);
  2503. #ifdef EXPV
  2504. /* Verify parameters. */
  2505. if (IS_VALID_HANDLE(hbr, BRFCASE) &&
  2506. IS_VALID_STRUCT_PTR(pcnot, CNEWOBJECTTWIN) &&
  2507. EVAL(pcnot->ulSize == sizeof(*pcnot)) &&
  2508. IS_VALID_WRITE_PTR(phtf, HTWINFAMILY))
  2509. #endif
  2510. {
  2511. HCLSIFACECACHE hcic;
  2512. if (CreateClassInterfaceCache(&hcic))
  2513. {
  2514. HPATHLIST hplBriefcase;
  2515. HPATH hpathFolder1;
  2516. InvalidatePathListInfo(GetBriefcasePathList(hbr));
  2517. hplBriefcase = GetBriefcasePathList(hbr);
  2518. tr = TranslatePATHRESULTToTWINRESULT(AddPath(hplBriefcase,
  2519. pcnot->pcszFolder1,
  2520. &hpathFolder1));
  2521. if (tr == TR_SUCCESS)
  2522. {
  2523. HPATH hpathFolder2;
  2524. tr = TranslatePATHRESULTToTWINRESULT(AddPath(hplBriefcase,
  2525. pcnot->pcszFolder2,
  2526. &hpathFolder2));
  2527. if (tr == TR_SUCCESS)
  2528. {
  2529. POBJECTTWIN pot1;
  2530. POBJECTTWIN pot2;
  2531. tr = TwinObjects(hbr, hcic, hpathFolder1, hpathFolder2,
  2532. pcnot->pcszName, &pot1, &pot2);
  2533. /*
  2534. * These twins are not really duplicates unless they were already
  2535. * connected as object twins.
  2536. */
  2537. if (tr == TR_DUPLICATE_TWIN &&
  2538. (IsStubFlagClear(&(pot1->stub), STUB_FL_FROM_OBJECT_TWIN) ||
  2539. IsStubFlagClear(&(pot2->stub), STUB_FL_FROM_OBJECT_TWIN)))
  2540. tr = TR_SUCCESS;
  2541. if (tr == TR_SUCCESS)
  2542. {
  2543. /* Success! */
  2544. ASSERT(pot1->ptfParent == pot2->ptfParent);
  2545. ASSERT(IS_VALID_HANDLE((HTWINFAMILY)(pot1->ptfParent), TWINFAMILY));
  2546. LockStub(&(pot1->ptfParent->stub));
  2547. SetStubFlag(&(pot1->stub), STUB_FL_FROM_OBJECT_TWIN);
  2548. SetStubFlag(&(pot2->stub), STUB_FL_FROM_OBJECT_TWIN);
  2549. *phtf = (HTWINFAMILY)(pot1->ptfParent);
  2550. }
  2551. DeletePath(hpathFolder2);
  2552. }
  2553. DeletePath(hpathFolder1);
  2554. }
  2555. DestroyClassInterfaceCache(hcic);
  2556. }
  2557. else
  2558. tr = TR_OUT_OF_MEMORY;
  2559. }
  2560. #ifdef EXPV
  2561. else
  2562. tr = TR_INVALID_PARAMETER;
  2563. #endif
  2564. DebugExitTWINRESULT(AddObjectTwin, tr);
  2565. EndExclusiveBriefcaseAccess();
  2566. }
  2567. else
  2568. tr = TR_REENTERED;
  2569. return(tr);
  2570. }
  2571. /******************************************************************************
  2572. @doc SYNCENGAPI
  2573. @api TWINRESULT | ReleaseTwinHandle | Releases a twin handle returned by
  2574. AddObjectTwin(), AddFolderTwin(), or GetObjectTwinHandle().
  2575. @parm HTWIN | hTwin | The twin handle that is to be released.
  2576. @rdesc If the twin handle was released successfully, TR_SUCCESS is returned.
  2577. Otherwise, the twin handle was not released successfully, and the return value
  2578. indicates the error that occurred. hTwin is no longer a valid twin handle
  2579. after ReleaseTwinHandle() is called.
  2580. @comm If the lock count of the twin drops to 0 and deletion is pending against
  2581. the twin, the twin is deleted. If ReleaseTwinHandle() is called with a valid
  2582. handle to a twin that has been deleted, TR_SUCCESS will be returned.
  2583. DeleteTwin() does not release a twin handle returned by AddObjectTwin(),
  2584. AddFolderTwin(), or GetObjectTwinHandle(). ReleaseTwinHandle() should be
  2585. called to release a twin handle returned by AddObjectTwin(), AddFolderTwin(),
  2586. or GetObjectTwinHandle(). DeleteTwin() should be called before
  2587. ReleaseTwinHandle() if the twin is to be deleted.
  2588. @xref AddObjectTwin AddFolderTwin DeleteTwin
  2589. ******************************************************************************/
  2590. SYNCENGAPI TWINRESULT WINAPI ReleaseTwinHandle(HTWIN hTwin)
  2591. {
  2592. TWINRESULT tr;
  2593. if (BeginExclusiveBriefcaseAccess())
  2594. {
  2595. DebugEntry(ReleaseTwinHandle);
  2596. #ifdef EXPV
  2597. /* Verify parameters. */
  2598. if (IS_VALID_HANDLE(hTwin, TWIN))
  2599. #endif
  2600. {
  2601. UnlockStub((PSTUB)hTwin);
  2602. tr = TR_SUCCESS;
  2603. }
  2604. #ifdef EXPV
  2605. else
  2606. tr = TR_INVALID_PARAMETER;
  2607. #endif
  2608. DebugExitTWINRESULT(ReleaseTwinHandle, tr);
  2609. EndExclusiveBriefcaseAccess();
  2610. }
  2611. else
  2612. tr = TR_REENTERED;
  2613. return(tr);
  2614. }
  2615. /******************************************************************************
  2616. @doc SYNCENGAPI
  2617. @api TWINRESULT | DeleteTwin | Deletes a twin from the synchronization
  2618. database. A twin is added to the synchronization database by AddObjectTwin()
  2619. or AddFolderTwin().
  2620. @parm HTWIN | htwin | A handle to the twin being deleted.
  2621. @rdesc If the twin was deleted successfully, TR_SUCCESS is returned.
  2622. Otherwise, the twin was not deleted successfully, and the return value
  2623. indicates the error that occurred.
  2624. @comm If DeleteTwin() is called with a valid handle to a twin that has been
  2625. deleted, TR_SUCCESS will be returned. DeleteTwin() does not release a twin
  2626. handle returned by AddObjectTwin(), AddFolderTwin(), or GetObjectTwinHandle().
  2627. ReleaseTwinHandle() should be called to release a twin handle returned by
  2628. AddObjectTwin(), AddFolderTwin(), or GetObjectTwinHandle(). DeleteTwin()
  2629. should be called before ReleaseTwinHandle() if the twin is to be deleted.
  2630. DeleteTwin() will always succeed on a valid HFOLDERTWIN. DeleteTwin() will
  2631. fail on a valid HOBJECTTWIN for any object twin that has source folder twins,
  2632. returning TR_HAS_FOLDER_TWIN_SRC. DeleteTwin() will also fail on a valid
  2633. HTWINFAMILY for any twin family that contains two or more object twins with
  2634. source folder twins, returning TR_HAS_FOLDER_TWIN_SRC. A twin family cannot
  2635. contain only one object twin with source folder twins. Twin families can only
  2636. contain 0, 2, or more object twins with source folder twins.
  2637. @xref AddObjectTwin AddFolderTwin ReleaseTwinHandle IsOrphanObjectTwin
  2638. CountSourceFolderTwins
  2639. ******************************************************************************/
  2640. SYNCENGAPI TWINRESULT WINAPI DeleteTwin(HTWIN hTwin)
  2641. {
  2642. TWINRESULT tr;
  2643. if (BeginExclusiveBriefcaseAccess())
  2644. {
  2645. DebugEntry(DeleteTwin);
  2646. #ifdef EXPV
  2647. /* Verify parameters. */
  2648. if (IS_VALID_HANDLE(hTwin, TWIN))
  2649. #endif
  2650. {
  2651. tr = DestroyStub((PSTUB)hTwin);
  2652. }
  2653. #ifdef EXPV
  2654. else
  2655. tr = TR_INVALID_PARAMETER;
  2656. #endif
  2657. DebugExitTWINRESULT(DeleteTwin, tr);
  2658. EndExclusiveBriefcaseAccess();
  2659. }
  2660. else
  2661. tr = TR_REENTERED;
  2662. return(tr);
  2663. }
  2664. /******************************************************************************
  2665. @doc SYNCENGAPI
  2666. @api TWINRESULT | GetObjectTwinHandle | Determines whether or not an object is
  2667. a twin. If the object is a twin, a twin handle for the twinned object is
  2668. returned.
  2669. @parm HBRFCASE | hbr | A handle to the open briefcase to be checked for the
  2670. object twin.
  2671. @parm PCSTR | pcszFolder | A pointer to a string indicating the object's
  2672. folder.
  2673. @parm PCSTR | pcszName | A pointer to a string indicating the object's name.
  2674. @parm PHOBJECTTWIN | phot | A pointer to an HOBJECTTWIN to be filled in with
  2675. a handle to the object twin or NULL. If the object is a twin, *phObjectTwin
  2676. is filled in with a handle to the object twin. If the object is not a twin,
  2677. *phObjectTwin is filled in with NULL. *phObjectTwin is only valid if
  2678. TR_SUCCESS is returned.
  2679. @rdesc If the lookup was successful, TR_SUCCESS is returned. Otherwise, the
  2680. lookup was not successful, and the return value indicates the error that
  2681. occurred.
  2682. @comm Once the caller is finshed with the twin handle returned by
  2683. GetObjectTwinHandle(), ReleaseTwinHandle() should be called to release the twin
  2684. handle. N.b., DeleteTwin() does not release a twin handle returned by
  2685. GetObjectTwinHandle().
  2686. @xref AddObjectTwin ReleaseTwinHandle DeleteTwin
  2687. ******************************************************************************/
  2688. SYNCENGAPI TWINRESULT WINAPI GetObjectTwinHandle(HBRFCASE hbr,
  2689. LPCTSTR pcszFolder,
  2690. LPCTSTR pcszName,
  2691. PHOBJECTTWIN phot)
  2692. {
  2693. TWINRESULT tr;
  2694. if (BeginExclusiveBriefcaseAccess())
  2695. {
  2696. DebugEntry(GetObjectTwinHandle);
  2697. #ifdef EXPV
  2698. /* Verify parameters. */
  2699. if (IS_VALID_HANDLE(hbr, BRFCASE) &&
  2700. IS_VALID_STRING_PTR(pcszFolder, CSTR) &&
  2701. IS_VALID_STRING_PTR(pcszName, CSTR) &&
  2702. IS_VALID_WRITE_PTR(phot, HOBJECTTWIN))
  2703. #endif
  2704. {
  2705. HPATH hpath;
  2706. InvalidatePathListInfo(GetBriefcasePathList(hbr));
  2707. tr = TranslatePATHRESULTToTWINRESULT(
  2708. AddPath(GetBriefcasePathList(hbr), pcszFolder, &hpath));
  2709. if (tr == TR_SUCCESS)
  2710. {
  2711. BOOL bFound;
  2712. HNODE hnode;
  2713. POBJECTTWIN pot;
  2714. /* Is this object already an object twin? */
  2715. bFound = FindObjectTwin(hbr, hpath, pcszName, &hnode);
  2716. if (bFound)
  2717. /* Yes. */
  2718. pot = (POBJECTTWIN)GetNodeData(hnode);
  2719. else
  2720. /*
  2721. * No. Expand folder twins, and check for a generating folder
  2722. * twin.
  2723. */
  2724. tr = TryToGenerateObjectTwin(hbr, hpath, pcszName, &bFound,
  2725. &pot);
  2726. if (tr == TR_SUCCESS)
  2727. {
  2728. if (bFound)
  2729. {
  2730. LockStub(&(pot->stub));
  2731. TRACE_OUT((TEXT("GetObjectTwinHandle(): %s\\%s is an object twin."),
  2732. DebugGetPathString(hpath),
  2733. pcszName));
  2734. *phot = (HOBJECTTWIN)pot;
  2735. ASSERT(IS_VALID_HANDLE(*phot, OBJECTTWIN));
  2736. }
  2737. else
  2738. {
  2739. TRACE_OUT((TEXT("GetObjectTwinHandle(): %s\\%s is not an object twin."),
  2740. DebugGetPathString(hpath),
  2741. pcszName));
  2742. *phot = NULL;
  2743. }
  2744. }
  2745. DeletePath(hpath);
  2746. }
  2747. }
  2748. #ifdef EXPV
  2749. else
  2750. tr = TR_INVALID_PARAMETER;
  2751. #endif
  2752. DebugExitTWINRESULT(GetObjectTwinHandle, tr);
  2753. EndExclusiveBriefcaseAccess();
  2754. }
  2755. else
  2756. tr = TR_REENTERED;
  2757. return(tr);
  2758. }
  2759. /******************************************************************************
  2760. @doc SYNCENGAPI
  2761. @api TWINRESULT | IsOrphanObjectTwin | Determines whether or not an object twin
  2762. was added to the synchronization database through a call to AddObjectTwin().
  2763. @parm HOBJECTTWIN | hot | A handle to the object twin whose orphan status is to
  2764. be determined.
  2765. @parm PBOOL | pbIsOrphanObjectTwin | A pointer to a BOOL to be filled in with
  2766. TRUE if the object twin was added through AddObjectTwin().
  2767. *pbIsOrphanObjectTwin is only valid if TR_SUCCESS is returned.
  2768. @rdesc If the lookup was successful, TR_SUCCESS is returned. Otherwise, the
  2769. lookup was not successful, and the return value indicates the error that
  2770. occurred.
  2771. @comm If IsOrphanObjectTwin() is called with a valid handle to an object twin
  2772. that has been deleted, TR_DELETED_TWIN will be returned.
  2773. @xref AddObjectTwin
  2774. ******************************************************************************/
  2775. SYNCENGAPI TWINRESULT WINAPI IsOrphanObjectTwin(HOBJECTTWIN hot,
  2776. PBOOL pbIsOrphanObjectTwin)
  2777. {
  2778. TWINRESULT tr;
  2779. if (BeginExclusiveBriefcaseAccess())
  2780. {
  2781. DebugEntry(IsOrphanObjectTwin);
  2782. #ifdef EXPV
  2783. /* Verify parameters. */
  2784. if (IS_VALID_HANDLE(hot, OBJECTTWIN) &&
  2785. IS_VALID_WRITE_PTR(pbIsOrphanObjectTwin, BOOL))
  2786. #endif
  2787. {
  2788. /* Has this object twin been deleted? */
  2789. if (IsStubFlagClear(&(((POBJECTTWIN)(hot))->stub), STUB_FL_UNLINKED))
  2790. {
  2791. /* No. */
  2792. if (IsStubFlagSet(&(((POBJECTTWIN)hot)->stub), STUB_FL_FROM_OBJECT_TWIN))
  2793. {
  2794. *pbIsOrphanObjectTwin = TRUE;
  2795. TRACE_OUT((TEXT("IsOrphanObjectTwin(): Object twin %s\\%s is an orphan object twin."),
  2796. DebugGetPathString(((POBJECTTWIN)hot)->hpath),
  2797. GetString(((POBJECTTWIN)hot)->ptfParent->hsName)));
  2798. }
  2799. else
  2800. {
  2801. *pbIsOrphanObjectTwin = FALSE;
  2802. TRACE_OUT((TEXT("IsOrphanObjectTwin(): Object twin %s\\%s is not an orphan object twin."),
  2803. DebugGetPathString(((POBJECTTWIN)hot)->hpath),
  2804. GetString(((POBJECTTWIN)hot)->ptfParent->hsName)));
  2805. }
  2806. ASSERT(*pbIsOrphanObjectTwin ||
  2807. ((POBJECTTWIN)hot)->ulcSrcFolderTwins);
  2808. tr = TR_SUCCESS;
  2809. }
  2810. else
  2811. /* Yes. */
  2812. tr = TR_DELETED_TWIN;
  2813. }
  2814. #ifdef EXPV
  2815. else
  2816. tr = TR_INVALID_PARAMETER;
  2817. #endif
  2818. DebugExitTWINRESULT(IsOrphanObjectTwin, tr);
  2819. EndExclusiveBriefcaseAccess();
  2820. }
  2821. else
  2822. tr = TR_REENTERED;
  2823. return(tr);
  2824. }
  2825. /******************************************************************************
  2826. @doc SYNCENGAPI
  2827. @api TWINRESULT | CountSourceFolderTwins | Determines the number of folder
  2828. twins that generate an object twin.
  2829. @parm HOBJECTTWIN | hot | A handle to the object twin whose folder twin sources
  2830. are to be counted.
  2831. @parm PULONG | pulcSrcFolderTwins | A pointer to a ULONG to be filled in with
  2832. the number of folder twins that generate the object twin. *pulcSrcFolderTwins
  2833. is only valid if TR_SUCCESS is returned.
  2834. @rdesc If the lookup was successful, TR_SUCCESS is returned. Otherwise, the
  2835. lookup was not successful, and the return value indicates the error that
  2836. occurred.
  2837. @comm If CountSourceFolderTwins() is called with a valid handle to a folder
  2838. twin that has been deleted, TR_DELETED_TWIN will be returned.
  2839. @xref AddFolderTwin
  2840. ******************************************************************************/
  2841. SYNCENGAPI TWINRESULT WINAPI CountSourceFolderTwins(HOBJECTTWIN hot,
  2842. PULONG pulcSrcFolderTwins)
  2843. {
  2844. TWINRESULT tr;
  2845. if (BeginExclusiveBriefcaseAccess())
  2846. {
  2847. DebugEntry(CountSourceFolderTwins);
  2848. #ifdef EXPV
  2849. /* Verify parameters. */
  2850. if (IS_VALID_HANDLE(hot, OBJECTTWIN) &&
  2851. IS_VALID_WRITE_PTR(pulcSrcFolderTwins, ULONG))
  2852. #endif
  2853. {
  2854. /* Has this object twin been deleted? */
  2855. if (IsStubFlagClear(&(((POBJECTTWIN)(hot))->stub), STUB_FL_UNLINKED))
  2856. {
  2857. /* No. */
  2858. *pulcSrcFolderTwins = ((POBJECTTWIN)hot)->ulcSrcFolderTwins;
  2859. ASSERT(*pulcSrcFolderTwins > 0 ||
  2860. IsStubFlagSet(&(((POBJECTTWIN)hot)->stub), STUB_FL_FROM_OBJECT_TWIN));
  2861. TRACE_OUT((TEXT("CountSourceFolderTwins(): Object twin %s\\%s has %lu source folder twins."),
  2862. DebugGetPathString(((POBJECTTWIN)hot)->hpath),
  2863. GetString(((POBJECTTWIN)hot)->ptfParent->hsName),
  2864. *pulcSrcFolderTwins));
  2865. tr = TR_SUCCESS;
  2866. }
  2867. else
  2868. /* Yes. */
  2869. tr = TR_DELETED_TWIN;
  2870. }
  2871. #ifdef EXPV
  2872. else
  2873. tr = TR_INVALID_PARAMETER;
  2874. #endif
  2875. DebugExitTWINRESULT(CountSourceFolderTwins, tr);
  2876. EndExclusiveBriefcaseAccess();
  2877. }
  2878. else
  2879. tr = TR_REENTERED;
  2880. return(tr);
  2881. }
  2882. /******************************************************************************
  2883. @doc SYNCENGAPI
  2884. @api BOOL | AnyTwins | Determines whether or not any twins currently exist in a
  2885. briefcase.
  2886. @parm HBRFCASE | hbr | A handle to the open briefcase to be checked for twins.
  2887. @parm PBOOL | pbAnyTwins | A pointer to a BOOL to be filled in with TRUE if
  2888. the given briefcase contains any twins or FALSE if not. *pbAnyTwins is only
  2889. valid if TR_SUCCESS is returned.
  2890. @rdesc If the lookup was successful, TR_SUCCESS is returned. Otherwise, the
  2891. lookup was not successful, and the return value indicates the error that
  2892. occurred.
  2893. ******************************************************************************/
  2894. SYNCENGAPI TWINRESULT WINAPI AnyTwins(HBRFCASE hbr, PBOOL pbAnyTwins)
  2895. {
  2896. TWINRESULT tr;
  2897. if (BeginExclusiveBriefcaseAccess())
  2898. {
  2899. DebugEntry(AnyTwins);
  2900. #ifdef EXPV
  2901. /* Verify parameters. */
  2902. if (IS_VALID_HANDLE(hbr, BRFCASE) &&
  2903. IS_VALID_WRITE_PTR(pbAnyTwins, BOOL))
  2904. #endif
  2905. {
  2906. if (GetPtrCount(GetBriefcaseTwinFamilyPtrArray(hbr)) ||
  2907. GetPtrCount(GetBriefcaseFolderPairPtrArray(hbr)))
  2908. {
  2909. *pbAnyTwins = TRUE;
  2910. TRACE_OUT((TEXT("AnyTwins(): There are twins in briefcase %#lx."),
  2911. hbr));
  2912. }
  2913. else
  2914. {
  2915. *pbAnyTwins = FALSE;
  2916. TRACE_OUT((TEXT("AnyTwins(): There are not any twins in briefcase %#lx."),
  2917. hbr));
  2918. }
  2919. tr = TR_SUCCESS;
  2920. }
  2921. #ifdef EXPV
  2922. else
  2923. tr = TR_INVALID_PARAMETER;
  2924. #endif
  2925. DebugExitTWINRESULT(AnyTwins, tr);
  2926. EndExclusiveBriefcaseAccess();
  2927. }
  2928. else
  2929. tr = TR_REENTERED;
  2930. return(tr);
  2931. }