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.

1151 lines
34 KiB

  1. //---------------------------------------------------------------------------
  2. //
  3. // Copyright (c) Microsoft Corporation 1993-1994
  4. //
  5. // File: crl.c
  6. //
  7. // This files contains code for the cached reclists
  8. //
  9. // History:
  10. // 09-02-93 ScottH Created
  11. // 01-31-94 ScottH Moved from cache.c
  12. //
  13. //---------------------------------------------------------------------------
  14. #include "brfprv.h" // common headers
  15. #include "recact.h"
  16. #include "res.h"
  17. #define CRL_Iterate(atom) \
  18. for (atom = Cache_FindFirstKey(&g_cacheCRL); \
  19. ATOM_ERR != atom; \
  20. atom = Cache_FindNextKey(&g_cacheCRL, atom))
  21. CACHE g_cacheCRL = {0, 0, 0}; // Reclist cache
  22. #define CRL_EnterCS() EnterCriticalSection(&g_cacheCRL.cs)
  23. #define CRL_LeaveCS() LeaveCriticalSection(&g_cacheCRL.cs)
  24. #ifdef DEBUG
  25. /*----------------------------------------------------------
  26. Purpose: Dump a CRL entry
  27. Returns: --
  28. Cond: --
  29. */
  30. void PRIVATE CRL_DumpEntry(
  31. CRL * pcrl)
  32. {
  33. TCHAR sz[MAXBUFLEN];
  34. ASSERT(pcrl);
  35. TRACE_MSG(TF_ALWAYS, TEXT("CRL: Atom %d: %s"), pcrl->atomPath, Atom_GetName(pcrl->atomPath));
  36. TRACE_MSG(TF_ALWAYS, TEXT(" Outside %d: %s"), pcrl->atomOutside, Atom_GetName(pcrl->atomOutside));
  37. TRACE_MSG(TF_ALWAYS, TEXT(" Ref [%u] Use [%u] %s %s %s %s"),
  38. Cache_GetRefCount(&g_cacheCRL, pcrl->atomPath),
  39. pcrl->ucUse,
  40. CRL_IsOrphan(pcrl) ? (LPCTSTR) TEXT("Orphan") : (LPCTSTR) TEXT(""),
  41. IsFlagSet(pcrl->uFlags, CRLF_DIRTY) ? (LPCTSTR) TEXT("Dirty") : (LPCTSTR) TEXT(""),
  42. IsFlagSet(pcrl->uFlags, CRLF_NUKE) ? (LPCTSTR) TEXT("Nuke") : (LPCTSTR) TEXT(""),
  43. CRL_IsSubfolderTwin(pcrl) ? (LPCTSTR) TEXT("SubfolderTwin") : (LPCTSTR) TEXT(""));
  44. TRACE_MSG(TF_ALWAYS, TEXT(" Status: %s"), SzFromIDS(pcrl->idsStatus, sz, ARRAYSIZE(sz)));
  45. }
  46. void PUBLIC CRL_DumpAll()
  47. {
  48. CRL * pcrl;
  49. int atom;
  50. BOOL bDump;
  51. ENTEREXCLUSIVE()
  52. {
  53. bDump = IsFlagSet(g_uDumpFlags, DF_CRL);
  54. }
  55. LEAVEEXCLUSIVE()
  56. if (!bDump)
  57. return ;
  58. CRL_Iterate(atom)
  59. {
  60. pcrl = Cache_GetPtr(&g_cacheCRL, atom);
  61. ASSERT(pcrl);
  62. if (pcrl)
  63. {
  64. CRL_DumpEntry(pcrl);
  65. Cache_DeleteItem(&g_cacheCRL, atom, FALSE, NULL, CRL_Free); // Decrement count
  66. }
  67. }
  68. }
  69. #endif
  70. /*----------------------------------------------------------
  71. Purpose: Return the resource string ID describing the action to take
  72. Returns: --
  73. Cond: --
  74. */
  75. UINT PRIVATE IdsFromRAItem(
  76. LPRA_ITEM pitem)
  77. {
  78. UINT ids;
  79. ASSERT(IsFlagSet(pitem->mask, RAIF_ACTION));
  80. switch (pitem->uAction)
  81. {
  82. case RAIA_TOOUT:
  83. case RAIA_TOIN:
  84. case RAIA_CONFLICT:
  85. case RAIA_DELETEOUT:
  86. case RAIA_DELETEIN:
  87. case RAIA_MERGE:
  88. case RAIA_SOMETHING:
  89. ids = IDS_STATE_NeedToUpdate;
  90. break;
  91. case RAIA_ORPHAN:
  92. ids = IDS_STATE_Orphan;
  93. break;
  94. case RAIA_DONTDELETE:
  95. case RAIA_SKIP:
  96. ASSERT(SI_UNAVAILABLE == pitem->siInside.uState ||
  97. SI_UNAVAILABLE == pitem->siOutside.uState);
  98. if (SI_UNAVAILABLE == pitem->siOutside.uState)
  99. {
  100. if (SI_UNCHANGED == pitem->siInside.uState)
  101. {
  102. ids = IDS_STATE_UptodateInBrf;
  103. }
  104. else if (SI_UNAVAILABLE != pitem->siInside.uState)
  105. {
  106. ids = IDS_STATE_NeedToUpdate;
  107. }
  108. else
  109. {
  110. ids = IDS_STATE_Unavailable;
  111. }
  112. }
  113. else
  114. {
  115. ASSERT(SI_UNAVAILABLE == pitem->siInside.uState);
  116. ids = IDS_STATE_Unavailable;
  117. }
  118. break;
  119. case RAIA_NOTHING:
  120. ids = IDS_STATE_Uptodate;
  121. break;
  122. default:
  123. ASSERT(0);
  124. ids = 0;
  125. break;
  126. }
  127. return ids;
  128. }
  129. /*----------------------------------------------------------
  130. Purpose: Gets the outside sync copy and the resource ID to the
  131. status string that indicates the status between the
  132. sync copies.
  133. Returns: --
  134. Cond: --
  135. */
  136. void PRIVATE SetPairInfo(
  137. PCRL pcrl)
  138. {
  139. LPCTSTR pszPath = Atom_GetName(pcrl->atomPath);
  140. LPCTSTR pszName = PathFindFileName(pszPath);
  141. // Is this an orphan?
  142. if (CRL_IsOrphan(pcrl))
  143. {
  144. // Yes; special case: is this one of the briefcase system files?
  145. LPCTSTR pszDBName;
  146. if (IsFlagSet(pcrl->uFlags, CRLF_ISLFNDRIVE))
  147. pszDBName = g_szDBName;
  148. else
  149. pszDBName = g_szDBNameShort;
  150. if (IsSzEqual(pszName, pszDBName) ||
  151. IsSzEqual(pszName, c_szDesktopIni))
  152. {
  153. // Yes
  154. pcrl->idsStatus = IDS_STATE_SystemFile;
  155. }
  156. // Is this a subfolder twin? (Only orphans are
  157. // candidates for being subfolder twins.)
  158. else if (CRL_IsSubfolderTwin(pcrl))
  159. {
  160. // Yes
  161. ASSERT(PathIsDirectory(pszPath));
  162. pcrl->idsStatus = IDS_STATE_Subfolder;
  163. }
  164. else
  165. {
  166. // No
  167. pcrl->idsStatus = IDS_STATE_Orphan;
  168. }
  169. if (Atom_IsValid(pcrl->atomOutside))
  170. {
  171. Atom_Delete(pcrl->atomOutside); // delete the old one
  172. }
  173. pcrl->atomOutside = Atom_Add(TEXT(""));
  174. }
  175. else
  176. {
  177. // No; get the info for this sync copy
  178. HRESULT hres;
  179. LPRA_ITEM pitem;
  180. TCHAR sz[MAXPATHLEN];
  181. ASSERT(pcrl->lprl);
  182. hres = RAI_Create(&pitem, Atom_GetName(pcrl->atomBrf), pszPath,
  183. pcrl->lprl, pcrl->lpftl);
  184. if (SUCCEEDED(hres))
  185. {
  186. lstrcpyn(sz, pitem->siOutside.pszDir, ARRAYSIZE(sz));
  187. // Is this a file?
  188. if ( !CRL_IsFolder(pcrl) )
  189. {
  190. // Yes; atomOutside needs to be a fully qualified path to
  191. // the outside file/folder--not just the parent folder.
  192. // That's why we tack on the filename here.
  193. PathAppend(sz, pszName);
  194. }
  195. if (Atom_IsValid(pcrl->atomOutside))
  196. {
  197. Atom_Delete(pcrl->atomOutside); // delete the old one
  198. }
  199. pcrl->atomOutside = Atom_Add(sz);
  200. pcrl->idsStatus = IdsFromRAItem(pitem);
  201. RAI_Free(pitem);
  202. }
  203. }
  204. }
  205. /*----------------------------------------------------------
  206. Purpose: Determines whether or not a subfolder of a briefcase
  207. is the root of a subtree twin.
  208. Returns: --
  209. Cond: --
  210. */
  211. BOOL PRIVATE IsSubtreeTwin(HBRFCASE hbrf, LPCTSTR pcszFolder)
  212. {
  213. BOOL bIsSubtreeTwin = FALSE;
  214. PFOLDERTWINLIST pftl;
  215. ASSERT(PathIsDirectory(pcszFolder));
  216. /* Create a folder twin list for the folder. */
  217. if (Sync_CreateFolderList(hbrf, pcszFolder, &pftl) == TR_SUCCESS)
  218. {
  219. PCFOLDERTWIN pcft;
  220. /*
  221. * Look through the folder twin list for any folder twins with the
  222. * FT_FL_SUBTREE flag set.
  223. */
  224. for (pcft = pftl->pcftFirst; pcft; pcft = pcft->pcftNext)
  225. {
  226. if (pcft->dwFlags & FT_FL_SUBTREE)
  227. {
  228. bIsSubtreeTwin = TRUE;
  229. break;
  230. }
  231. }
  232. Sync_DestroyFolderList(pftl);
  233. }
  234. return(bIsSubtreeTwin);
  235. }
  236. /*----------------------------------------------------------
  237. Purpose: Determines whether or not a path is a subfolder of a subtree twin in a
  238. briefcase.
  239. Returns: --
  240. Cond: --
  241. */
  242. BOOL PUBLIC IsSubfolderTwin(HBRFCASE hbrf, LPCTSTR pcszPath)
  243. {
  244. BOOL bIsSubfolderTwin = FALSE;
  245. TCHAR szBrfRoot[MAXPATHLEN];
  246. if (PathIsDirectory(pcszPath) &&
  247. PathGetLocality(pcszPath, szBrfRoot, ARRAYSIZE(szBrfRoot)) == PL_INSIDE)
  248. {
  249. int ncchBrfRootLen;
  250. TCHAR szParent[MAXPATHLEN];
  251. ASSERT(PathIsPrefix(szBrfRoot, pcszPath));
  252. ncchBrfRootLen = lstrlen(szBrfRoot);
  253. ASSERT(lstrlen(pcszPath) < ARRAYSIZE(szParent));
  254. lstrcpyn(szParent, pcszPath, ARRAYSIZE(szParent));
  255. /*
  256. * Keep whacking off the last path component until we find a parent
  257. * subtree twin root, or we hit the briefcase root.
  258. */
  259. while (! bIsSubfolderTwin &&
  260. PathRemoveFileSpec(szParent) &&
  261. lstrlen(szParent) > ncchBrfRootLen)
  262. {
  263. BOOL bIsFolderTwin;
  264. if (Sync_IsFolder(hbrf, szParent, &bIsFolderTwin) == TR_SUCCESS &&
  265. bIsFolderTwin)
  266. {
  267. bIsSubfolderTwin = IsSubtreeTwin(hbrf, szParent);
  268. #ifdef DEBUG
  269. TRACE_MSG(TF_CACHE, TEXT("CACHE Found subfolder twin %s with parent subtree twin root %s."),
  270. pcszPath,
  271. szParent);
  272. #endif
  273. }
  274. }
  275. }
  276. return(bIsSubfolderTwin);
  277. }
  278. /*----------------------------------------------------------
  279. Purpose: Sets the bSubfolderTwin member of a CRL.
  280. Returns: --
  281. Cond: The lprl and lpftl members of the CRL must be filled in before calling
  282. this function.
  283. */
  284. void PRIVATE SetSubfolderTwinFlag(PCRL pcrl)
  285. {
  286. if (! pcrl->lprl && ! pcrl->lpftl)
  287. {
  288. if (IsSubfolderTwin(pcrl->hbrf, Atom_GetName(pcrl->atomPath)))
  289. SetFlag(pcrl->uFlags, CRLF_SUBFOLDERTWIN);
  290. else
  291. ClearFlag(pcrl->uFlags, CRLF_SUBFOLDERTWIN);
  292. }
  293. else
  294. {
  295. ClearFlag(pcrl->uFlags, CRLF_SUBFOLDERTWIN);
  296. }
  297. }
  298. /*----------------------------------------------------------
  299. Purpose: Free the reclist
  300. Returns: --
  301. Cond: hwndOwner is not used, so it is okay for all CRL_ routines
  302. to pass NULL as hwndOwner.
  303. This function is serialized by the caller (Cache_Term or
  304. Cache_DeleteItem).
  305. */
  306. void CALLBACK CRL_Free(
  307. LPVOID lpv,
  308. HWND hwndOwner)
  309. {
  310. CRL * pcrl = (CRL *)lpv;
  311. ASSERT(Sync_IsEngineLoaded());
  312. DEBUG_CODE( TRACE_MSG(TF_CACHE, TEXT("CACHE Destroying CRL for %s (0x%lx)"),
  313. Atom_GetName(pcrl->atomPath), pcrl->hbrf); )
  314. if (Atom_IsValid(pcrl->atomOutside))
  315. Atom_Delete(pcrl->atomOutside);
  316. if (Atom_IsValid(pcrl->atomBrf))
  317. Atom_Delete(pcrl->atomBrf);
  318. if (pcrl->lprl)
  319. Sync_DestroyRecList(pcrl->lprl);
  320. if (pcrl->lpftl)
  321. Sync_DestroyFolderList(pcrl->lpftl);
  322. // The CRL does not own pabortevt, leave it alone
  323. SharedFree(&pcrl);
  324. }
  325. /*----------------------------------------------------------
  326. Purpose: Create a reclist and (optional) folder twin list for a path.
  327. Returns: standard result
  328. S_OK if the item is a twin
  329. S_FALSE if the item is an orphan
  330. Cond: --
  331. */
  332. HRESULT PRIVATE CreatePathLists(
  333. HBRFCASE hbrf,
  334. PABORTEVT pabortevt,
  335. int atomPath,
  336. PRECLIST * lplprl,
  337. PFOLDERTWINLIST * lplpftl)
  338. {
  339. HRESULT hres;
  340. LPCTSTR pszPath = Atom_GetName(atomPath);
  341. ASSERT(pszPath);
  342. ASSERT(hbrf);
  343. ASSERT(lplprl);
  344. ASSERT(lplpftl);
  345. *lplprl = NULL;
  346. *lplpftl = NULL;
  347. // Two routes.
  348. //
  349. // 1) If the path is to the root of a briefcase,
  350. // create a complete reclist.
  351. //
  352. // 2) Otherwise create a reclist for the individual file or folder
  353. //
  354. // Hack: a quick way of telling if atomPath is a briefcase
  355. // root is by looking for it in the CBS cache.
  356. // Is this the root of a briefcase?
  357. if (CBS_Get(atomPath))
  358. {
  359. // Yes
  360. CBS_Delete(atomPath, NULL); // Decrement count
  361. hres = Sync_CreateCompleteRecList(hbrf, pabortevt, lplprl);
  362. }
  363. else
  364. {
  365. // No; is this a twin?
  366. hres = Sync_IsTwin(hbrf, pszPath, 0);
  367. if (S_OK == hres)
  368. {
  369. // Yes; create a reclist (and an optional folder twin list).
  370. HTWINLIST htl;
  371. hres = E_OUTOFMEMORY; // assume error
  372. if (Sync_CreateTwinList(hbrf, &htl) == TR_SUCCESS)
  373. {
  374. if (Sync_AddPathToTwinList(hbrf, htl, pszPath, lplpftl))
  375. {
  376. hres = Sync_CreateRecListEx(htl, pabortevt, lplprl);
  377. if (SUCCEEDED(hres))
  378. {
  379. // The object may have been implicitly deleted
  380. // in CreateRecList. Check again.
  381. hres = Sync_IsTwin(hbrf, pszPath, 0);
  382. }
  383. }
  384. Sync_DestroyTwinList(htl);
  385. }
  386. }
  387. }
  388. if (FAILED(hres))
  389. {
  390. // Cleanup on failure
  391. //
  392. if (*lplpftl)
  393. Sync_DestroyFolderList(*lplpftl);
  394. *lplprl = NULL;
  395. *lplpftl = NULL;
  396. }
  397. return hres;
  398. }
  399. /*----------------------------------------------------------
  400. Purpose: Add a CRL entry for the atomPath to the cache. This
  401. consists of creating the reclist (and folder twin list
  402. possibly).
  403. If the atomPath is already in the cache, this function
  404. increments the reference count of the item and calls
  405. CRL_Replace.
  406. Returns: standard result
  407. Cond: Must call CRL_Delete for every call to this function.
  408. IMPORTANT: Some portions of code call PathIsDirectory,
  409. which will fail if atomPath does not exist.
  410. */
  411. HRESULT PUBLIC CRL_Add(
  412. PCBS pcbs,
  413. int atomPath)
  414. {
  415. HRESULT hres = E_OUTOFMEMORY;
  416. PRECLIST lprl = NULL;
  417. PFOLDERTWINLIST lpftl = NULL;
  418. CRL * pcrl;
  419. ASSERT(pcbs);
  420. CRL_EnterCS();
  421. {
  422. // Caller wants to add. If it already exists, we simply return
  423. // the existing entry.
  424. //
  425. // This CRL_Get increments the count (if it succeeds)
  426. pcrl = Cache_GetPtr(&g_cacheCRL, atomPath);
  427. // Is the item in the cache?
  428. if (pcrl)
  429. {
  430. // Yes; attempt to get fresh contents
  431. hres = CRL_Replace(atomPath);
  432. }
  433. else
  434. {
  435. // No; the entry is not in the cache. Add it.
  436. LPCTSTR pszPath = Atom_GetName(atomPath);
  437. ASSERT(pszPath);
  438. DEBUG_CODE( TRACE_MSG(TF_CACHE, TEXT("CACHE Adding CRL for %s (0x%lx)"),
  439. pszPath, pcbs->hbrf); )
  440. // Leave the critical section while we do expensive calculation
  441. CRL_LeaveCS();
  442. {
  443. hres = CreatePathLists(pcbs->hbrf, pcbs->pabortevt,
  444. atomPath, &lprl, &lpftl);
  445. }
  446. CRL_EnterCS();
  447. if (FAILED(hres))
  448. goto Fail;
  449. else
  450. {
  451. LPCTSTR pszBrf;
  452. // Allocate using commctrl's Alloc, so the structure will be in
  453. // shared heap space across processes.
  454. pcrl = SharedAllocType(CRL);
  455. if (!pcrl)
  456. {
  457. hres = E_OUTOFMEMORY;
  458. goto Fail;
  459. }
  460. pcrl->atomPath = atomPath;
  461. pcrl->hbrf = pcbs->hbrf;
  462. pszBrf = Atom_GetName(pcbs->atomBrf);
  463. pcrl->atomBrf = Atom_Add(pszBrf);
  464. pcrl->pabortevt = pcbs->pabortevt;
  465. pcrl->lpftl = lpftl;
  466. pcrl->lprl = lprl;
  467. pcrl->ucUse = 0;
  468. pcrl->uFlags = 0; // reset
  469. SetSubfolderTwinFlag(pcrl);
  470. if (S_FALSE == hres)
  471. SetFlag(pcrl->uFlags, CRLF_ORPHAN);
  472. if (PathIsDirectory(Atom_GetName(atomPath)))
  473. SetFlag(pcrl->uFlags, CRLF_ISFOLDER);
  474. if (IsFlagSet(pcbs->uFlags, CBSF_LFNDRIVE))
  475. SetFlag(pcrl->uFlags, CRLF_ISLFNDRIVE);
  476. SetPairInfo(pcrl);
  477. // This Cache_AddItem does the increment count
  478. if ( !Cache_AddItem(&g_cacheCRL, atomPath, (LPVOID)pcrl) )
  479. {
  480. // Failed
  481. Atom_Delete(pcrl->atomBrf);
  482. Atom_Delete(pcrl->atomOutside);
  483. hres = E_OUTOFMEMORY;
  484. goto Fail;
  485. }
  486. }
  487. }
  488. }
  489. CRL_LeaveCS();
  490. return hres;
  491. Fail:
  492. // Cleanup on failure
  493. //
  494. if (lprl)
  495. Sync_DestroyRecList(lprl);
  496. if (lpftl)
  497. Sync_DestroyFolderList(lpftl);
  498. SharedFree(&pcrl);
  499. CRL_LeaveCS();
  500. DEBUG_MSG(TF_ERROR, TEXT("SyncUI CRL_Add failed!"));
  501. return hres;
  502. }
  503. /*----------------------------------------------------------
  504. Purpose: Decrement the reference count and the use count to
  505. the reclist cache entry.
  506. If the reference count == 0, the entry is deleted.
  507. Returns: --
  508. Cond: --
  509. */
  510. void PUBLIC CRL_Delete(
  511. int atomPath)
  512. {
  513. CRL * pcrl;
  514. CRL_EnterCS();
  515. {
  516. // Decrement the use count
  517. //
  518. pcrl = Cache_GetPtr(&g_cacheCRL, atomPath);
  519. if (pcrl)
  520. {
  521. DEBUG_CODE( LPCTSTR pszPath = Atom_GetName(atomPath); )
  522. if (pcrl->ucUse > 0)
  523. pcrl->ucUse--;
  524. if (IsFlagSet(pcrl->uFlags, CRLF_NUKE))
  525. {
  526. if (pcrl->ucUse == 0)
  527. {
  528. DEBUG_CODE( TRACE_MSG(TF_CACHE, TEXT("CACHE Nuking late CRL %s..."),
  529. pszPath); )
  530. // A nuke was deferred. Now we can really do it.
  531. //
  532. Cache_DeleteItem(&g_cacheCRL, atomPath, TRUE, NULL, CRL_Free);
  533. goto Done;
  534. }
  535. #ifdef DEBUG
  536. else
  537. {
  538. TRACE_MSG(TF_CACHE, TEXT("CACHE Deferring nuke CRL %s..."),
  539. pszPath);
  540. }
  541. #endif
  542. }
  543. Cache_DeleteItem(&g_cacheCRL, atomPath, FALSE, NULL, CRL_Free); // Decrement for Cache_GetPtr
  544. // The real delete...
  545. Cache_DeleteItem(&g_cacheCRL, atomPath, FALSE, NULL, CRL_Free);
  546. }
  547. Done:;
  548. }
  549. CRL_LeaveCS();
  550. }
  551. /*----------------------------------------------------------
  552. Purpose: Nuke the cache entry if the use count is 0. Otherwise,
  553. set the nuke bit, and this entry will get nuked on the
  554. next CRL_Get when the use count is 0.
  555. Returns: --
  556. Cond: --
  557. */
  558. void PUBLIC CRL_Nuke(
  559. int atomPath)
  560. {
  561. CRL * pcrl;
  562. CRL_EnterCS();
  563. {
  564. // Check the use count
  565. //
  566. pcrl = Cache_GetPtr(&g_cacheCRL, atomPath);
  567. if (pcrl)
  568. {
  569. if (pcrl->ucUse > 0)
  570. {
  571. DEBUG_CODE( TRACE_MSG(TF_CACHE, TEXT("CACHE Marking to nuke CRL for %s (0x%lx)"),
  572. Atom_GetName(atomPath), pcrl->hbrf); )
  573. SetFlag(pcrl->uFlags, CRLF_NUKE);
  574. Cache_DeleteItem(&g_cacheCRL, atomPath, FALSE, NULL, CRL_Free); // Decrement for Cache_GetPtr
  575. }
  576. else
  577. {
  578. DEBUG_CODE( TRACE_MSG(TF_CACHE, TEXT("CACHE Nuking CRL for %s (0x%lx)"),
  579. Atom_GetName(atomPath), pcrl->hbrf); )
  580. Cache_DeleteItem(&g_cacheCRL, atomPath, TRUE, NULL, CRL_Free);
  581. }
  582. }
  583. }
  584. CRL_LeaveCS();
  585. }
  586. /*----------------------------------------------------------
  587. Purpose: Replace the atomPath in the cache. This consists of
  588. creating the reclist (and folder twin list possibly)
  589. and replacing the contents of pcrl.
  590. The pcrl pointer remains unchanged.
  591. The reference and use-counts remain unchanged.
  592. Returns: standard result
  593. Cond:
  594. IMPORTANT: Some portions of code call PathIsDirectory,
  595. which will fail if atomPath does not exist.
  596. */
  597. HRESULT PUBLIC CRL_Replace(
  598. int atomPath)
  599. {
  600. HRESULT hres;
  601. CRL * pcrl;
  602. CRL_EnterCS();
  603. {
  604. pcrl = Cache_GetPtr(&g_cacheCRL, atomPath);
  605. // Does the item exist?
  606. if (pcrl)
  607. {
  608. DEBUG_CODE( LPCTSTR pszPath = Atom_GetName(atomPath); )
  609. ASSERT(pszPath);
  610. DEBUG_CODE( TRACE_MSG(TF_CACHE, TEXT("CACHE Replacing CRL for %s (0x%lx)"),
  611. pszPath, pcrl->hbrf); )
  612. // Yes; mark it dirty and call CRL_Get on it.
  613. SetFlag(pcrl->uFlags, CRLF_DIRTY);
  614. // Note: pay attention to the difference between Cache_Delete
  615. // and CRL_Delete. Cache_Delete must match Cache_Add/Get and
  616. // CRL_Delete must match CRL_Add/Get.
  617. //
  618. Cache_DeleteItem(&g_cacheCRL, atomPath, FALSE, NULL, CRL_Free); // Decrement count for Cache_GetPtr
  619. hres = CRL_Get(atomPath, &pcrl); // This does the replace
  620. CRL_Delete(atomPath); // Decrement count for CRL_Get
  621. }
  622. else
  623. {
  624. hres = E_FAIL;
  625. }
  626. }
  627. CRL_LeaveCS();
  628. return hres;
  629. }
  630. /*----------------------------------------------------------
  631. Purpose: Get the reclist from the cache. If the cache item exists
  632. and is marked dirty and the use count is 0, then recreate
  633. the reclist.
  634. If the nuke bit is set, then the entry is nuked and this
  635. function returns NULL.
  636. Returns: standard result
  637. Ptr to cache entry.
  638. Cond: Must call CRL_Delete for every call to CRL_Get
  639. IMPORTANT: Some portions of code call PathIsDirectory,
  640. which will fail if atomPath does not exist.
  641. */
  642. HRESULT PUBLIC CRL_Get(
  643. int atomPath,
  644. PCRL * ppcrl)
  645. {
  646. HRESULT hres;
  647. PCRL pcrl;
  648. PRECLIST lprl = NULL;
  649. PFOLDERTWINLIST lpftl = NULL;
  650. CRL_EnterCS();
  651. {
  652. // Don't need to decrement the reference count in this
  653. // function -- this is Get!
  654. //
  655. pcrl = Cache_GetPtr(&g_cacheCRL, atomPath);
  656. if (pcrl)
  657. {
  658. HBRFCASE hbrf = pcrl->hbrf;
  659. // Is this item pending a nuke?
  660. if (IsFlagSet(pcrl->uFlags, CRLF_NUKE))
  661. {
  662. // Yes; return NULL as if it were already nuked.
  663. DEBUG_CODE( LPCTSTR pszPath = Atom_GetName(atomPath); )
  664. DEBUG_CODE( TRACE_MSG(TF_CACHE, TEXT("CACHE Attempt to get deferred nuke CRL %s (0x%lx)..."),
  665. pszPath, hbrf); )
  666. // (Decrement counter for Cache_GetPtr to keep count even,
  667. // since we are returning NULL.)
  668. Cache_DeleteItem(&g_cacheCRL, atomPath, FALSE, NULL, CRL_Free);
  669. pcrl = NULL;
  670. hres = E_FAIL;
  671. }
  672. // Is this item tagged dirty and the use-count is 0?
  673. else if (IsFlagSet(pcrl->uFlags, CRLF_DIRTY) && pcrl->ucUse == 0)
  674. {
  675. // Yes; we are free to re-create the reclist.
  676. LPCTSTR pszPath = Atom_GetName(atomPath);
  677. ASSERT(pszPath);
  678. DEBUG_CODE( TRACE_MSG(TF_CACHE, TEXT("CACHE Getting clean CRL %s (0x%lx)..."),
  679. pszPath, hbrf); )
  680. // Since we'll be leaving the critical section below,
  681. // temporarily increase the use count to keep the pcrl
  682. // from getting nuked from under us.
  683. pcrl->ucUse++;
  684. // Replace the contents of the cache entry
  685. // Leave the critical section while we do expensive calculation
  686. CRL_LeaveCS();
  687. {
  688. hres = CreatePathLists(hbrf, pcrl->pabortevt, atomPath,
  689. &lprl, &lpftl);
  690. }
  691. CRL_EnterCS();
  692. // Decrement use count
  693. pcrl->ucUse--;
  694. if (FAILED(hres))
  695. {
  696. DEBUG_CODE( DEBUG_MSG(TF_ERROR, TEXT("SyncUI CRL_Get failed in cleaning dirty entry!")); )
  697. // Still return pcrl since it exists
  698. hres = NOERROR;
  699. }
  700. else
  701. {
  702. // Put the new lists in the cache entry
  703. if (pcrl->lprl)
  704. {
  705. Sync_DestroyRecList(pcrl->lprl);
  706. }
  707. pcrl->lprl = lprl;
  708. if (pcrl->lpftl)
  709. {
  710. Sync_DestroyFolderList(pcrl->lpftl);
  711. }
  712. pcrl->lpftl = lpftl;
  713. if (S_FALSE == hres)
  714. SetFlag(pcrl->uFlags, CRLF_ORPHAN);
  715. else
  716. {
  717. ASSERT(S_OK == hres);
  718. ClearFlag(pcrl->uFlags, CRLF_ORPHAN);
  719. }
  720. ClearFlag(pcrl->uFlags, CRLF_DIRTY);
  721. SetSubfolderTwinFlag(pcrl);
  722. SetPairInfo(pcrl);
  723. hres = NOERROR;
  724. }
  725. }
  726. else
  727. {
  728. #ifdef DEBUG
  729. LPCTSTR pszPath = Atom_GetName(atomPath);
  730. ASSERT(pszPath);
  731. if (IsFlagSet(pcrl->uFlags, CRLF_DIRTY))
  732. {
  733. TRACE_MSG(TF_CACHE, TEXT("CACHE Getting dirty CRL %s (0x%lx)..."),
  734. pszPath, hbrf);
  735. }
  736. else
  737. {
  738. TRACE_MSG(TF_CACHE, TEXT("CACHE Getting CRL %s (0x%lx)..."),
  739. pszPath, hbrf);
  740. }
  741. #endif
  742. hres = NOERROR;
  743. }
  744. }
  745. else
  746. hres = E_FAIL;
  747. // Now increment the use count
  748. //
  749. if (pcrl)
  750. pcrl->ucUse++;
  751. *ppcrl = pcrl;
  752. ASSERT((FAILED(hres) && !*ppcrl) ||
  753. (SUCCEEDED(hres) && *ppcrl));
  754. }
  755. CRL_LeaveCS();
  756. return hres;
  757. }
  758. /*----------------------------------------------------------
  759. Purpose: Mark any related CRLs dirty. Which CRLs get marked dirty
  760. depends on the lEvent.
  761. In addition, *pbRefresh is set to TRUE if the window that
  762. is calling this function should refresh itself.
  763. (N.b. in the following rules, we never refresh the immediate
  764. folder unless explicitly stated, since the shell will do this
  765. automatically. E.g., if C:\Bar\Foo.txt received NOE_DIRTYITEM,
  766. the shell will automatically repaint C:\Bar.)
  767. Rules:
  768. NOE_CREATE Cause: A file is created.
  769. Dirty? Any CRLs whose atomInside or atomOutside
  770. are parents or equal to atomPath.
  771. Refresh? Only in windows of parent folders on either
  772. side OR
  773. in immediate window on the briefcase side
  774. if atomPath was created on the outside.
  775. NOE_CREATEFOLDER same as above
  776. NOE_DELETE Cause: A file or folder was deleted.
  777. Dirty? Any CRLs whose atomInside or atomOutside
  778. are parents or equal to atomPath.
  779. Delete CRL if atomPath matches atomInside
  780. Refresh? Only in windows of parent folders on either
  781. side OR
  782. in immediate window on the briefcase side
  783. if atomPath was deleted on the outside.
  784. NOE_DELETEFOLDER same as above
  785. NOE_RENAME Cause: A file or folder was renamed or moved.
  786. Dirty? Any CRLs whose atomInside or atomOutside
  787. are parents or equal to atomPath.
  788. Rename CRL (and related database entry) if
  789. atomPath is inside briefcase
  790. Refresh? Only in windows of parent folders on either
  791. side OR
  792. in immediate window on the briefcase side
  793. if atomPath is renamed on the outside.
  794. NOE_RENAMEFOLDER same as above
  795. NOE_DIRTY Cause: Varies. Typically something needs refreshed.
  796. Dirty? Any CRLs whose atomInside or atomOutside
  797. are parents or equal to atomPath.
  798. If atomPath is folder, any CRLs which are
  799. children of atomPath.
  800. Refresh? Only in windows of parent folders on either
  801. side OR
  802. in immediate window on the briefcase side
  803. if atomPath is updated on the outside.
  804. Returns: FALSE if nothing was marked
  805. TRUE if something was marked
  806. Cond: --
  807. */
  808. BOOL PUBLIC CRL_Dirty(
  809. int atomPath,
  810. int atomCabFolder, // path of open cabinet window
  811. LONG lEvent,
  812. LPBOOL pbRefresh) // return TRUE to refresh cabinet window
  813. {
  814. BOOL bRet = FALSE;
  815. CRL * pcrl;
  816. int atom;
  817. int atomParent;
  818. ASSERT(pbRefresh);
  819. *pbRefresh = FALSE;
  820. CRL_EnterCS();
  821. {
  822. BOOL bIsFolder;
  823. // Get the atomParent of the atomPath
  824. TCHAR szParent[MAXPATHLEN];
  825. lstrcpyn(szParent, Atom_GetName(atomPath), ARRAYSIZE(szParent));
  826. PathRemoveFileSpec(szParent);
  827. if (0 == *szParent) // skip blank parent paths
  828. goto Done;
  829. atomParent = Atom_Add(szParent);
  830. if (ATOM_ERR == atomParent)
  831. goto Done;
  832. // Is the path that is being updated a folder?
  833. pcrl = Cache_GetPtr(&g_cacheCRL, atomPath);
  834. if (pcrl)
  835. {
  836. bIsFolder = CRL_IsFolder(pcrl);
  837. Cache_DeleteItem(&g_cacheCRL, atomPath, FALSE, NULL, CRL_Free); // Decrement count
  838. }
  839. else
  840. {
  841. bIsFolder = FALSE;
  842. }
  843. CRL_Iterate(atom)
  844. {
  845. pcrl = Cache_GetPtr(&g_cacheCRL, atom);
  846. ASSERT(pcrl);
  847. if (pcrl)
  848. {
  849. // Is CRL a parent or equal of atomPath?
  850. if (Atom_IsParentOf(atom, atomPath))
  851. {
  852. // Yes; mark it
  853. DEBUG_CODE( LPCTSTR pszDbg = Atom_GetName(atom); )
  854. DEBUG_CODE( TRACE_MSG(TF_CACHE, TEXT("CACHE Tagging CRL for %s (0x%lx)"),
  855. pszDbg, pcrl->hbrf); )
  856. SetFlag(pcrl->uFlags, CRLF_DIRTY);
  857. bRet = TRUE;
  858. // Refresh this window?
  859. // (Only if the cabinet folder is > than an immediate
  860. // parent folder.)
  861. *pbRefresh = Atom_IsParentOf(atomCabFolder, atom) &&
  862. atomCabFolder != atomParent;
  863. switch (lEvent)
  864. {
  865. case NOE_DELETE:
  866. case NOE_DELETEFOLDER:
  867. // Is this CRL the item being deleted?
  868. if (pcrl->atomPath == atomPath)
  869. {
  870. // Yes; delete the CRL
  871. CRL_Delete(atom);
  872. }
  873. break;
  874. case NOE_RENAME:
  875. case NOE_RENAMEFOLDER:
  876. // Is this CRL being renamed (inside briefcase only)?
  877. if (pcrl->atomPath == atomPath)
  878. {
  879. // FEATURE: Yes; mark it for renaming
  880. }
  881. break;
  882. case NOE_DIRTY:
  883. case NOE_DIRTYFOLDER:
  884. // Is the atomPath a folder and this CRL a child?
  885. if (bIsFolder && Atom_IsChildOf(pcrl->atomPath, atomPath))
  886. {
  887. // Yes; mark it
  888. DEBUG_CODE( LPCTSTR pszDbg = Atom_GetName(atom); )
  889. DEBUG_CODE( TRACE_MSG(TF_CACHE, TEXT("CACHE Tagging CRL for %s (0x%lx)"),
  890. pszDbg, pcrl->hbrf); )
  891. SetFlag(pcrl->uFlags, CRLF_DIRTY);
  892. bRet = TRUE;
  893. }
  894. break;
  895. }
  896. }
  897. // Is CRL's atomOutside a parent or equal of atomPath?
  898. if (Atom_IsParentOf(pcrl->atomOutside, atomPath))
  899. {
  900. // Yes; mark it
  901. DEBUG_CODE( LPCTSTR pszDbg = Atom_GetName(atom); )
  902. DEBUG_CODE( TRACE_MSG(TF_CACHE, TEXT("CACHE Tagging CRL for %s (0x%lx)"),
  903. pszDbg, pcrl->hbrf); )
  904. SetFlag(pcrl->uFlags, CRLF_DIRTY);
  905. bRet = TRUE;
  906. // Refresh this window?
  907. *pbRefresh = Atom_IsParentOf(atomCabFolder, atom);
  908. }
  909. Cache_DeleteItem(&g_cacheCRL, atom, FALSE, NULL, CRL_Free); // Decrement count
  910. }
  911. }
  912. Done:;
  913. }
  914. CRL_LeaveCS();
  915. return bRet;
  916. }
  917. /*----------------------------------------------------------
  918. Purpose: Mark the entire cache dirty
  919. Returns: --
  920. Cond: --
  921. */
  922. void PUBLIC CRL_DirtyAll(
  923. int atomBrf)
  924. {
  925. CRL_EnterCS();
  926. {
  927. CRL * pcrl;
  928. int atom;
  929. CRL_Iterate(atom)
  930. {
  931. pcrl = Cache_GetPtr(&g_cacheCRL, atom);
  932. ASSERT(pcrl);
  933. if (pcrl && pcrl->atomBrf == atomBrf)
  934. {
  935. DEBUG_CODE( LPCTSTR pszDbg = Atom_GetName(atom); )
  936. DEBUG_CODE( TRACE_MSG(TF_CACHE, TEXT("CACHE Tagging CRL for %s (0x%lx)"), pszDbg,
  937. pcrl->hbrf); )
  938. SetFlag(pcrl->uFlags, CRLF_DIRTY);
  939. Cache_DeleteItem(&g_cacheCRL, atom, FALSE, NULL, CRL_Free); // Decrement count
  940. }
  941. }
  942. }
  943. CRL_LeaveCS();
  944. }