NT4/private/windows/rover/filesync/syncui/crl.c
2020-09-30 17:12:29 +02:00

1153 lines
34 KiB
C

//---------------------------------------------------------------------------
//
// Copyright (c) Microsoft Corporation 1993-1994
//
// File: crl.c
//
// This files contains code for the cached reclists
//
// History:
// 09-02-93 ScottH Created
// 01-31-94 ScottH Moved from cache.c
//
//---------------------------------------------------------------------------
#include "brfprv.h" // common headers
#include "recact.h"
#include "res.h"
#define CRL_Iterate(atom) \
for (atom = Cache_FindFirstKey(&g_cacheCRL); \
ATOM_ERR != atom; \
atom = Cache_FindNextKey(&g_cacheCRL, atom))
CACHE g_cacheCRL = {0, 0, 0}; // Reclist cache
#define CRL_EnterCS() EnterCriticalSection(&g_cacheCRL.cs)
#define CRL_LeaveCS() LeaveCriticalSection(&g_cacheCRL.cs)
#ifdef DEBUG
/*----------------------------------------------------------
Purpose: Dump a CRL entry
Returns: --
Cond: --
*/
void PRIVATE CRL_DumpEntry(
CRL * pcrl)
{
TCHAR sz[MAXBUFLEN];
ASSERT(pcrl);
TRACE_MSG(TF_ALWAYS, TEXT("CRL: Atom %d: %s"), pcrl->atomPath, Atom_GetName(pcrl->atomPath));
TRACE_MSG(TF_ALWAYS, TEXT(" Outside %d: %s"), pcrl->atomOutside, Atom_GetName(pcrl->atomOutside));
TRACE_MSG(TF_ALWAYS, TEXT(" Ref [%u] Use [%u] %s %s %s %s"),
Cache_GetRefCount(&g_cacheCRL, pcrl->atomPath),
pcrl->ucUse,
CRL_IsOrphan(pcrl) ? (LPCTSTR) TEXT("Orphan") : (LPCTSTR) TEXT(""),
IsFlagSet(pcrl->uFlags, CRLF_DIRTY) ? (LPCTSTR) TEXT("Dirty") : (LPCTSTR) TEXT(""),
IsFlagSet(pcrl->uFlags, CRLF_NUKE) ? (LPCTSTR) TEXT("Nuke") : (LPCTSTR) TEXT(""),
CRL_IsSubfolderTwin(pcrl) ? (LPCTSTR) TEXT("SubfolderTwin") : (LPCTSTR) TEXT(""));
TRACE_MSG(TF_ALWAYS, TEXT(" Status: %s"), SzFromIDS(pcrl->idsStatus, sz, ARRAYSIZE(sz)));
}
void PUBLIC CRL_DumpAll()
{
CRL * pcrl;
int atom;
BOOL bDump;
ENTEREXCLUSIVE()
{
bDump = IsFlagSet(g_uDumpFlags, DF_CRL);
}
LEAVEEXCLUSIVE()
if (!bDump)
return ;
CRL_Iterate(atom)
{
pcrl = Cache_GetPtr(&g_cacheCRL, atom);
ASSERT(pcrl);
if (pcrl)
{
CRL_DumpEntry(pcrl);
Cache_DeleteItem(&g_cacheCRL, atom, FALSE, NULL, CRL_Free); // Decrement count
}
}
}
#endif
/*----------------------------------------------------------
Purpose: Return the resource string ID describing the action to take
Returns: --
Cond: --
*/
UINT PRIVATE IdsFromRAItem(
LPRA_ITEM pitem)
{
UINT ids;
ASSERT(IsFlagSet(pitem->mask, RAIF_ACTION));
switch (pitem->uAction)
{
case RAIA_TOOUT:
case RAIA_TOIN:
case RAIA_CONFLICT:
case RAIA_DELETEOUT:
case RAIA_DELETEIN:
case RAIA_MERGE:
case RAIA_SOMETHING:
ids = IDS_STATE_NeedToUpdate;
break;
case RAIA_ORPHAN:
ids = IDS_STATE_Orphan;
break;
case RAIA_DONTDELETE:
case RAIA_SKIP:
ASSERT(SI_UNAVAILABLE == pitem->siInside.uState ||
SI_UNAVAILABLE == pitem->siOutside.uState);
if (SI_UNAVAILABLE == pitem->siOutside.uState)
{
if (SI_UNCHANGED == pitem->siInside.uState)
{
ids = IDS_STATE_UptodateInBrf;
}
else if (SI_UNAVAILABLE != pitem->siInside.uState)
{
ids = IDS_STATE_NeedToUpdate;
}
else
{
ids = IDS_STATE_Unavailable;
}
}
else
{
ASSERT(SI_UNAVAILABLE == pitem->siInside.uState);
ids = IDS_STATE_Unavailable;
}
break;
case RAIA_NOTHING:
ids = IDS_STATE_Uptodate;
break;
default:
ASSERT(0);
ids = 0;
break;
}
return ids;
}
/*----------------------------------------------------------
Purpose: Gets the outside sync copy and the resource ID to the
status string that indicates the status between the
sync copies.
Returns: --
Cond: --
*/
void PRIVATE SetPairInfo(
PCRL pcrl)
{
LPCTSTR pszPath = Atom_GetName(pcrl->atomPath);
LPCTSTR pszName = PathFindFileName(pszPath);
// Is this an orphan?
if (CRL_IsOrphan(pcrl))
{
// Yes; special case: is this one of the briefcase system files?
LPCTSTR pszDBName;
if (IsFlagSet(pcrl->uFlags, CRLF_ISLFNDRIVE))
pszDBName = g_szDBName;
else
pszDBName = g_szDBNameShort;
if (IsSzEqual(pszName, pszDBName) ||
IsSzEqual(pszName, c_szDesktopIni))
{
// Yes
pcrl->idsStatus = IDS_STATE_SystemFile;
}
// Is this a subfolder twin? (Only orphans are
// candidates for being subfolder twins.)
else if (CRL_IsSubfolderTwin(pcrl))
{
// Yes
ASSERT(PathIsDirectory(pszPath));
pcrl->idsStatus = IDS_STATE_Subfolder;
}
else
{
// No
pcrl->idsStatus = IDS_STATE_Orphan;
}
if (Atom_IsValid(pcrl->atomOutside))
{
Atom_Delete(pcrl->atomOutside); // delete the old one
}
pcrl->atomOutside = Atom_Add(TEXT(""));
}
else
{
// No; get the info for this sync copy
HRESULT hres;
LPRA_ITEM pitem;
TCHAR sz[MAXPATHLEN];
ASSERT(pcrl->lprl);
hres = RAI_Create(&pitem, Atom_GetName(pcrl->atomBrf), pszPath,
pcrl->lprl, pcrl->lpftl);
if (SUCCEEDED(hres))
{
lstrcpy(sz, pitem->siOutside.pszDir);
// Is this a file?
if ( !CRL_IsFolder(pcrl) )
{
// Yes; atomOutside needs to be a fully qualified path to
// the outside file/folder--not just the parent folder.
// That's why we tack on the filename here.
PathAppend(sz, pszName);
}
if (Atom_IsValid(pcrl->atomOutside))
{
Atom_Delete(pcrl->atomOutside); // delete the old one
}
pcrl->atomOutside = Atom_Add(sz);
pcrl->idsStatus = IdsFromRAItem(pitem);
RAI_Free(pitem);
}
}
}
/*----------------------------------------------------------
Purpose: Determines whether or not a subfolder of a briefcase
is the root of a subtree twin.
Returns: --
Cond: --
*/
BOOL PRIVATE IsSubtreeTwin(HBRFCASE hbrf, LPCTSTR pcszFolder)
{
BOOL bIsSubtreeTwin = FALSE;
PFOLDERTWINLIST pftl;
ASSERT(PathIsDirectory(pcszFolder));
/* Create a folder twin list for the folder. */
if (Sync_CreateFolderList(hbrf, pcszFolder, &pftl) == TR_SUCCESS)
{
PCFOLDERTWIN pcft;
/*
* Look through the folder twin list for any folder twins with the
* FT_FL_SUBTREE flag set.
*/
for (pcft = pftl->pcftFirst; pcft; pcft = pcft->pcftNext)
{
if (pcft->dwFlags & FT_FL_SUBTREE)
{
bIsSubtreeTwin = TRUE;
break;
}
}
Sync_DestroyFolderList(pftl);
}
return(bIsSubtreeTwin);
}
/*----------------------------------------------------------
Purpose: Determines whether or not a path is a subfolder of a subtree twin in a
briefcase.
Returns: --
Cond: --
*/
BOOL PUBLIC IsSubfolderTwin(HBRFCASE hbrf, LPCTSTR pcszPath)
{
BOOL bIsSubfolderTwin = FALSE;
TCHAR szBrfRoot[MAXPATHLEN];
if (PathIsDirectory(pcszPath) &&
PathGetLocality(pcszPath, szBrfRoot) == PL_INSIDE)
{
int ncchBrfRootLen;
TCHAR szParent[MAXPATHLEN];
ASSERT(PathIsPrefix(pcszPath, szBrfRoot));
ncchBrfRootLen = lstrlen(szBrfRoot);
ASSERT(lstrlen(pcszPath) < ARRAYSIZE(szParent));
lstrcpy(szParent, pcszPath);
/*
* Keep whacking off the last path component until we find a parent
* subtree twin root, or we hit the briefcase root.
*/
while (! bIsSubfolderTwin &&
PathRemoveFileSpec(szParent) &&
lstrlen(szParent) > ncchBrfRootLen)
{
BOOL bIsFolderTwin;
if (Sync_IsFolder(hbrf, szParent, &bIsFolderTwin) == TR_SUCCESS &&
bIsFolderTwin)
{
bIsSubfolderTwin = IsSubtreeTwin(hbrf, szParent);
#ifdef DEBUG
TRACE_MSG(TF_CACHE, TEXT("CACHE Found subfolder twin %s with parent subtree twin root %s."),
pcszPath,
szParent);
#endif
}
}
}
return(bIsSubfolderTwin);
}
/*----------------------------------------------------------
Purpose: Sets the bSubfolderTwin member of a CRL.
Returns: --
Cond: The lprl and lpftl members of the CRL must be filled in before calling
this function.
*/
void PRIVATE SetSubfolderTwinFlag(PCRL pcrl)
{
if (! pcrl->lprl && ! pcrl->lpftl)
{
if (IsSubfolderTwin(pcrl->hbrf, Atom_GetName(pcrl->atomPath)))
SetFlag(pcrl->uFlags, CRLF_SUBFOLDERTWIN);
else
ClearFlag(pcrl->uFlags, CRLF_SUBFOLDERTWIN);
}
else
{
ClearFlag(pcrl->uFlags, CRLF_SUBFOLDERTWIN);
}
}
/*----------------------------------------------------------
Purpose: Free the reclist
Returns: --
Cond: hwndOwner is not used, so it is okay for all CRL_ routines
to pass NULL as hwndOwner.
This function is serialized by the caller (Cache_Term or
Cache_DeleteItem).
*/
void CALLBACK CRL_Free(
LPVOID lpv,
HWND hwndOwner)
{
CRL * pcrl = (CRL *)lpv;
ASSERT(Sync_IsEngineLoaded());
DEBUG_CODE( TRACE_MSG(TF_CACHE, TEXT("CACHE Destroying CRL for %s (0x%lx)"),
Atom_GetName(pcrl->atomPath), pcrl->hbrf); )
if (Atom_IsValid(pcrl->atomOutside))
Atom_Delete(pcrl->atomOutside);
if (Atom_IsValid(pcrl->atomBrf))
Atom_Delete(pcrl->atomBrf);
if (pcrl->lprl)
Sync_DestroyRecList(pcrl->lprl);
if (pcrl->lpftl)
Sync_DestroyFolderList(pcrl->lpftl);
// The CRL does not own pabortevt, leave it alone
SharedFree(&pcrl);
}
/*----------------------------------------------------------
Purpose: Create a reclist and (optional) folder twin list for a path.
Returns: standard result
S_OK if the item is a twin
S_FALSE if the item is an orphan
Cond: --
*/
HRESULT PRIVATE CreatePathLists(
HBRFCASE hbrf,
PABORTEVT pabortevt,
int atomPath,
PRECLIST * lplprl,
PFOLDERTWINLIST * lplpftl)
{
HRESULT hres;
LPCTSTR pszPath = Atom_GetName(atomPath);
ASSERT(pszPath);
ASSERT(hbrf);
ASSERT(lplprl);
ASSERT(lplpftl);
*lplprl = NULL;
*lplpftl = NULL;
// Two routes.
//
// 1) If the path is to the root of a briefcase,
// create a complete reclist.
//
// 2) Otherwise create a reclist for the individual file or folder
//
// Hack: a quick way of telling if atomPath is a briefcase
// root is by looking for it in the CBS cache.
// Is this the root of a briefcase?
if (CBS_Get(atomPath))
{
// Yes
CBS_Delete(atomPath, NULL); // Decrement count
hres = Sync_CreateCompleteRecList(hbrf, pabortevt, lplprl);
}
else
{
// No; is this a twin?
hres = Sync_IsTwin(hbrf, pszPath, 0);
if (S_OK == hres)
{
// Yes; create a reclist (and an optional folder twin list).
HTWINLIST htl;
hres = E_OUTOFMEMORY; // assume error
if (Sync_CreateTwinList(hbrf, &htl) == TR_SUCCESS)
{
if (Sync_AddPathToTwinList(hbrf, htl, pszPath, lplpftl))
{
hres = Sync_CreateRecListEx(htl, pabortevt, lplprl);
if (SUCCEEDED(hres))
{
// The object may have been implicitly deleted
// in CreateRecList. Check again.
hres = Sync_IsTwin(hbrf, pszPath, 0);
}
}
Sync_DestroyTwinList(htl);
}
}
}
if (FAILED(hres))
{
// Cleanup on failure
//
if (*lplpftl)
Sync_DestroyFolderList(*lplpftl);
*lplprl = NULL;
*lplpftl = NULL;
}
return hres;
}
/*----------------------------------------------------------
Purpose: Add a CRL entry for the atomPath to the cache. This
consists of creating the reclist (and folder twin list
possibly).
If the atomPath is already in the cache, this function
increments the reference count of the item and calls
CRL_Replace.
Returns: standard result
Cond: Must call CRL_Delete for every call to this function.
IMPORTANT: Some portions of code call PathIsDirectory,
which will fail if atomPath does not exist.
*/
HRESULT PUBLIC CRL_Add(
PCBS pcbs,
int atomPath)
{
HRESULT hres = E_OUTOFMEMORY;
PRECLIST lprl = NULL;
PFOLDERTWINLIST lpftl = NULL;
CRL * pcrl;
ASSERT(pcbs);
CRL_EnterCS();
{
// Caller wants to add. If it already exists, we simply return
// the existing entry.
//
// This CRL_Get increments the count (if it succeeds)
pcrl = Cache_GetPtr(&g_cacheCRL, atomPath);
// Is the item in the cache?
if (pcrl)
{
// Yes; attempt to get fresh contents
hres = CRL_Replace(atomPath);
}
else
{
// No; the entry is not in the cache. Add it.
LPCTSTR pszPath = Atom_GetName(atomPath);
ASSERT(pszPath);
DEBUG_CODE( TRACE_MSG(TF_CACHE, TEXT("CACHE Adding CRL for %s (0x%lx)"),
pszPath, pcbs->hbrf); )
// Leave the critical section while we do expensive calculation
CRL_LeaveCS();
{
hres = CreatePathLists(pcbs->hbrf, pcbs->pabortevt,
atomPath, &lprl, &lpftl);
}
CRL_EnterCS();
if (FAILED(hres))
goto Fail;
else
{
LPCTSTR pszBrf;
// Allocate using commctrl's Alloc, so the structure will be in
// shared heap space across processes.
pcrl = SharedAllocType(CRL);
if (!pcrl)
{
hres = E_OUTOFMEMORY;
goto Fail;
}
pcrl->atomPath = atomPath;
pcrl->hbrf = pcbs->hbrf;
pszBrf = Atom_GetName(pcbs->atomBrf);
pcrl->atomBrf = Atom_Add(pszBrf);
pcrl->pabortevt = pcbs->pabortevt;
pcrl->lpftl = lpftl;
pcrl->lprl = lprl;
pcrl->ucUse = 0;
pcrl->uFlags = 0; // reset
SetSubfolderTwinFlag(pcrl);
if (S_FALSE == hres)
SetFlag(pcrl->uFlags, CRLF_ORPHAN);
if (PathIsDirectory(Atom_GetName(atomPath)))
SetFlag(pcrl->uFlags, CRLF_ISFOLDER);
if (IsFlagSet(pcbs->uFlags, CBSF_LFNDRIVE))
SetFlag(pcrl->uFlags, CRLF_ISLFNDRIVE);
SetPairInfo(pcrl);
// This Cache_AddItem does the increment count
if ( !Cache_AddItem(&g_cacheCRL, atomPath, (LPVOID)pcrl) )
{
// Failed
Atom_Delete(pcrl->atomBrf);
Atom_Delete(pcrl->atomOutside);
hres = E_OUTOFMEMORY;
goto Fail;
}
}
}
}
CRL_LeaveCS();
return hres;
Fail:
// Cleanup on failure
//
if (lprl)
Sync_DestroyRecList(lprl);
if (lpftl)
Sync_DestroyFolderList(lpftl);
SharedFree(&pcrl);
CRL_LeaveCS();
DEBUG_MSG(TF_ERROR, TEXT("SyncUI CRL_Add failed!"));
return hres;
}
/*----------------------------------------------------------
Purpose: Decrement the reference count and the use count to
the reclist cache entry.
If the reference count == 0, the entry is deleted.
Returns: --
Cond: --
*/
void PUBLIC CRL_Delete(
int atomPath)
{
CRL * pcrl;
CRL_EnterCS();
{
// Decrement the use count
//
pcrl = Cache_GetPtr(&g_cacheCRL, atomPath);
if (pcrl)
{
DEBUG_CODE( LPCTSTR pszPath = Atom_GetName(atomPath); )
if (pcrl->ucUse > 0)
pcrl->ucUse--;
if (IsFlagSet(pcrl->uFlags, CRLF_NUKE))
{
if (pcrl->ucUse == 0)
{
DEBUG_CODE( TRACE_MSG(TF_CACHE, TEXT("CACHE Nuking late CRL %s..."),
pszPath); )
// A nuke was deferred. Now we can really do it.
//
Cache_DeleteItem(&g_cacheCRL, atomPath, TRUE, NULL, CRL_Free);
goto Done;
}
#ifdef DEBUG
else
{
TRACE_MSG(TF_CACHE, TEXT("CACHE Deferring nuke CRL %s..."),
pszPath);
}
#endif
}
Cache_DeleteItem(&g_cacheCRL, atomPath, FALSE, NULL, CRL_Free); // Decrement for Cache_GetPtr
// The real delete...
Cache_DeleteItem(&g_cacheCRL, atomPath, FALSE, NULL, CRL_Free);
}
Done:;
}
CRL_LeaveCS();
}
/*----------------------------------------------------------
Purpose: Nuke the cache entry if the use count is 0. Otherwise,
set the nuke bit, and this entry will get nuked on the
next CRL_Get when the use count is 0.
Returns: --
Cond: --
*/
void PUBLIC CRL_Nuke(
int atomPath)
{
CRL * pcrl;
CRL_EnterCS();
{
// Check the use count
//
pcrl = Cache_GetPtr(&g_cacheCRL, atomPath);
if (pcrl)
{
if (pcrl->ucUse > 0)
{
DEBUG_CODE( TRACE_MSG(TF_CACHE, TEXT("CACHE Marking to nuke CRL for %s (0x%lx)"),
Atom_GetName(atomPath), pcrl->hbrf); )
SetFlag(pcrl->uFlags, CRLF_NUKE);
Cache_DeleteItem(&g_cacheCRL, atomPath, FALSE, NULL, CRL_Free); // Decrement for Cache_GetPtr
}
else
{
DEBUG_CODE( TRACE_MSG(TF_CACHE, TEXT("CACHE Nuking CRL for %s (0x%lx)"),
Atom_GetName(atomPath), pcrl->hbrf); )
Cache_DeleteItem(&g_cacheCRL, atomPath, TRUE, NULL, CRL_Free);
}
}
}
CRL_LeaveCS();
}
/*----------------------------------------------------------
Purpose: Replace the atomPath in the cache. This consists of
creating the reclist (and folder twin list possibly)
and replacing the contents of pcrl.
The pcrl pointer remains unchanged.
The reference and use-counts remain unchanged.
Returns: standard result
Cond:
IMPORTANT: Some portions of code call PathIsDirectory,
which will fail if atomPath does not exist.
*/
HRESULT PUBLIC CRL_Replace(
int atomPath)
{
HRESULT hres;
CRL * pcrl;
CRL_EnterCS();
{
pcrl = Cache_GetPtr(&g_cacheCRL, atomPath);
// Does the item exist?
if (pcrl)
{
DEBUG_CODE( LPCTSTR pszPath = Atom_GetName(atomPath); )
ASSERT(pszPath);
DEBUG_CODE( TRACE_MSG(TF_CACHE, TEXT("CACHE Replacing CRL for %s (0x%lx)"),
pszPath, pcrl->hbrf); )
// Yes; mark it dirty and call CRL_Get on it.
SetFlag(pcrl->uFlags, CRLF_DIRTY);
// Note: pay attention to the difference between Cache_Delete
// and CRL_Delete. Cache_Delete must match Cache_Add/Get and
// CRL_Delete must match CRL_Add/Get.
//
Cache_DeleteItem(&g_cacheCRL, atomPath, FALSE, NULL, CRL_Free); // Decrement count for Cache_GetPtr
hres = CRL_Get(atomPath, &pcrl); // This does the replace
CRL_Delete(atomPath); // Decrement count for CRL_Get
}
else
{
hres = E_FAIL;
}
}
CRL_LeaveCS();
return hres;
}
/*----------------------------------------------------------
Purpose: Get the reclist from the cache. If the cache item exists
and is marked dirty and the use count is 0, then recreate
the reclist.
If the nuke bit is set, then the entry is nuked and this
function returns NULL.
Returns: standard result
Ptr to cache entry.
Cond: Must call CRL_Delete for every call to CRL_Get
IMPORTANT: Some portions of code call PathIsDirectory,
which will fail if atomPath does not exist.
*/
HRESULT PUBLIC CRL_Get(
int atomPath,
PCRL * ppcrl)
{
HRESULT hres;
PCRL pcrl;
PRECLIST lprl = NULL;
PFOLDERTWINLIST lpftl = NULL;
CRL_EnterCS();
{
// Don't need to decrement the reference count in this
// function -- this is Get!
//
pcrl = Cache_GetPtr(&g_cacheCRL, atomPath);
if (pcrl)
{
HBRFCASE hbrf = pcrl->hbrf;
// Is this item pending a nuke?
if (IsFlagSet(pcrl->uFlags, CRLF_NUKE))
{
// Yes; return NULL as if it were already nuked.
DEBUG_CODE( LPCTSTR pszPath = Atom_GetName(atomPath); )
DEBUG_CODE( TRACE_MSG(TF_CACHE, TEXT("CACHE Attempt to get deferred nuke CRL %s (0x%lx)..."),
pszPath, hbrf); )
// (Decrement counter for Cache_GetPtr to keep count even,
// since we are returning NULL.)
Cache_DeleteItem(&g_cacheCRL, atomPath, FALSE, NULL, CRL_Free);
pcrl = NULL;
hres = E_FAIL;
}
// Is this item tagged dirty and the use-count is 0?
else if (IsFlagSet(pcrl->uFlags, CRLF_DIRTY) && pcrl->ucUse == 0)
{
// Yes; we are free to re-create the reclist.
LPCTSTR pszPath = Atom_GetName(atomPath);
ASSERT(pszPath);
DEBUG_CODE( TRACE_MSG(TF_CACHE, TEXT("CACHE Getting clean CRL %s (0x%lx)..."),
pszPath, hbrf); )
// Since we'll be leaving the critical section below,
// temporarily increase the use count to keep the pcrl
// from getting nuked from under us.
pcrl->ucUse++;
// Replace the contents of the cache entry
// Leave the critical section while we do expensive calculation
CRL_LeaveCS();
{
hres = CreatePathLists(hbrf, pcrl->pabortevt, atomPath,
&lprl, &lpftl);
}
CRL_EnterCS();
// Decrement use count
pcrl->ucUse--;
if (FAILED(hres))
{
DEBUG_CODE( DEBUG_MSG(TF_ERROR, TEXT("SyncUI CRL_Get failed in cleaning dirty entry!")); )
// Still return pcrl since it exists
hres = NOERROR;
}
else
{
// Put the new lists in the cache entry
if (pcrl->lprl)
{
Sync_DestroyRecList(pcrl->lprl);
}
pcrl->lprl = lprl;
if (pcrl->lpftl)
{
Sync_DestroyFolderList(pcrl->lpftl);
}
pcrl->lpftl = lpftl;
if (S_FALSE == hres)
SetFlag(pcrl->uFlags, CRLF_ORPHAN);
else
{
ASSERT(S_OK == hres);
ClearFlag(pcrl->uFlags, CRLF_ORPHAN);
}
ClearFlag(pcrl->uFlags, CRLF_DIRTY);
SetSubfolderTwinFlag(pcrl);
SetPairInfo(pcrl);
hres = NOERROR;
}
}
else
{
#ifdef DEBUG
LPCTSTR pszPath = Atom_GetName(atomPath);
ASSERT(pszPath);
if (IsFlagSet(pcrl->uFlags, CRLF_DIRTY))
{
TRACE_MSG(TF_CACHE, TEXT("CACHE Getting dirty CRL %s (0x%lx)..."),
pszPath, hbrf);
}
else
{
TRACE_MSG(TF_CACHE, TEXT("CACHE Getting CRL %s (0x%lx)..."),
pszPath, hbrf);
}
#endif
hres = NOERROR;
}
}
else
hres = E_FAIL;
// Now increment the use count
//
if (pcrl)
pcrl->ucUse++;
*ppcrl = pcrl;
ASSERT((FAILED(hres) && !*ppcrl) ||
(SUCCEEDED(hres) && *ppcrl));
}
CRL_LeaveCS();
return hres;
}
/*----------------------------------------------------------
Purpose: Mark any related CRLs dirty. Which CRLs get marked dirty
depends on the lEvent.
In addition, *pbRefresh is set to TRUE if the window that
is calling this function should refresh itself.
(N.b. in the following rules, we never refresh the immediate
folder unless explicitly stated, since the shell will do this
automatically. E.g., if C:\Bar\Foo.txt received NOE_DIRTYITEM,
the shell will automatically repaint C:\Bar.)
Rules:
NOE_CREATE Cause: A file is created.
Dirty? Any CRLs whose atomInside or atomOutside
are parents or equal to atomPath.
Refresh? Only in windows of parent folders on either
side OR
in immediate window on the briefcase side
if atomPath was created on the outside.
NOE_CREATEFOLDER same as above
NOE_DELETE Cause: A file or folder was deleted.
Dirty? Any CRLs whose atomInside or atomOutside
are parents or equal to atomPath.
Delete CRL if atomPath matches atomInside
Refresh? Only in windows of parent folders on either
side OR
in immediate window on the briefcase side
if atomPath was deleted on the outside.
NOE_DELETEFOLDER same as above
NOE_RENAME Cause: A file or folder was renamed or moved.
Dirty? Any CRLs whose atomInside or atomOutside
are parents or equal to atomPath.
Rename CRL (and related database entry) if
atomPath is inside briefcase
Refresh? Only in windows of parent folders on either
side OR
in immediate window on the briefcase side
if atomPath is renamed on the outside.
NOE_RENAMEFOLDER same as above
NOE_DIRTY Cause: Varies. Typically something needs refreshed.
Dirty? Any CRLs whose atomInside or atomOutside
are parents or equal to atomPath.
If atomPath is folder, any CRLs which are
children of atomPath.
Refresh? Only in windows of parent folders on either
side OR
in immediate window on the briefcase side
if atomPath is updated on the outside.
Returns: FALSE if nothing was marked
TRUE if something was marked
Cond: --
*/
BOOL PUBLIC CRL_Dirty(
int atomPath,
int atomCabFolder, // path of open cabinet window
LONG lEvent,
LPBOOL pbRefresh) // return TRUE to refresh cabinet window
{
BOOL bRet = FALSE;
CRL * pcrl;
int atom;
int atomParent;
ASSERT(pbRefresh);
*pbRefresh = FALSE;
CRL_EnterCS();
{
BOOL bIsFolder;
// Get the atomParent of the atomPath
TCHAR szParent[MAXPATHLEN];
lstrcpy(szParent, Atom_GetName(atomPath));
PathRemoveFileSpec(szParent);
if (0 == *szParent) // skip blank parent paths
goto Done;
atomParent = Atom_Add(szParent);
if (ATOM_ERR == atomParent)
goto Done;
// Is the path that is being updated a folder?
pcrl = Cache_GetPtr(&g_cacheCRL, atomPath);
if (pcrl)
{
bIsFolder = CRL_IsFolder(pcrl);
Cache_DeleteItem(&g_cacheCRL, atomPath, FALSE, NULL, CRL_Free); // Decrement count
}
else
{
bIsFolder = FALSE;
}
CRL_Iterate(atom)
{
pcrl = Cache_GetPtr(&g_cacheCRL, atom);
ASSERT(pcrl);
if (pcrl)
{
// Is CRL a parent or equal of atomPath?
if (Atom_IsParentOf(atom, atomPath))
{
// Yes; mark it
DEBUG_CODE( LPCTSTR pszDbg = Atom_GetName(atom); )
DEBUG_CODE( TRACE_MSG(TF_CACHE, TEXT("CACHE Tagging CRL for %s (0x%lx)"),
pszDbg, pcrl->hbrf); )
SetFlag(pcrl->uFlags, CRLF_DIRTY);
bRet = TRUE;
// Refresh this window?
// (Only if the cabinet folder is > than an immediate
// parent folder.)
*pbRefresh = Atom_IsParentOf(atomCabFolder, atom) &&
atomCabFolder != atomParent;
switch (lEvent)
{
case NOE_DELETE:
case NOE_DELETEFOLDER:
// Is this CRL the item being deleted?
if (pcrl->atomPath == atomPath)
{
// Yes; delete the CRL
CRL_Delete(atom);
}
break;
case NOE_RENAME:
case NOE_RENAMEFOLDER:
// Is this CRL being renamed (inside briefcase only)?
if (pcrl->atomPath == atomPath)
{
// Yes; mark it for renaming
// BUGBUG
}
break;
case NOE_DIRTY:
case NOE_DIRTYFOLDER:
// Is the atomPath a folder and this CRL a child?
if (bIsFolder && Atom_IsChildOf(pcrl->atomPath, atomPath))
{
// Yes; mark it
DEBUG_CODE( LPCTSTR pszDbg = Atom_GetName(atom); )
DEBUG_CODE( TRACE_MSG(TF_CACHE, TEXT("CACHE Tagging CRL for %s (0x%lx)"),
pszDbg, pcrl->hbrf); )
SetFlag(pcrl->uFlags, CRLF_DIRTY);
bRet = TRUE;
}
break;
}
}
// Is CRL's atomOutside a parent or equal of atomPath?
if (Atom_IsParentOf(pcrl->atomOutside, atomPath))
{
// Yes; mark it
DEBUG_CODE( LPCTSTR pszDbg = Atom_GetName(atom); )
DEBUG_CODE( TRACE_MSG(TF_CACHE, TEXT("CACHE Tagging CRL for %s (0x%lx)"),
pszDbg, pcrl->hbrf); )
SetFlag(pcrl->uFlags, CRLF_DIRTY);
bRet = TRUE;
// Refresh this window?
*pbRefresh = Atom_IsParentOf(atomCabFolder, atom);
}
Cache_DeleteItem(&g_cacheCRL, atom, FALSE, NULL, CRL_Free); // Decrement count
}
}
Done:;
}
CRL_LeaveCS();
return bRet;
}
/*----------------------------------------------------------
Purpose: Mark the entire cache dirty
Returns: --
Cond: --
*/
void PUBLIC CRL_DirtyAll(
int atomBrf)
{
CRL_EnterCS();
{
CRL * pcrl;
int atom;
CRL_Iterate(atom)
{
pcrl = Cache_GetPtr(&g_cacheCRL, atom);
ASSERT(pcrl);
if (pcrl && pcrl->atomBrf == atomBrf)
{
DEBUG_CODE( LPCTSTR pszDbg = Atom_GetName(atom); )
DEBUG_CODE( TRACE_MSG(TF_CACHE, TEXT("CACHE Tagging CRL for %s (0x%lx)"), pszDbg,
pcrl->hbrf); )
SetFlag(pcrl->uFlags, CRLF_DIRTY);
Cache_DeleteItem(&g_cacheCRL, atom, FALSE, NULL, CRL_Free); // Decrement count
}
}
}
CRL_LeaveCS();
}