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

349 lines
10 KiB
C

/*
* subcycle.c - Subtree cycle detection routines module.
*/
/* Headers
**********/
#include "project.h"
#pragma hdrstop
#include "stub.h"
#include "subcycle.h"
/* Constants
************/
/* pointer array allocation constants */
#define NUM_CYCLE_PTRS_TO_ADD (16)
/***************************** Private Functions *****************************/
/* Module Prototypes
********************/
PRIVATE_CODE TWINRESULT CheckHalfForSubtreeCycle(HPTRARRAY, HPATH, HPATH, LPCTSTR);
/*
** CheckHalfForSubtreeCycle()
**
** Checks to see if half of a proposed new folder subtree twin would create one
** or more cycles of folder subtree twins.
**
** Arguments: hpaFolderPairs - handle to PTRARRAY containing pointers to
** folder pairs
** hpathStartFolder - root folder of initial half of proposed
** new folder pair
** hpathEndFolder - root folder of other half of proposed new
** folder pair
** pcszName - name specification of matching objects to be
** included in proposed new folder subtree pair
**
** Returns: TWINRESULT
**
** Side Effects: none
**
** N.b., this function should be called twice for each proposed new folder
** subtree pair.
*/
PRIVATE_CODE TWINRESULT CheckHalfForSubtreeCycle(HPTRARRAY hpaFolderPairs,
HPATH hpathStartFolder,
HPATH hpathEndFolder,
LPCTSTR pcszName)
{
TWINRESULT tr;
ARRAYINDEX aicFolderPairs;
NEWPTRARRAY npa;
HPTRARRAY hpaFolders;
ASSERT(IS_VALID_HANDLE(hpaFolderPairs, PTRARRAY));
ASSERT(IS_VALID_HANDLE(hpathStartFolder, PATH));
ASSERT(IS_VALID_HANDLE(hpathEndFolder, PATH));
ASSERT(IS_VALID_STRING_PTR(pcszName, CSTR));
aicFolderPairs = GetPtrCount(hpaFolderPairs);
/*
* Try to create an unsorted pointer array to be used in checking for
* cycles.
*/
npa.aicInitialPtrs = aicFolderPairs;
npa.aicAllocGranularity = NUM_CYCLE_PTRS_TO_ADD;
npa.dwFlags = 0;
if (CreatePtrArray(&npa, &hpaFolders))
{
ARRAYINDEX aicFolders;
ARRAYINDEX aiCurFolder;
HPATH hpathCurFolderRoot;
/* Search all folder pairs connected to the first new folder twin. */
/*
* Mark all folder twins unused. A "used" folder twin is one that has
* already been visited while searching for subtree cycles. I.e., a
* used folder subtree pair half intersected the first folder of the
* proposed new folder twin, and its other half was added to the list for
* later comparison.
*/
ClearFlagInArrayOfStubs(hpaFolderPairs, STUB_FL_USED);
/*
* Loop to process entire graph of folder subtree twins connected to the
* first new folder twin. Folder twins are only added to the hpaFolders
* array if they don't already intersect the second of the two proposed
* new folder subtree twins.
*/
tr = TR_SUCCESS;
aicFolders = 0;
aiCurFolder = 0;
/* Begin with start folder. */
hpathCurFolderRoot = hpathStartFolder;
FOREVER
{
ARRAYINDEX aiCheckFolderRoot;
/*
* Loop to find all subtree folder pairs that intersect
* hpaFolders[aiCurFolder]'s subtree.
*/
for (aiCheckFolderRoot = 0;
aiCheckFolderRoot < aicFolderPairs;
aiCheckFolderRoot++)
{
PFOLDERPAIR pfpCheck;
/* Get this subtree folder pair's root folder. */
pfpCheck = GetPtr(hpaFolderPairs, aiCheckFolderRoot);
ASSERT(IS_VALID_STRUCT_PTR(pfpCheck, CFOLDERPAIR));
/* Have we already visited this folder pair? */
if (IsStubFlagSet(&(pfpCheck->stub), STUB_FL_SUBTREE) &&
IsStubFlagClear(&(pfpCheck->stub), STUB_FL_BEING_TRANSLATED) &&
IsStubFlagClear(&(pfpCheck->stub), STUB_FL_USED) &&
IsStubFlagClear(&(pfpCheck->pfpOther->stub), STUB_FL_USED))
{
/*
* No. Does this subtree folder pair intersect the current
* folder pair node's subtree, and the objects named in the
* proposed new folder subtree twin?
*/
ASSERT(IsStubFlagSet(&(pfpCheck->pfpOther->stub), STUB_FL_SUBTREE));
ASSERT(IsStubFlagClear(&(pfpCheck->pfpOther->stub), STUB_FL_BEING_TRANSLATED));
if (SubtreesIntersect(hpathCurFolderRoot, pfpCheck->hpath) &&
NamesIntersect(GetString(pfpCheck->pfpd->hsName), pcszName))
{
HPATH hpathOtherCheckFolderRoot;
/* Yes. Get the other side of the folder subtree pair. */
hpathOtherCheckFolderRoot = pfpCheck->pfpOther->hpath;
/*
* Does this pair connect back to the other side of the
* proposed new folder pair?
*/
if (SubtreesIntersect(hpathOtherCheckFolderRoot,
hpathEndFolder))
{
/*
* Yes. Are the roots different parts of the common
* subtree?
*/
if (ComparePaths(hpathEndFolder,
hpathOtherCheckFolderRoot)
!= CR_EQUAL)
{
/* Yes. Found a cycle. Bail out. */
WARNING_OUT((TEXT("CheckHalfForSubtreeCycle(): Subtree cycle found connecting folders %s and %s."),
DebugGetPathString(hpathStartFolder),
DebugGetPathString(hpathEndFolder)));
tr = TR_SUBTREE_CYCLE_FOUND;
break;
}
/*
* We don't need to include this root in the search if it
* is the same as the other side of the proposed new
* folder pair since it will be covered during the other
* call to CheckHalfForSubtreeCycle().
*/
}
else
{
/* Add this subtree as another node to be examined. */
if (! InsertPtr(hpaFolders, NULL, aicFolders++,
(PCVOID)(pfpCheck->pfpOther)))
tr = TR_OUT_OF_MEMORY;
}
/* Mark this folder twin as already visited. */
if (tr == TR_SUCCESS)
SetStubFlag(&(pfpCheck->stub), STUB_FL_USED);
else
break;
}
}
}
/* Any folder subtree twins left to investigate? */
if (aiCurFolder < aicFolders)
{
PFOLDERPAIR pfpCur;
/* Yes. */
pfpCur = GetPtr(hpaFolders, aiCurFolder++);
hpathCurFolderRoot = pfpCur->hpath;
}
else
/* No. */
break;
}
DestroyPtrArray(hpaFolders);
}
else
tr = TR_OUT_OF_MEMORY;
return(tr);
}
/****************************** Public Functions *****************************/
/*
** BeginTranslateFolder()
**
**
**
** Arguments:
**
** Returns:
**
** Side Effects: none
*/
PUBLIC_CODE void BeginTranslateFolder(PFOLDERPAIR pfp)
{
ASSERT(IS_VALID_STRUCT_PTR(pfp, CFOLDERPAIR));
ASSERT(IsStubFlagClear(&(pfp->stub), STUB_FL_BEING_TRANSLATED));
ASSERT(IsStubFlagClear(&(pfp->pfpOther->stub), STUB_FL_BEING_TRANSLATED));
SetStubFlag(&(pfp->stub), STUB_FL_BEING_TRANSLATED);
SetStubFlag(&(pfp->pfpOther->stub), STUB_FL_BEING_TRANSLATED);
return;
}
/*
** EndTranslateFolder()
**
**
**
** Arguments:
**
** Returns:
**
** Side Effects: none
*/
PUBLIC_CODE void EndTranslateFolder(PFOLDERPAIR pfp)
{
ASSERT(IS_VALID_STRUCT_PTR(pfp, CFOLDERPAIR));
ASSERT(IsStubFlagSet(&(pfp->stub), STUB_FL_BEING_TRANSLATED));
ASSERT(IsStubFlagSet(&(pfp->pfpOther->stub), STUB_FL_BEING_TRANSLATED));
ClearStubFlag(&(pfp->stub), STUB_FL_BEING_TRANSLATED);
ClearStubFlag(&(pfp->pfpOther->stub), STUB_FL_BEING_TRANSLATED);
return;
}
/*
** CheckForSubtreeCycles()
**
** Checks to see if a proposed new folder subtree twin would create one or more
** cycles of folder subtree twins.
**
** Arguments:
**
** Returns: TWINRESULT
**
** Side Effects: none
**
** N.b., TR_SUBTREE_CYCLE_FOUND is returned if the folder subtree roots of the
** proposed new folder subtree twin are the same.
*/
PUBLIC_CODE TWINRESULT CheckForSubtreeCycles(HPTRARRAY hpaFolderPairs,
HPATH hpathFirstFolder,
HPATH hpathSecondFolder,
HSTRING hsName)
{
TWINRESULT tr;
ASSERT(IS_VALID_HANDLE(hpaFolderPairs, PTRARRAY));
ASSERT(IS_VALID_HANDLE(hpathFirstFolder, PATH));
ASSERT(IS_VALID_HANDLE(hpathSecondFolder, PATH));
ASSERT(IS_VALID_HANDLE(hsName, STRING));
/* Are the folder twins cyclical on their own? */
if (SubtreesIntersect(hpathFirstFolder, hpathSecondFolder))
{
/* Yes. */
tr = TR_SUBTREE_CYCLE_FOUND;
WARNING_OUT((TEXT("CheckForSubtreeCycles(): Subtree cycle found connecting folders %s and %s."),
DebugGetPathString(hpathFirstFolder),
DebugGetPathString(hpathSecondFolder)));
}
else
{
LPCTSTR pcszName;
/* No. Check for any indirect subtree cycle. */
pcszName = GetString(hsName);
tr = CheckHalfForSubtreeCycle(hpaFolderPairs, hpathFirstFolder,
hpathSecondFolder, pcszName);
if (tr == TR_SUCCESS)
tr = CheckHalfForSubtreeCycle(hpaFolderPairs, hpathSecondFolder,
hpathFirstFolder, pcszName);
}
return(tr);
}