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.

1471 lines
38 KiB

  1. /*
  2. * expandft.c - Routines for expanding folder twins to object twins.
  3. */
  4. /* Headers
  5. **********/
  6. #include "project.h"
  7. #pragma hdrstop
  8. #include "stub.h"
  9. /* Constants
  10. ************/
  11. /* for subtree folder searching */
  12. #define STAR_DOT_STAR TEXT("*.*")
  13. /* Macros
  14. *********/
  15. /* name component macros used by NameComponentsIntersect() */
  16. #define COMPONENT_CHARS_MATCH(ch1, ch2) (CharLower((PTSTR)(DWORD_PTR)ch1) == CharLower((PTSTR)(DWORD_PTR)ch2) || (ch1) == QMARK || (ch2) == QMARK)
  17. #define IS_COMPONENT_TERMINATOR(ch) (! (ch) || (ch) == PERIOD || (ch) == ASTERISK)
  18. /* Types
  19. ********/
  20. /* find structure used by ExpandSubtree() */
  21. typedef struct _findstate
  22. {
  23. HANDLE hff;
  24. WIN32_FIND_DATA wfd;
  25. }
  26. FINDSTATE;
  27. DECLARE_STANDARD_TYPES(FINDSTATE);
  28. /* information structure passed to GenerateObjectTwinFromFolderTwinProc() */
  29. typedef struct _expandsubtreetwininfo
  30. {
  31. PFOLDERPAIR pfp;
  32. UINT ucbSubtreeRootPathLen;
  33. HCLSIFACECACHE hcic;
  34. CREATERECLISTPROC crlp;
  35. LPARAM lpCallbackData;
  36. TWINRESULT tr;
  37. }
  38. EXPANDSUBTREETWININFO;
  39. DECLARE_STANDARD_TYPES(EXPANDSUBTREETWININFO);
  40. /* Module Variables
  41. *******************/
  42. /*
  43. * folder names to be avoided during subtree expansion (comparison is
  44. * case-insensitive)
  45. */
  46. PRIVATE_DATA CONST LPCTSTR MrgcpcszFoldersToAvoid[] =
  47. {
  48. TEXT("."),
  49. TEXT("..")
  50. };
  51. /***************************** Private Functions *****************************/
  52. /* Module Prototypes
  53. ********************/
  54. PRIVATE_CODE BOOL SetObjectTwinFileStamp(POBJECTTWIN, PVOID);
  55. PRIVATE_CODE void MarkFolderTwinDeletionPending(PFOLDERPAIR);
  56. PRIVATE_CODE void UnmarkFolderTwinDeletionPending(PFOLDERPAIR);
  57. PRIVATE_CODE TWINRESULT ExpandFolderTwin(PFOLDERPAIR, HCLSIFACECACHE, CREATERECLISTPROC, LPARAM);
  58. PRIVATE_CODE BOOL GenerateObjectTwinFromFolderTwinProc(LPCTSTR, PCWIN32_FIND_DATA, PVOID);
  59. PRIVATE_CODE TWINRESULT ExpandSubtreeTwin(PFOLDERPAIR, HCLSIFACECACHE, CREATERECLISTPROC, LPARAM);
  60. PRIVATE_CODE BOOL IsFolderToExpand(LPCTSTR);
  61. PRIVATE_CODE TWINRESULT FakeObjectTwinFromFolderTwin(PCFOLDERPAIR, LPCTSTR, LPCTSTR, HCLSIFACECACHE, POBJECTTWIN *, POBJECTTWIN *);
  62. PRIVATE_CODE TWINRESULT AddFolderObjectTwinFromFolderTwin(PCFOLDERPAIR, LPCTSTR, HCLSIFACECACHE);
  63. PRIVATE_CODE TWINRESULT AddFileObjectTwinFromFolderTwin(PCFOLDERPAIR, LPCTSTR, PCWIN32_FIND_DATA, HCLSIFACECACHE);
  64. PRIVATE_CODE BOOL NameComponentsIntersect(LPCTSTR, LPCTSTR);
  65. PRIVATE_CODE BOOL AttributesMatch(DWORD, DWORD);
  66. PRIVATE_CODE void PrepareForFolderTwinExpansion(HBRFCASE);
  67. PRIVATE_CODE TWINRESULT MyExpandIntersectingFolderTwins(PFOLDERPAIR, HCLSIFACECACHE, CREATERECLISTPROC, LPARAM);
  68. PRIVATE_CODE TWINRESULT HalfExpandIntersectingFolderTwins(PFOLDERPAIR, HCLSIFACECACHE, CREATERECLISTPROC, LPARAM);
  69. #ifdef DEBUG
  70. PRIVATE_CODE BOOL IsValidPCEXPANDSUBTREETWININFO(PCEXPANDSUBTREETWININFO);
  71. #endif
  72. /*
  73. ** SetObjectTwinFileStampCondition()
  74. **
  75. **
  76. **
  77. ** Arguments:
  78. **
  79. ** Returns:
  80. **
  81. ** Side Effects: none
  82. */
  83. PRIVATE_CODE BOOL SetObjectTwinFileStampCondition(POBJECTTWIN pot,
  84. PVOID fscond)
  85. {
  86. ASSERT(IS_VALID_STRUCT_PTR(pot, COBJECTTWIN));
  87. ASSERT(IsValidFILESTAMPCONDITION((FILESTAMPCONDITION)PtrToUlong(fscond)));
  88. ZeroMemory(&(pot->fsCurrent), sizeof(pot->fsCurrent));
  89. pot->fsCurrent.fscond = (FILESTAMPCONDITION)PtrToUlong(fscond);
  90. SetStubFlag(&(pot->stub), STUB_FL_FILE_STAMP_VALID);
  91. return(TRUE);
  92. }
  93. /*
  94. ** MarkFolderTwinDeletionPending()
  95. **
  96. **
  97. **
  98. ** Arguments:
  99. **
  100. ** Returns:
  101. **
  102. ** Side Effects: none
  103. */
  104. PRIVATE_CODE void MarkFolderTwinDeletionPending(PFOLDERPAIR pfp)
  105. {
  106. ASSERT(IS_VALID_STRUCT_PTR(pfp, CFOLDERPAIR));
  107. if (IsStubFlagClear(&(pfp->stub), STUB_FL_DELETION_PENDING))
  108. {
  109. TCHAR rgchRootPath[MAX_PATH_LEN];
  110. GetPathRootString(pfp->hpath, rgchRootPath, ARRAYSIZE(rgchRootPath));
  111. if (PathExists(rgchRootPath))
  112. {
  113. SetStubFlag(&(pfp->stub), STUB_FL_DELETION_PENDING);
  114. TRACE_OUT((TEXT("MarkFolderTwinDeletionPending(): Folder twin deletion pending for deleted folder %s."),
  115. DebugGetPathString(pfp->hpath)));
  116. }
  117. else
  118. WARNING_OUT((TEXT("MarkFolderTwinDeletionPending(): Root path %s of folder %s does not exist."),
  119. rgchRootPath,
  120. DebugGetPathString(pfp->hpath)));
  121. }
  122. return;
  123. }
  124. /*
  125. ** UnmarkFolderTwinDeletionPending()
  126. **
  127. **
  128. **
  129. ** Arguments:
  130. **
  131. ** Returns:
  132. **
  133. ** Side Effects: none
  134. */
  135. PRIVATE_CODE void UnmarkFolderTwinDeletionPending(PFOLDERPAIR pfp)
  136. {
  137. ASSERT(IS_VALID_STRUCT_PTR(pfp, CFOLDERPAIR));
  138. if (IsStubFlagSet(&(pfp->stub), STUB_FL_DELETION_PENDING))
  139. WARNING_OUT((TEXT("UnmarkFolderTwinDeletionPending(): Folder twin %s was deleted but has been recreated."),
  140. DebugGetPathString(pfp->hpath)));
  141. ClearStubFlag(&(pfp->stub), STUB_FL_DELETION_PENDING);
  142. return;
  143. }
  144. /*
  145. ** ExpandFolderTwin()
  146. **
  147. ** Expands a single folder of half of a folder pair into object twins.
  148. **
  149. ** Arguments: pfp - pointer to folder pair whose folder is to be expanded
  150. **
  151. ** Returns: TWINRESULT
  152. **
  153. ** Side Effects: none
  154. */
  155. PRIVATE_CODE TWINRESULT ExpandFolderTwin(PFOLDERPAIR pfp, HCLSIFACECACHE hcic,
  156. CREATERECLISTPROC crlp,
  157. LPARAM lpCallbackData)
  158. {
  159. TWINRESULT tr = TR_SUCCESS;
  160. TCHAR rgchSearchSpec[MAX_PATH_LEN];
  161. /* lpCallbackData may be any value. */
  162. ASSERT(IS_VALID_STRUCT_PTR(pfp, CFOLDERPAIR));
  163. ASSERT(IS_VALID_HANDLE(hcic, CLSIFACECACHE));
  164. ASSERT(! crlp ||
  165. IS_VALID_CODE_PTR(crlp, CREATERECLISTPROC));
  166. ASSERT(IsPathVolumeAvailable(pfp->hpath));
  167. ASSERT(IsStubFlagClear(&(pfp->stub), STUB_FL_SUBTREE));
  168. ASSERT(IsStubFlagClear(&(pfp->stub), STUB_FL_USED));
  169. /* Build search specification. */
  170. GetPathString(pfp->hpath, rgchSearchSpec, ARRAYSIZE(rgchSearchSpec));
  171. if (PathExists(rgchSearchSpec))
  172. {
  173. WIN32_FIND_DATA wfd;
  174. HANDLE hff;
  175. UnmarkFolderTwinDeletionPending(pfp);
  176. TRACE_OUT((TEXT("ExpandFolderTwin(): Expanding folder %s for objects matching %s."),
  177. rgchSearchSpec,
  178. GetString(pfp->pfpd->hsName)));
  179. tr = AddFolderObjectTwinFromFolderTwin(pfp, EMPTY_STRING, hcic);
  180. if (tr == TR_SUCCESS)
  181. {
  182. CatPath(rgchSearchSpec, GetString(pfp->pfpd->hsName), ARRAYSIZE(rgchSearchSpec));
  183. hff = FindFirstFile(rgchSearchSpec, &wfd);
  184. /* Did we find a matching object? */
  185. if (hff != INVALID_HANDLE_VALUE)
  186. {
  187. /* Yes. */
  188. do
  189. {
  190. /* Ping. */
  191. if (NotifyCreateRecListStatus(crlp, CRLS_DELTA_CREATE_REC_LIST,
  192. 0, lpCallbackData))
  193. {
  194. if (AttributesMatch(pfp->pfpd->dwAttributes,
  195. wfd.dwFileAttributes))
  196. {
  197. TRACE_OUT((TEXT("ExpandFolderTwin(): Found matching object %s."),
  198. &(wfd.cFileName)));
  199. tr = AddFileObjectTwinFromFolderTwin(pfp, EMPTY_STRING,
  200. &wfd, hcic);
  201. if (tr != TR_SUCCESS)
  202. break;
  203. }
  204. }
  205. else
  206. tr = TR_ABORT;
  207. } while (FindNextFile(hff, &wfd));
  208. }
  209. if (hff != INVALID_HANDLE_VALUE)
  210. FindClose(hff);
  211. }
  212. TRACE_OUT((TEXT("ExpandFolderTwin(): Folder expansion complete.")));
  213. }
  214. else
  215. MarkFolderTwinDeletionPending(pfp);
  216. return(tr);
  217. }
  218. /*
  219. ** GenerateObjectTwinFromFolderTwinProc()
  220. **
  221. **
  222. **
  223. ** Arguments:
  224. **
  225. ** Returns:
  226. **
  227. ** Side Effects: none
  228. */
  229. PRIVATE_CODE BOOL GenerateObjectTwinFromFolderTwinProc(LPCTSTR pcszFolder,
  230. PCWIN32_FIND_DATA pcwfd,
  231. PVOID pvpesti)
  232. {
  233. TWINRESULT tr;
  234. PEXPANDSUBTREETWININFO pesti = pvpesti;
  235. ASSERT(IsCanonicalPath(pcszFolder));
  236. ASSERT(IS_VALID_READ_PTR(pcwfd, CWIN32_FIND_DATA));
  237. ASSERT(IS_VALID_STRUCT_PTR(pesti, CEXPANDSUBTREETWININFO));
  238. /* Ping. */
  239. if (NotifyCreateRecListStatus(pesti->crlp, CRLS_DELTA_CREATE_REC_LIST, 0,
  240. pesti->lpCallbackData))
  241. {
  242. if (IS_ATTR_DIR(pcwfd->dwFileAttributes))
  243. {
  244. TCHAR rgchFolder[MAX_PATH_LEN];
  245. /* Add any folder as a folder object twin. */
  246. ComposePath(rgchFolder, pcszFolder, pcwfd->cFileName, ARRAYSIZE(rgchFolder));
  247. ASSERT(lstrlen(rgchFolder) < ARRAYSIZE(rgchFolder));
  248. tr = AddFolderObjectTwinFromFolderTwin(
  249. pesti->pfp,
  250. rgchFolder + (pesti->ucbSubtreeRootPathLen / sizeof(TCHAR)),
  251. pesti->hcic);
  252. }
  253. else
  254. {
  255. /* Does this file match the requested attributes? */
  256. if (NamesIntersect(pcwfd->cFileName,
  257. GetString(pesti->pfp->pfpd->hsName)) &&
  258. AttributesMatch(pesti->pfp->pfpd->dwAttributes,
  259. pcwfd->dwFileAttributes))
  260. {
  261. /* Yes. Twin it. */
  262. TRACE_OUT((TEXT("GenerateObjectTwinFromFolderTwinProc(): Found matching object %s in subfolder %s."),
  263. pcwfd->cFileName,
  264. pcszFolder));
  265. tr = AddFileObjectTwinFromFolderTwin(
  266. pesti->pfp,
  267. pcszFolder + (pesti->ucbSubtreeRootPathLen / sizeof(TCHAR)),
  268. pcwfd, pesti->hcic);
  269. }
  270. else
  271. {
  272. TRACE_OUT((TEXT("GenerateObjectTwinFromFolderTwinProc(): Skipping unmatched object %s in subfolder %s."),
  273. pcwfd->cFileName,
  274. pcszFolder));
  275. tr = TR_SUCCESS;
  276. }
  277. }
  278. }
  279. else
  280. tr = TR_ABORT;
  281. pesti->tr = tr;
  282. ASSERT(IS_VALID_STRUCT_PTR(pvpesti, CEXPANDSUBTREETWININFO));
  283. return(tr == TR_SUCCESS);
  284. }
  285. /*
  286. ** ExpandSubtreeTwin()
  287. **
  288. **
  289. **
  290. ** Arguments:
  291. **
  292. ** Returns:
  293. **
  294. ** Side Effects: none
  295. */
  296. PRIVATE_CODE TWINRESULT ExpandSubtreeTwin(PFOLDERPAIR pfp, HCLSIFACECACHE hcic,
  297. CREATERECLISTPROC crlp,
  298. LPARAM lpCallbackData)
  299. {
  300. TWINRESULT tr = TR_SUCCESS;
  301. TCHAR rgchPath[MAX_PATH_LEN];
  302. /* lpCallbackData may be any value. */
  303. ASSERT(IS_VALID_STRUCT_PTR(pfp, CFOLDERPAIR));
  304. ASSERT(IS_VALID_HANDLE(hcic, CLSIFACECACHE));
  305. ASSERT(! crlp ||
  306. IS_VALID_CODE_PTR(crlp, CREATERECLISTPROC));
  307. ASSERT(IsPathVolumeAvailable(pfp->hpath));
  308. ASSERT(IsStubFlagSet(&(pfp->stub), STUB_FL_SUBTREE));
  309. ASSERT(IsStubFlagClear(&(pfp->stub), STUB_FL_USED));
  310. GetPathString(pfp->hpath, rgchPath, ARRAYSIZE(rgchPath));
  311. if (PathExists(rgchPath))
  312. {
  313. UnmarkFolderTwinDeletionPending(pfp);
  314. tr = AddFolderObjectTwinFromFolderTwin(pfp, EMPTY_STRING, hcic);
  315. if (tr == TR_SUCCESS)
  316. {
  317. EXPANDSUBTREETWININFO esti;
  318. esti.pfp = pfp;
  319. esti.ucbSubtreeRootPathLen = lstrlen(rgchPath) * sizeof(TCHAR); // UNICODE really cb?
  320. esti.hcic = hcic;
  321. esti.crlp = crlp;
  322. esti.lpCallbackData = lpCallbackData;
  323. esti.tr = TR_SUCCESS;
  324. tr = ExpandSubtree(pfp->hpath, &GenerateObjectTwinFromFolderTwinProc,
  325. &esti);
  326. ASSERT(tr != TR_SUCCESS ||
  327. esti.tr == TR_SUCCESS);
  328. if (tr == TR_SUCCESS ||
  329. tr == TR_ABORT)
  330. tr = esti.tr;
  331. }
  332. }
  333. else
  334. MarkFolderTwinDeletionPending(pfp);
  335. return(tr);
  336. }
  337. /*
  338. ** IsFolderToExpand()
  339. **
  340. **
  341. **
  342. ** Arguments:
  343. **
  344. ** Returns: TWINRESULT
  345. **
  346. ** Side Effects: none
  347. */
  348. PRIVATE_CODE BOOL IsFolderToExpand(LPCTSTR pcszFolder)
  349. {
  350. BOOL bExpandMe = TRUE;
  351. int i;
  352. for (i = 0; i < ARRAY_ELEMENTS(MrgcpcszFoldersToAvoid); i++)
  353. {
  354. if (ComparePathStrings(pcszFolder, MrgcpcszFoldersToAvoid[i])
  355. == CR_EQUAL)
  356. {
  357. bExpandMe = FALSE;
  358. break;
  359. }
  360. }
  361. return(bExpandMe);
  362. }
  363. /*
  364. ** FakeObjectTwinFromFolderTwin()
  365. **
  366. **
  367. **
  368. ** Arguments:
  369. **
  370. ** Returns:
  371. **
  372. ** Side Effects: none
  373. */
  374. PRIVATE_CODE TWINRESULT FakeObjectTwinFromFolderTwin(PCFOLDERPAIR pcfp,
  375. LPCTSTR pcszSubPath,
  376. LPCTSTR pcszName,
  377. HCLSIFACECACHE hcic,
  378. POBJECTTWIN *ppot1,
  379. POBJECTTWIN *ppot2)
  380. {
  381. TWINRESULT tr = TR_OUT_OF_MEMORY;
  382. HPATHLIST hpl;
  383. HPATH hpath1;
  384. ASSERT(IS_VALID_STRUCT_PTR(pcfp, CFOLDERPAIR));
  385. ASSERT(IS_VALID_STRING_PTR(pcszSubPath, CSTR));
  386. ASSERT(IS_VALID_STRING_PTR(pcszName, CSTR));
  387. ASSERT(IS_VALID_HANDLE(hcic, CLSIFACECACHE));
  388. ASSERT(IS_VALID_WRITE_PTR(ppot1, POBJECTTWIN));
  389. ASSERT(IS_VALID_WRITE_PTR(ppot2, POBJECTTWIN));
  390. /* If the common sub path is non-empty, append it to the path strings. */
  391. hpl = GetBriefcasePathList(pcfp->pfpd->hbr);
  392. if (AddChildPath(hpl, pcfp->hpath, pcszSubPath, &hpath1))
  393. {
  394. HPATH hpath2;
  395. if (AddChildPath(hpl, pcfp->pfpOther->hpath, pcszSubPath, &hpath2))
  396. {
  397. /* Add the two object twins. */
  398. tr = TwinObjects(pcfp->pfpd->hbr, hcic, hpath1, hpath2, pcszName,
  399. ppot1, ppot2);
  400. DeletePath(hpath2);
  401. }
  402. DeletePath(hpath1);
  403. }
  404. return(tr);
  405. }
  406. /*
  407. ** AddFolderObjectTwinFromFolderTwin()
  408. **
  409. **
  410. **
  411. ** Arguments:
  412. **
  413. ** Returns:
  414. **
  415. ** Side Effects: none
  416. */
  417. PRIVATE_CODE TWINRESULT AddFolderObjectTwinFromFolderTwin(PCFOLDERPAIR pcfp,
  418. LPCTSTR pcszSubPath,
  419. HCLSIFACECACHE hcic)
  420. {
  421. TWINRESULT tr;
  422. POBJECTTWIN pot1;
  423. POBJECTTWIN pot2;
  424. ASSERT(IS_VALID_STRUCT_PTR(pcfp, CFOLDERPAIR));
  425. ASSERT(IS_VALID_STRING_PTR(pcszSubPath, CSTR));
  426. ASSERT(IS_VALID_HANDLE(hcic, CLSIFACECACHE));
  427. /* Add the two object twins. */
  428. tr = FakeObjectTwinFromFolderTwin(pcfp, pcszSubPath, EMPTY_STRING, hcic,
  429. &pot1, &pot2);
  430. /* An attempted redundant add is ok. */
  431. if (tr == TR_DUPLICATE_TWIN)
  432. tr = TR_SUCCESS;
  433. if (tr == TR_SUCCESS)
  434. /* Cache folder object twin file stamps. */
  435. SetObjectTwinFileStampCondition(pot1, IntToPtr(FS_COND_EXISTS));
  436. return(tr);
  437. }
  438. /*
  439. ** AddFileObjectTwinFromFolderTwin()
  440. **
  441. ** Adds a pair of object twins generated by a folder twin.
  442. **
  443. ** Arguments: pfp - pointer to folder pair that generated the two object
  444. ** twins
  445. ** pcszSubPath - common path off of folder pair roots describing
  446. ** object's location
  447. ** pcszName - name of object twins
  448. **
  449. ** Returns: TWINRESULT
  450. **
  451. ** Side Effects: none
  452. */
  453. PRIVATE_CODE TWINRESULT AddFileObjectTwinFromFolderTwin(PCFOLDERPAIR pcfp,
  454. LPCTSTR pcszSubPath,
  455. PCWIN32_FIND_DATA pcwfd,
  456. HCLSIFACECACHE hcic)
  457. {
  458. TWINRESULT tr;
  459. POBJECTTWIN pot1;
  460. POBJECTTWIN pot2;
  461. ASSERT(IS_VALID_STRUCT_PTR(pcfp, CFOLDERPAIR));
  462. ASSERT(IS_VALID_STRING_PTR(pcszSubPath, CSTR));
  463. ASSERT(IS_VALID_READ_PTR(pcwfd, CWIN32_FIND_DATA));
  464. ASSERT(IS_VALID_HANDLE(hcic, CLSIFACECACHE));
  465. /* Add the two object twins. */
  466. tr = FakeObjectTwinFromFolderTwin(pcfp, pcszSubPath, pcwfd->cFileName, hcic,
  467. &pot1, &pot2);
  468. /* An attempted redundant add is ok. */
  469. if (tr == TR_DUPLICATE_TWIN)
  470. tr = TR_SUCCESS;
  471. if (tr == TR_SUCCESS)
  472. {
  473. /* Cache object twin file stamp. */
  474. CopyFileStampFromFindData(pcwfd, &(pot1->fsCurrent));
  475. SetStubFlag(&(pot1->stub), STUB_FL_FILE_STAMP_VALID);
  476. }
  477. return(tr);
  478. }
  479. /*
  480. ** NameComponentsIntersect()
  481. **
  482. **
  483. **
  484. ** Arguments:
  485. **
  486. ** Returns:
  487. **
  488. ** Side Effects: none
  489. */
  490. PRIVATE_CODE BOOL NameComponentsIntersect(LPCTSTR pcszComponent1,
  491. LPCTSTR pcszComponent2)
  492. {
  493. BOOL bIntersect;
  494. ASSERT(IS_VALID_STRING_PTR(pcszComponent1, CSTR));
  495. ASSERT(IS_VALID_STRING_PTR(pcszComponent2, CSTR));
  496. while (! IS_COMPONENT_TERMINATOR(*pcszComponent1) && ! IS_COMPONENT_TERMINATOR(*pcszComponent2) &&
  497. COMPONENT_CHARS_MATCH(*pcszComponent1, *pcszComponent2))
  498. {
  499. pcszComponent1 = CharNext(pcszComponent1);
  500. pcszComponent2 = CharNext(pcszComponent2);
  501. }
  502. if (*pcszComponent1 == ASTERISK ||
  503. *pcszComponent2 == ASTERISK ||
  504. *pcszComponent1 == *pcszComponent2)
  505. bIntersect = TRUE;
  506. else
  507. {
  508. LPCTSTR pcszTrailer;
  509. if (! *pcszComponent1 || *pcszComponent1 == PERIOD)
  510. pcszTrailer = pcszComponent2;
  511. else
  512. pcszTrailer = pcszComponent1;
  513. while (*pcszTrailer == QMARK)
  514. pcszTrailer++;
  515. if (IS_COMPONENT_TERMINATOR(*pcszTrailer))
  516. bIntersect = TRUE;
  517. else
  518. bIntersect = FALSE;
  519. }
  520. return(bIntersect);
  521. }
  522. /*
  523. ** AttributesMatch()
  524. **
  525. **
  526. **
  527. ** Arguments:
  528. **
  529. ** Returns:
  530. **
  531. ** Side Effects: none
  532. **
  533. ** An object's attributes match the master attributes iff the object's
  534. ** attributes do not contain any set bits that are not also set in the master
  535. ** attributes.
  536. */
  537. PRIVATE_CODE BOOL AttributesMatch(DWORD dwMasterAttributes,
  538. DWORD dwObjectAttributes)
  539. {
  540. // We don't consider a difference in compression to be enough to call
  541. // the file different, especially since that attribute is impossible
  542. // to reconcile in some cases.
  543. dwObjectAttributes &= ~(FILE_ATTRIBUTE_COMPRESSED);
  544. return(! (dwObjectAttributes & (~dwMasterAttributes)));
  545. }
  546. /*
  547. ** PrepareForFolderTwinExpansion()
  548. **
  549. **
  550. **
  551. ** Arguments:
  552. **
  553. ** Returns: void
  554. **
  555. ** Side Effects: none
  556. **
  557. ** N.b., this function should be called before the outermost call to
  558. ** MyExpandIntersectingFolderTwins().
  559. */
  560. PRIVATE_CODE void PrepareForFolderTwinExpansion(HBRFCASE hbr)
  561. {
  562. ASSERT(IS_VALID_HANDLE(hbr, BRFCASE));
  563. ClearFlagInArrayOfStubs(GetBriefcaseFolderPairPtrArray(hbr), STUB_FL_USED);
  564. EVAL(EnumObjectTwins(hbr,
  565. (ENUMGENERATEDOBJECTTWINSPROC)&ClearStubFlagWrapper,
  566. IntToPtr(STUB_FL_FILE_STAMP_VALID)));
  567. return;
  568. }
  569. /*
  570. ** MyExpandIntersectingFolderTwins()
  571. **
  572. ** Expands all folder twins intersecting a pair of folder twins.
  573. **
  574. ** Arguments:
  575. **
  576. ** Returns: TWINRESULT
  577. **
  578. ** Side Effects: Marks expanded folder pairs used.
  579. **
  580. ** N.b., PrepareForFolderTwinExpansion(pfp->pfpd->hbr) should be called before
  581. ** the first time this function is called.
  582. */
  583. PRIVATE_CODE TWINRESULT MyExpandIntersectingFolderTwins(PFOLDERPAIR pfp,
  584. HCLSIFACECACHE hcic,
  585. CREATERECLISTPROC crlp,
  586. LPARAM lpCallbackData)
  587. {
  588. TWINRESULT tr;
  589. /* lpCallbackData may be any value. */
  590. ASSERT(IS_VALID_STRUCT_PTR(pfp, CFOLDERPAIR));
  591. ASSERT(IS_VALID_HANDLE(hcic, CLSIFACECACHE));
  592. ASSERT(! crlp ||
  593. IS_VALID_CODE_PTR(crlp, CREATERECLISTPROC));
  594. /*
  595. * N.b., pfp may already be marked used here, but may intersect folder twins
  596. * that have not yet been expanded.
  597. */
  598. tr = HalfExpandIntersectingFolderTwins(pfp, hcic, crlp, lpCallbackData);
  599. if (tr == TR_SUCCESS)
  600. {
  601. ASSERT(IsStubFlagSet(&(pfp->stub), STUB_FL_USED));
  602. tr = HalfExpandIntersectingFolderTwins(pfp->pfpOther, hcic, crlp,
  603. lpCallbackData);
  604. }
  605. return(tr);
  606. }
  607. /*
  608. ** HalfExpandIntersectingFolderTwins()
  609. **
  610. ** Expands all folder twins intersecting one half of a pair of folder twins.
  611. **
  612. ** Arguments:
  613. **
  614. ** Returns: TWINRESULT
  615. **
  616. ** Side Effects: Marks expanded folder pairs used.
  617. **
  618. ** N.b., this function is only meant to be called from
  619. ** MyExpandIntersectingFolderTwins().
  620. */
  621. PRIVATE_CODE TWINRESULT HalfExpandIntersectingFolderTwins(
  622. PFOLDERPAIR pfp,
  623. HCLSIFACECACHE hcic,
  624. CREATERECLISTPROC crlp,
  625. LPARAM lpCallbackData)
  626. {
  627. TWINRESULT tr = TR_SUCCESS;
  628. /* lpCallbackData may be any value. */
  629. ASSERT(IS_VALID_STRUCT_PTR(pfp, CFOLDERPAIR));
  630. ASSERT(IS_VALID_HANDLE(hcic, CLSIFACECACHE));
  631. ASSERT(! crlp ||
  632. IS_VALID_CODE_PTR(crlp, CREATERECLISTPROC));
  633. if (IsStubFlagClear(&(pfp->stub), STUB_FL_UNLINKED))
  634. {
  635. BOOL bArgIsSubtree;
  636. HPTRARRAY hpaFolderPairs;
  637. ARRAYINDEX ai;
  638. ARRAYINDEX aicFolderPairs;
  639. bArgIsSubtree = IsStubFlagSet(&(pfp->stub), STUB_FL_SUBTREE);
  640. hpaFolderPairs = GetBriefcaseFolderPairPtrArray(pfp->pfpd->hbr);
  641. aicFolderPairs = GetPtrCount(hpaFolderPairs);
  642. for (ai = 0; ai < aicFolderPairs; ai++)
  643. {
  644. PFOLDERPAIR pfpCur;
  645. pfpCur = (PFOLDERPAIR)GetPtr(hpaFolderPairs, ai);
  646. ASSERT(IS_VALID_STRUCT_PTR(pfpCur, CFOLDERPAIR));
  647. if (IsStubFlagClear(&(pfpCur->stub), STUB_FL_USED) &&
  648. NamesIntersect(GetString(pfp->pfpd->hsName),
  649. GetString(pfpCur->pfpd->hsName)))
  650. {
  651. BOOL bCurIsSubtree;
  652. BOOL bExpand = FALSE;
  653. bCurIsSubtree = IsStubFlagSet(&(pfpCur->stub), STUB_FL_SUBTREE);
  654. if (bCurIsSubtree)
  655. {
  656. if (bArgIsSubtree)
  657. bExpand = SubtreesIntersect(pfp->hpath, pfpCur->hpath);
  658. else
  659. bExpand = IsPathPrefix(pfp->hpath, pfpCur->hpath);
  660. }
  661. else
  662. {
  663. if (bArgIsSubtree)
  664. bExpand = IsPathPrefix(pfpCur->hpath, pfp->hpath);
  665. else
  666. bExpand = (ComparePaths(pfp->hpath, pfpCur->hpath) == CR_EQUAL);
  667. }
  668. /* Expand folder twin and mark it used. */
  669. if (bExpand)
  670. {
  671. /*
  672. * Mark all generated object twins as non-existent or unavailable.
  673. * Expand available folder twin.
  674. */
  675. if (IsPathVolumeAvailable(pfp->hpath))
  676. {
  677. EVAL(EnumGeneratedObjectTwins(pfp,
  678. &SetObjectTwinFileStampCondition,
  679. IntToPtr(FS_COND_DOES_NOT_EXIST)));
  680. if (bCurIsSubtree)
  681. tr = ExpandSubtreeTwin(pfpCur, hcic, crlp, lpCallbackData);
  682. else
  683. tr = ExpandFolderTwin(pfpCur, hcic, crlp, lpCallbackData);
  684. if (tr != TR_SUCCESS)
  685. break;
  686. }
  687. else
  688. {
  689. EVAL(EnumGeneratedObjectTwins(pfp, &SetObjectTwinFileStampCondition,
  690. IntToPtr(FS_COND_UNAVAILABLE)));
  691. WARNING_OUT((TEXT("HalfExpandIntersectingFolderTwins(): Unavailable folder %s skipped."),
  692. DebugGetPathString(pfp->hpath)));
  693. }
  694. SetStubFlag(&(pfp->stub), STUB_FL_USED);
  695. }
  696. }
  697. }
  698. }
  699. return(tr);
  700. }
  701. #ifdef DEBUG
  702. /*
  703. ** IsValidPCEXPANDSUBTREETWININFO()
  704. **
  705. **
  706. **
  707. ** Arguments:
  708. **
  709. ** Returns:
  710. **
  711. ** Side Effects: none
  712. */
  713. PRIVATE_CODE BOOL IsValidPCEXPANDSUBTREETWININFO(PCEXPANDSUBTREETWININFO pcesi)
  714. {
  715. /* lpCallbackData may be any value. */
  716. return(IS_VALID_READ_PTR(pcesi, CEXPANDSUBTREETWININFO) &&
  717. IS_VALID_STRUCT_PTR(pcesi->pfp, CFOLDERPAIR) &&
  718. EVAL(pcesi->ucbSubtreeRootPathLen > 0) &&
  719. IS_VALID_HANDLE(pcesi->hcic, CLSIFACECACHE) &&
  720. IsValidTWINRESULT(pcesi->tr));
  721. }
  722. #endif
  723. /****************************** Public Functions *****************************/
  724. /*
  725. ** ExpandSubtree()
  726. **
  727. **
  728. **
  729. ** Arguments:
  730. **
  731. ** Returns: TWINRESULT
  732. **
  733. ** Side Effects: none
  734. */
  735. PUBLIC_CODE TWINRESULT ExpandSubtree(HPATH hpathRoot, EXPANDSUBTREEPROC esp,
  736. PVOID pvRefData)
  737. {
  738. TWINRESULT tr;
  739. PFINDSTATE pfs;
  740. /* pvRefData may be any value. */
  741. ASSERT(IS_VALID_HANDLE(hpathRoot, PATH));
  742. ASSERT(IS_VALID_CODE_PTR(esp, EXPANDSUBTREEPROC));
  743. ASSERT(IsPathVolumeAvailable(hpathRoot));
  744. if (AllocateMemory(MAX_FOLDER_DEPTH * sizeof(pfs[0]), &pfs))
  745. {
  746. /* Copy subtree root folder to beginning of search path buffer. */
  747. TCHAR rgchSearchSpec[MAX_PATH_LEN];
  748. LPTSTR pszPathSuffix;
  749. int iFind;
  750. LPTSTR pszStartOfSubPath;
  751. BOOL bFound;
  752. #ifdef DEBUG
  753. /* Are we leaking WIN32_FIND_DATA structures? */
  754. ULONG ulcOpenFinds = 0;
  755. #endif
  756. rgchSearchSpec[0] = TEXT('\0');
  757. GetPathRootString(hpathRoot, rgchSearchSpec, ARRAYSIZE(rgchSearchSpec));
  758. pszPathSuffix = rgchSearchSpec + lstrlen(rgchSearchSpec);
  759. GetPathSuffixString(hpathRoot, pszPathSuffix);
  760. pszStartOfSubPath = rgchSearchSpec + lstrlen(rgchSearchSpec);
  761. TRACE_OUT((TEXT("ExpandSubtree(): Expanding subtree rooted at %s."),
  762. rgchSearchSpec));
  763. /* Append *.* file specification. */
  764. CatPath(rgchSearchSpec, STAR_DOT_STAR, ARRAYSIZE(rgchSearchSpec));
  765. /* Begin search at subtree root. */
  766. iFind = 0;
  767. pfs[iFind].hff = FindFirstFile(rgchSearchSpec, &(pfs[iFind].wfd));
  768. #ifdef DEBUG
  769. if (pfs[iFind].hff != INVALID_HANDLE_VALUE)
  770. ulcOpenFinds++;
  771. #endif
  772. bFound = (pfs[iFind].hff != INVALID_HANDLE_VALUE);
  773. /* Rip off *.*. */
  774. DeleteLastPathElement(pszPathSuffix);
  775. /* Search subtree depth first. */
  776. tr = TR_SUCCESS;
  777. while (bFound && tr == TR_SUCCESS)
  778. {
  779. /* Did we find a directory to expand? */
  780. if (IS_ATTR_DIR(pfs[iFind].wfd.dwFileAttributes))
  781. {
  782. if (IsFolderToExpand(pfs[iFind].wfd.cFileName))
  783. {
  784. /* Yes. Dive down into it. */
  785. /* Append the new directory to the current search path. */
  786. CatPath(rgchSearchSpec, pfs[iFind].wfd.cFileName, ARRAYSIZE(rgchSearchSpec));
  787. TRACE_OUT((TEXT("ExpandSubtree(): Diving into subfolder %s."),
  788. rgchSearchSpec));
  789. /* Append *.* file specification. */
  790. CatPath(rgchSearchSpec, STAR_DOT_STAR, ARRAYSIZE(rgchSearchSpec));
  791. /* Start search in the new directory. */
  792. ASSERT(iFind < INT_MAX);
  793. iFind++;
  794. pfs[iFind].hff = FindFirstFile(rgchSearchSpec, &(pfs[iFind].wfd));
  795. bFound = (pfs[iFind].hff != INVALID_HANDLE_VALUE);
  796. #ifdef DEBUG
  797. if (bFound)
  798. ulcOpenFinds++;
  799. #endif
  800. /* Rip off *.*. */
  801. DeleteLastPathElement(pszPathSuffix);
  802. }
  803. else
  804. /* Continue search in this directory. */
  805. bFound = FindNextFile(pfs[iFind].hff, &(pfs[iFind].wfd));
  806. }
  807. else
  808. {
  809. /* Found a file. */
  810. TRACE_OUT((TEXT("ExpandSubtree(): Found file %s\\%s."),
  811. rgchSearchSpec,
  812. pfs[iFind].wfd.cFileName));
  813. if ((*esp)(rgchSearchSpec, &(pfs[iFind].wfd), pvRefData))
  814. bFound = FindNextFile(pfs[iFind].hff, &(pfs[iFind].wfd));
  815. else
  816. tr = TR_ABORT;
  817. }
  818. if (tr == TR_SUCCESS)
  819. {
  820. while (! bFound)
  821. {
  822. /* Find failed. Climb back up one directory level. */
  823. if (pfs[iFind].hff != INVALID_HANDLE_VALUE)
  824. {
  825. FindClose(pfs[iFind].hff);
  826. #ifdef DEBUG
  827. ulcOpenFinds--;
  828. #endif
  829. }
  830. if (iFind > 0)
  831. {
  832. DeleteLastPathElement(pszPathSuffix);
  833. iFind--;
  834. if (IsFolderToExpand(pfs[iFind].wfd.cFileName))
  835. {
  836. TRACE_OUT((TEXT("ExpandSubtree(): Found folder %s\\%s."),
  837. rgchSearchSpec,
  838. pfs[iFind].wfd.cFileName));
  839. if (! (*esp)(rgchSearchSpec, &(pfs[iFind].wfd), pvRefData))
  840. {
  841. tr = TR_ABORT;
  842. break;
  843. }
  844. }
  845. bFound = FindNextFile(pfs[iFind].hff, &(pfs[iFind].wfd));
  846. }
  847. else
  848. {
  849. ASSERT(! iFind);
  850. break;
  851. }
  852. }
  853. }
  854. }
  855. if (tr != TR_SUCCESS)
  856. {
  857. /* Close all open find operations on failure. */
  858. while (iFind >= 0)
  859. {
  860. if (pfs[iFind].hff != INVALID_HANDLE_VALUE)
  861. {
  862. FindClose(pfs[iFind].hff);
  863. iFind--;
  864. #ifdef DEBUG
  865. ulcOpenFinds--;
  866. #endif
  867. }
  868. }
  869. }
  870. ASSERT(! ulcOpenFinds);
  871. FreeMemory(pfs);
  872. TRACE_OUT((TEXT("ExpandSubtree(): Subtree expansion complete.")));
  873. }
  874. else
  875. tr = TR_OUT_OF_MEMORY;
  876. return(tr);
  877. }
  878. /*
  879. ** ClearStubFlagWrapper()
  880. **
  881. **
  882. **
  883. ** Arguments:
  884. **
  885. ** Returns:
  886. **
  887. ** Side Effects: none
  888. */
  889. PUBLIC_CODE BOOL ClearStubFlagWrapper(PSTUB pstub, PVOID dwFlags)
  890. {
  891. ASSERT(IS_VALID_STRUCT_PTR(pstub, CSTUB));
  892. ASSERT(FLAGS_ARE_VALID(PtrToUlong(dwFlags), ALL_STUB_FLAGS));
  893. ClearStubFlag(pstub, PtrToUlong(dwFlags));
  894. return(TRUE);
  895. }
  896. /*
  897. ** SetStubFlagWrapper()
  898. **
  899. **
  900. **
  901. ** Arguments:
  902. **
  903. ** Returns:
  904. **
  905. ** Side Effects: none
  906. */
  907. PUBLIC_CODE BOOL SetStubFlagWrapper(PSTUB pstub, PVOID dwFlags)
  908. {
  909. ASSERT(IS_VALID_STRUCT_PTR(pstub, CSTUB));
  910. ASSERT(FLAGS_ARE_VALID(PtrToUlong(dwFlags), ALL_STUB_FLAGS));
  911. SetStubFlag(pstub, PtrToUlong(dwFlags));
  912. return(TRUE);
  913. }
  914. /*
  915. ** ExpandIntersectingFolderTwins()
  916. **
  917. **
  918. **
  919. ** Arguments:
  920. **
  921. ** Returns: TWINRESULT
  922. **
  923. ** Side Effects: Leaves only the folder pairs expanded marked used.
  924. */
  925. PUBLIC_CODE TWINRESULT ExpandIntersectingFolderTwins(PFOLDERPAIR pfp,
  926. CREATERECLISTPROC crlp,
  927. LPARAM lpCallbackData)
  928. {
  929. TWINRESULT tr;
  930. HCLSIFACECACHE hcic;
  931. /* lpCallbackData may be any value. */
  932. ASSERT(IS_VALID_STRUCT_PTR(pfp, CFOLDERPAIR));
  933. ASSERT(! crlp ||
  934. IS_VALID_CODE_PTR(crlp, CREATERECLISTPROC));
  935. ASSERT(IsStubFlagClear(&(pfp->stub), STUB_FL_UNLINKED));
  936. if (CreateClassInterfaceCache(&hcic))
  937. {
  938. /* Prepare for call to MyExpandIntersectingFolderTwins(). */
  939. PrepareForFolderTwinExpansion(pfp->pfpd->hbr);
  940. tr = MyExpandIntersectingFolderTwins(pfp, hcic, crlp, lpCallbackData);
  941. DestroyClassInterfaceCache(hcic);
  942. }
  943. else
  944. tr = TR_OUT_OF_MEMORY;
  945. return(tr);
  946. }
  947. /*
  948. ** ExpandFolderTwinsIntersectingTwinList()
  949. **
  950. **
  951. **
  952. ** Arguments:
  953. **
  954. ** Returns:
  955. **
  956. ** Side Effects: Leaves only the folder pairs expanded marked used.
  957. */
  958. PUBLIC_CODE TWINRESULT ExpandFolderTwinsIntersectingTwinList(
  959. HTWINLIST htl,
  960. CREATERECLISTPROC crlp,
  961. LPARAM lpCallbackData)
  962. {
  963. TWINRESULT tr;
  964. HCLSIFACECACHE hcic;
  965. /* lpCallbackData may be any value. */
  966. ASSERT(IS_VALID_HANDLE(htl, TWINLIST));
  967. ASSERT(! crlp ||
  968. IS_VALID_CODE_PTR(crlp, CREATERECLISTPROC));
  969. if (CreateClassInterfaceCache(&hcic))
  970. {
  971. ARRAYINDEX aicTwins;
  972. ARRAYINDEX ai;
  973. tr = TR_SUCCESS;
  974. /* Prepare for calls to MyExpandIntersectingFolderTwins(). */
  975. PrepareForFolderTwinExpansion(GetTwinListBriefcase(htl));
  976. aicTwins = GetTwinListCount(htl);
  977. for (ai = 0; ai < aicTwins; ai++)
  978. {
  979. HTWIN htwin;
  980. htwin = GetTwinFromTwinList(htl, ai);
  981. /* Expand only live folder twins. */
  982. if (((PCSTUB)htwin)->st == ST_FOLDERPAIR)
  983. {
  984. tr = MyExpandIntersectingFolderTwins((PFOLDERPAIR)htwin, hcic,
  985. crlp, lpCallbackData);
  986. if (tr != TR_SUCCESS)
  987. break;
  988. }
  989. }
  990. DestroyClassInterfaceCache(hcic);
  991. }
  992. else
  993. tr = TR_OUT_OF_MEMORY;
  994. return(tr);
  995. }
  996. /*
  997. ** TryToGenerateObjectTwin()
  998. **
  999. **
  1000. **
  1001. ** Arguments:
  1002. **
  1003. ** Returns:
  1004. **
  1005. ** Side Effects: none
  1006. */
  1007. PUBLIC_CODE TWINRESULT TryToGenerateObjectTwin(HBRFCASE hbr, HPATH hpathFolder,
  1008. LPCTSTR pcszName,
  1009. PBOOL pbGenerated,
  1010. POBJECTTWIN *ppot)
  1011. {
  1012. TWINRESULT tr;
  1013. HCLSIFACECACHE hcic;
  1014. ASSERT(IS_VALID_HANDLE(hbr, BRFCASE));
  1015. ASSERT(IS_VALID_HANDLE(hpathFolder, PATH));
  1016. ASSERT(IS_VALID_STRING_PTR(pcszName, CSTR));
  1017. ASSERT(IS_VALID_WRITE_PTR(pbGenerated, BOOL));
  1018. ASSERT(IS_VALID_WRITE_PTR(ppot, POBJECTTWIN));
  1019. if (CreateClassInterfaceCache(&hcic))
  1020. {
  1021. HPTRARRAY hpaFolderPairs;
  1022. ARRAYINDEX aicPtrs;
  1023. ARRAYINDEX ai;
  1024. tr = TR_SUCCESS;
  1025. *pbGenerated = FALSE;
  1026. hpaFolderPairs = GetBriefcaseFolderPairPtrArray(hbr);
  1027. aicPtrs = GetPtrCount(hpaFolderPairs);
  1028. ASSERT(! (aicPtrs % 2));
  1029. for (ai = 0; ai < aicPtrs; ai++)
  1030. {
  1031. PCFOLDERPAIR pcfp;
  1032. pcfp = GetPtr(hpaFolderPairs, ai);
  1033. if (FolderTwinGeneratesObjectTwin(pcfp, hpathFolder, pcszName))
  1034. {
  1035. TCHAR rgchSubPath[MAX_PATH_LEN];
  1036. LPCTSTR pcszSubPath;
  1037. POBJECTTWIN potOther;
  1038. if (IsStubFlagSet(&(pcfp->stub), STUB_FL_SUBTREE))
  1039. pcszSubPath = FindChildPathSuffix(pcfp->hpath, hpathFolder,
  1040. rgchSubPath);
  1041. else
  1042. pcszSubPath = EMPTY_STRING;
  1043. tr = FakeObjectTwinFromFolderTwin(pcfp, pcszSubPath, pcszName,
  1044. hcic, ppot, &potOther);
  1045. if (tr == TR_SUCCESS)
  1046. *pbGenerated = TRUE;
  1047. else
  1048. ASSERT(tr != TR_DUPLICATE_TWIN);
  1049. break;
  1050. }
  1051. }
  1052. DestroyClassInterfaceCache(hcic);
  1053. }
  1054. else
  1055. tr = TR_OUT_OF_MEMORY;
  1056. ASSERT(tr != TR_SUCCESS ||
  1057. ! *pbGenerated ||
  1058. IS_VALID_STRUCT_PTR(*ppot, COBJECTTWIN));
  1059. return(tr);
  1060. }
  1061. /*
  1062. ** NamesIntersect()
  1063. **
  1064. ** Determines whether or not two names may refer to the same object. Both
  1065. ** names may contain wildcards ('*' or '?').
  1066. **
  1067. ** Arguments: pcszName1 - first name
  1068. ** pcszName2 - second name
  1069. **
  1070. ** Returns: TRUE if the two names intersect. FALSE if not.
  1071. **
  1072. ** Side Effects: none
  1073. **
  1074. ** A "name" is broken up into two components: a "base" and an optional
  1075. ** "extension", e.g., "BASE" or "BASE.EXT".
  1076. **
  1077. ** "Intersecting names" are defined as follows:
  1078. **
  1079. ** 1) An asterisk matches 0 or more characters in the base or extension.
  1080. ** 2) Any characters after an asterisk in the base or extension are ignored.
  1081. ** 3) A question mark matches exactly one character, or no character if it
  1082. ** appears at the end of the base or extension.
  1083. **
  1084. ** N.b., this function does not perform any checking on the validity of the two
  1085. ** names.
  1086. */
  1087. PUBLIC_CODE BOOL NamesIntersect(LPCTSTR pcszName1, LPCTSTR pcszName2)
  1088. {
  1089. BOOL bIntersect = FALSE;
  1090. ASSERT(IS_VALID_STRING_PTR(pcszName1, CSTR));
  1091. ASSERT(IS_VALID_STRING_PTR(pcszName2, CSTR));
  1092. if (NameComponentsIntersect(pcszName1, pcszName2))
  1093. {
  1094. LPCTSTR pcszExt1;
  1095. LPCTSTR pcszExt2;
  1096. /* Get extensions, skipping leading periods. */
  1097. pcszExt1 = ExtractExtension(pcszName1);
  1098. if (*pcszExt1 == PERIOD)
  1099. pcszExt1 = CharNext(pcszExt1);
  1100. pcszExt2 = ExtractExtension(pcszName2);
  1101. if (*pcszExt2 == PERIOD)
  1102. pcszExt2 = CharNext(pcszExt2);
  1103. bIntersect = NameComponentsIntersect(pcszExt1, pcszExt2);
  1104. }
  1105. return(bIntersect);
  1106. }
  1107. #ifdef DEBUG
  1108. /*
  1109. ** IsValidTWINRESULT()
  1110. **
  1111. **
  1112. **
  1113. ** Arguments:
  1114. **
  1115. ** Returns:
  1116. **
  1117. ** Side Effects: none
  1118. */
  1119. PUBLIC_CODE BOOL IsValidTWINRESULT(TWINRESULT tr)
  1120. {
  1121. BOOL bResult;
  1122. switch (tr)
  1123. {
  1124. case TR_SUCCESS:
  1125. case TR_RH_LOAD_FAILED:
  1126. case TR_SRC_OPEN_FAILED:
  1127. case TR_SRC_READ_FAILED:
  1128. case TR_DEST_OPEN_FAILED:
  1129. case TR_DEST_WRITE_FAILED:
  1130. case TR_ABORT:
  1131. case TR_UNAVAILABLE_VOLUME:
  1132. case TR_OUT_OF_MEMORY:
  1133. case TR_FILE_CHANGED:
  1134. case TR_DUPLICATE_TWIN:
  1135. case TR_DELETED_TWIN:
  1136. case TR_HAS_FOLDER_TWIN_SRC:
  1137. case TR_INVALID_PARAMETER:
  1138. case TR_REENTERED:
  1139. case TR_SAME_FOLDER:
  1140. case TR_SUBTREE_CYCLE_FOUND:
  1141. case TR_NO_MERGE_HANDLER:
  1142. case TR_MERGE_INCOMPLETE:
  1143. case TR_TOO_DIFFERENT:
  1144. case TR_BRIEFCASE_LOCKED:
  1145. case TR_BRIEFCASE_OPEN_FAILED:
  1146. case TR_BRIEFCASE_READ_FAILED:
  1147. case TR_BRIEFCASE_WRITE_FAILED:
  1148. case TR_CORRUPT_BRIEFCASE:
  1149. case TR_NEWER_BRIEFCASE:
  1150. case TR_NO_MORE:
  1151. bResult = TRUE;
  1152. break;
  1153. default:
  1154. bResult = FALSE;
  1155. ERROR_OUT((TEXT("IsValidTWINRESULT(): Invalid TWINRESULT %d."),
  1156. tr));
  1157. break;
  1158. }
  1159. return(bResult);
  1160. }
  1161. #endif