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
1471 lines
38 KiB
/*
|
|
* expandft.c - Routines for expanding folder twins to object twins.
|
|
*/
|
|
|
|
|
|
/* Headers
|
|
**********/
|
|
|
|
#include "project.h"
|
|
#pragma hdrstop
|
|
|
|
#include "stub.h"
|
|
|
|
|
|
/* Constants
|
|
************/
|
|
|
|
/* for subtree folder searching */
|
|
|
|
#define STAR_DOT_STAR TEXT("*.*")
|
|
|
|
|
|
/* Macros
|
|
*********/
|
|
|
|
/* name component macros used by NameComponentsIntersect() */
|
|
|
|
#define COMPONENT_CHARS_MATCH(ch1, ch2) (CharLower((PTSTR)(DWORD_PTR)ch1) == CharLower((PTSTR)(DWORD_PTR)ch2) || (ch1) == QMARK || (ch2) == QMARK)
|
|
|
|
#define IS_COMPONENT_TERMINATOR(ch) (! (ch) || (ch) == PERIOD || (ch) == ASTERISK)
|
|
|
|
|
|
/* Types
|
|
********/
|
|
|
|
/* find structure used by ExpandSubtree() */
|
|
|
|
typedef struct _findstate
|
|
{
|
|
HANDLE hff;
|
|
|
|
WIN32_FIND_DATA wfd;
|
|
}
|
|
FINDSTATE;
|
|
DECLARE_STANDARD_TYPES(FINDSTATE);
|
|
|
|
/* information structure passed to GenerateObjectTwinFromFolderTwinProc() */
|
|
|
|
typedef struct _expandsubtreetwininfo
|
|
{
|
|
PFOLDERPAIR pfp;
|
|
|
|
UINT ucbSubtreeRootPathLen;
|
|
|
|
HCLSIFACECACHE hcic;
|
|
|
|
CREATERECLISTPROC crlp;
|
|
|
|
LPARAM lpCallbackData;
|
|
|
|
TWINRESULT tr;
|
|
}
|
|
EXPANDSUBTREETWININFO;
|
|
DECLARE_STANDARD_TYPES(EXPANDSUBTREETWININFO);
|
|
|
|
|
|
/* Module Variables
|
|
*******************/
|
|
|
|
/*
|
|
* folder names to be avoided during subtree expansion (comparison is
|
|
* case-insensitive)
|
|
*/
|
|
|
|
PRIVATE_DATA CONST LPCTSTR MrgcpcszFoldersToAvoid[] =
|
|
{
|
|
TEXT("."),
|
|
TEXT("..")
|
|
};
|
|
|
|
|
|
/***************************** Private Functions *****************************/
|
|
|
|
/* Module Prototypes
|
|
********************/
|
|
|
|
PRIVATE_CODE BOOL SetObjectTwinFileStamp(POBJECTTWIN, PVOID);
|
|
PRIVATE_CODE void MarkFolderTwinDeletionPending(PFOLDERPAIR);
|
|
PRIVATE_CODE void UnmarkFolderTwinDeletionPending(PFOLDERPAIR);
|
|
PRIVATE_CODE TWINRESULT ExpandFolderTwin(PFOLDERPAIR, HCLSIFACECACHE, CREATERECLISTPROC, LPARAM);
|
|
PRIVATE_CODE BOOL GenerateObjectTwinFromFolderTwinProc(LPCTSTR, PCWIN32_FIND_DATA, PVOID);
|
|
PRIVATE_CODE TWINRESULT ExpandSubtreeTwin(PFOLDERPAIR, HCLSIFACECACHE, CREATERECLISTPROC, LPARAM);
|
|
PRIVATE_CODE BOOL IsFolderToExpand(LPCTSTR);
|
|
PRIVATE_CODE TWINRESULT FakeObjectTwinFromFolderTwin(PCFOLDERPAIR, LPCTSTR, LPCTSTR, HCLSIFACECACHE, POBJECTTWIN *, POBJECTTWIN *);
|
|
PRIVATE_CODE TWINRESULT AddFolderObjectTwinFromFolderTwin(PCFOLDERPAIR, LPCTSTR, HCLSIFACECACHE);
|
|
PRIVATE_CODE TWINRESULT AddFileObjectTwinFromFolderTwin(PCFOLDERPAIR, LPCTSTR, PCWIN32_FIND_DATA, HCLSIFACECACHE);
|
|
PRIVATE_CODE BOOL NameComponentsIntersect(LPCTSTR, LPCTSTR);
|
|
PRIVATE_CODE BOOL AttributesMatch(DWORD, DWORD);
|
|
PRIVATE_CODE void PrepareForFolderTwinExpansion(HBRFCASE);
|
|
PRIVATE_CODE TWINRESULT MyExpandIntersectingFolderTwins(PFOLDERPAIR, HCLSIFACECACHE, CREATERECLISTPROC, LPARAM);
|
|
PRIVATE_CODE TWINRESULT HalfExpandIntersectingFolderTwins(PFOLDERPAIR, HCLSIFACECACHE, CREATERECLISTPROC, LPARAM);
|
|
|
|
#ifdef DEBUG
|
|
|
|
PRIVATE_CODE BOOL IsValidPCEXPANDSUBTREETWININFO(PCEXPANDSUBTREETWININFO);
|
|
|
|
#endif
|
|
|
|
|
|
/*
|
|
** SetObjectTwinFileStampCondition()
|
|
**
|
|
**
|
|
**
|
|
** Arguments:
|
|
**
|
|
** Returns:
|
|
**
|
|
** Side Effects: none
|
|
*/
|
|
PRIVATE_CODE BOOL SetObjectTwinFileStampCondition(POBJECTTWIN pot,
|
|
PVOID fscond)
|
|
{
|
|
ASSERT(IS_VALID_STRUCT_PTR(pot, COBJECTTWIN));
|
|
ASSERT(IsValidFILESTAMPCONDITION((FILESTAMPCONDITION)PtrToUlong(fscond)));
|
|
|
|
ZeroMemory(&(pot->fsCurrent), sizeof(pot->fsCurrent));
|
|
pot->fsCurrent.fscond = (FILESTAMPCONDITION)PtrToUlong(fscond);
|
|
|
|
SetStubFlag(&(pot->stub), STUB_FL_FILE_STAMP_VALID);
|
|
|
|
return(TRUE);
|
|
}
|
|
|
|
|
|
/*
|
|
** MarkFolderTwinDeletionPending()
|
|
**
|
|
**
|
|
**
|
|
** Arguments:
|
|
**
|
|
** Returns:
|
|
**
|
|
** Side Effects: none
|
|
*/
|
|
PRIVATE_CODE void MarkFolderTwinDeletionPending(PFOLDERPAIR pfp)
|
|
{
|
|
ASSERT(IS_VALID_STRUCT_PTR(pfp, CFOLDERPAIR));
|
|
|
|
if (IsStubFlagClear(&(pfp->stub), STUB_FL_DELETION_PENDING))
|
|
{
|
|
TCHAR rgchRootPath[MAX_PATH_LEN];
|
|
|
|
GetPathRootString(pfp->hpath, rgchRootPath, ARRAYSIZE(rgchRootPath));
|
|
|
|
if (PathExists(rgchRootPath))
|
|
{
|
|
SetStubFlag(&(pfp->stub), STUB_FL_DELETION_PENDING);
|
|
|
|
TRACE_OUT((TEXT("MarkFolderTwinDeletionPending(): Folder twin deletion pending for deleted folder %s."),
|
|
DebugGetPathString(pfp->hpath)));
|
|
}
|
|
else
|
|
WARNING_OUT((TEXT("MarkFolderTwinDeletionPending(): Root path %s of folder %s does not exist."),
|
|
rgchRootPath,
|
|
DebugGetPathString(pfp->hpath)));
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
|
|
/*
|
|
** UnmarkFolderTwinDeletionPending()
|
|
**
|
|
**
|
|
**
|
|
** Arguments:
|
|
**
|
|
** Returns:
|
|
**
|
|
** Side Effects: none
|
|
*/
|
|
PRIVATE_CODE void UnmarkFolderTwinDeletionPending(PFOLDERPAIR pfp)
|
|
{
|
|
ASSERT(IS_VALID_STRUCT_PTR(pfp, CFOLDERPAIR));
|
|
|
|
if (IsStubFlagSet(&(pfp->stub), STUB_FL_DELETION_PENDING))
|
|
WARNING_OUT((TEXT("UnmarkFolderTwinDeletionPending(): Folder twin %s was deleted but has been recreated."),
|
|
DebugGetPathString(pfp->hpath)));
|
|
|
|
ClearStubFlag(&(pfp->stub), STUB_FL_DELETION_PENDING);
|
|
|
|
return;
|
|
}
|
|
|
|
|
|
/*
|
|
** ExpandFolderTwin()
|
|
**
|
|
** Expands a single folder of half of a folder pair into object twins.
|
|
**
|
|
** Arguments: pfp - pointer to folder pair whose folder is to be expanded
|
|
**
|
|
** Returns: TWINRESULT
|
|
**
|
|
** Side Effects: none
|
|
*/
|
|
PRIVATE_CODE TWINRESULT ExpandFolderTwin(PFOLDERPAIR pfp, HCLSIFACECACHE hcic,
|
|
CREATERECLISTPROC crlp,
|
|
LPARAM lpCallbackData)
|
|
{
|
|
TWINRESULT tr = TR_SUCCESS;
|
|
TCHAR rgchSearchSpec[MAX_PATH_LEN];
|
|
|
|
/* lpCallbackData may be any value. */
|
|
|
|
ASSERT(IS_VALID_STRUCT_PTR(pfp, CFOLDERPAIR));
|
|
ASSERT(IS_VALID_HANDLE(hcic, CLSIFACECACHE));
|
|
ASSERT(! crlp ||
|
|
IS_VALID_CODE_PTR(crlp, CREATERECLISTPROC));
|
|
|
|
ASSERT(IsPathVolumeAvailable(pfp->hpath));
|
|
ASSERT(IsStubFlagClear(&(pfp->stub), STUB_FL_SUBTREE));
|
|
ASSERT(IsStubFlagClear(&(pfp->stub), STUB_FL_USED));
|
|
|
|
/* Build search specification. */
|
|
|
|
GetPathString(pfp->hpath, rgchSearchSpec, ARRAYSIZE(rgchSearchSpec));
|
|
|
|
if (PathExists(rgchSearchSpec))
|
|
{
|
|
WIN32_FIND_DATA wfd;
|
|
HANDLE hff;
|
|
|
|
UnmarkFolderTwinDeletionPending(pfp);
|
|
|
|
TRACE_OUT((TEXT("ExpandFolderTwin(): Expanding folder %s for objects matching %s."),
|
|
rgchSearchSpec,
|
|
GetString(pfp->pfpd->hsName)));
|
|
|
|
tr = AddFolderObjectTwinFromFolderTwin(pfp, EMPTY_STRING, hcic);
|
|
|
|
if (tr == TR_SUCCESS)
|
|
{
|
|
CatPath(rgchSearchSpec, GetString(pfp->pfpd->hsName), ARRAYSIZE(rgchSearchSpec));
|
|
|
|
hff = FindFirstFile(rgchSearchSpec, &wfd);
|
|
|
|
/* Did we find a matching object? */
|
|
|
|
if (hff != INVALID_HANDLE_VALUE)
|
|
{
|
|
/* Yes. */
|
|
|
|
do
|
|
{
|
|
/* Ping. */
|
|
|
|
if (NotifyCreateRecListStatus(crlp, CRLS_DELTA_CREATE_REC_LIST,
|
|
0, lpCallbackData))
|
|
{
|
|
if (AttributesMatch(pfp->pfpd->dwAttributes,
|
|
wfd.dwFileAttributes))
|
|
{
|
|
TRACE_OUT((TEXT("ExpandFolderTwin(): Found matching object %s."),
|
|
&(wfd.cFileName)));
|
|
|
|
tr = AddFileObjectTwinFromFolderTwin(pfp, EMPTY_STRING,
|
|
&wfd, hcic);
|
|
|
|
if (tr != TR_SUCCESS)
|
|
break;
|
|
}
|
|
}
|
|
else
|
|
tr = TR_ABORT;
|
|
|
|
} while (FindNextFile(hff, &wfd));
|
|
}
|
|
|
|
if (hff != INVALID_HANDLE_VALUE)
|
|
FindClose(hff);
|
|
}
|
|
|
|
TRACE_OUT((TEXT("ExpandFolderTwin(): Folder expansion complete.")));
|
|
}
|
|
else
|
|
MarkFolderTwinDeletionPending(pfp);
|
|
|
|
return(tr);
|
|
}
|
|
|
|
|
|
/*
|
|
** GenerateObjectTwinFromFolderTwinProc()
|
|
**
|
|
**
|
|
**
|
|
** Arguments:
|
|
**
|
|
** Returns:
|
|
**
|
|
** Side Effects: none
|
|
*/
|
|
PRIVATE_CODE BOOL GenerateObjectTwinFromFolderTwinProc(LPCTSTR pcszFolder,
|
|
PCWIN32_FIND_DATA pcwfd,
|
|
PVOID pvpesti)
|
|
{
|
|
TWINRESULT tr;
|
|
PEXPANDSUBTREETWININFO pesti = pvpesti;
|
|
|
|
ASSERT(IsCanonicalPath(pcszFolder));
|
|
ASSERT(IS_VALID_READ_PTR(pcwfd, CWIN32_FIND_DATA));
|
|
ASSERT(IS_VALID_STRUCT_PTR(pesti, CEXPANDSUBTREETWININFO));
|
|
|
|
/* Ping. */
|
|
|
|
if (NotifyCreateRecListStatus(pesti->crlp, CRLS_DELTA_CREATE_REC_LIST, 0,
|
|
pesti->lpCallbackData))
|
|
{
|
|
if (IS_ATTR_DIR(pcwfd->dwFileAttributes))
|
|
{
|
|
TCHAR rgchFolder[MAX_PATH_LEN];
|
|
|
|
/* Add any folder as a folder object twin. */
|
|
|
|
ComposePath(rgchFolder, pcszFolder, pcwfd->cFileName, ARRAYSIZE(rgchFolder));
|
|
ASSERT(lstrlen(rgchFolder) < ARRAYSIZE(rgchFolder));
|
|
|
|
tr = AddFolderObjectTwinFromFolderTwin(
|
|
pesti->pfp,
|
|
rgchFolder + (pesti->ucbSubtreeRootPathLen / sizeof(TCHAR)),
|
|
pesti->hcic);
|
|
}
|
|
else
|
|
{
|
|
/* Does this file match the requested attributes? */
|
|
|
|
if (NamesIntersect(pcwfd->cFileName,
|
|
GetString(pesti->pfp->pfpd->hsName)) &&
|
|
AttributesMatch(pesti->pfp->pfpd->dwAttributes,
|
|
pcwfd->dwFileAttributes))
|
|
{
|
|
/* Yes. Twin it. */
|
|
|
|
TRACE_OUT((TEXT("GenerateObjectTwinFromFolderTwinProc(): Found matching object %s in subfolder %s."),
|
|
pcwfd->cFileName,
|
|
pcszFolder));
|
|
|
|
tr = AddFileObjectTwinFromFolderTwin(
|
|
pesti->pfp,
|
|
pcszFolder + (pesti->ucbSubtreeRootPathLen / sizeof(TCHAR)),
|
|
pcwfd, pesti->hcic);
|
|
}
|
|
else
|
|
{
|
|
TRACE_OUT((TEXT("GenerateObjectTwinFromFolderTwinProc(): Skipping unmatched object %s in subfolder %s."),
|
|
pcwfd->cFileName,
|
|
pcszFolder));
|
|
|
|
tr = TR_SUCCESS;
|
|
}
|
|
}
|
|
}
|
|
else
|
|
tr = TR_ABORT;
|
|
|
|
pesti->tr = tr;
|
|
|
|
ASSERT(IS_VALID_STRUCT_PTR(pvpesti, CEXPANDSUBTREETWININFO));
|
|
|
|
return(tr == TR_SUCCESS);
|
|
}
|
|
|
|
|
|
/*
|
|
** ExpandSubtreeTwin()
|
|
**
|
|
**
|
|
**
|
|
** Arguments:
|
|
**
|
|
** Returns:
|
|
**
|
|
** Side Effects: none
|
|
*/
|
|
PRIVATE_CODE TWINRESULT ExpandSubtreeTwin(PFOLDERPAIR pfp, HCLSIFACECACHE hcic,
|
|
CREATERECLISTPROC crlp,
|
|
LPARAM lpCallbackData)
|
|
{
|
|
TWINRESULT tr = TR_SUCCESS;
|
|
TCHAR rgchPath[MAX_PATH_LEN];
|
|
|
|
/* lpCallbackData may be any value. */
|
|
|
|
ASSERT(IS_VALID_STRUCT_PTR(pfp, CFOLDERPAIR));
|
|
ASSERT(IS_VALID_HANDLE(hcic, CLSIFACECACHE));
|
|
ASSERT(! crlp ||
|
|
IS_VALID_CODE_PTR(crlp, CREATERECLISTPROC));
|
|
|
|
ASSERT(IsPathVolumeAvailable(pfp->hpath));
|
|
ASSERT(IsStubFlagSet(&(pfp->stub), STUB_FL_SUBTREE));
|
|
ASSERT(IsStubFlagClear(&(pfp->stub), STUB_FL_USED));
|
|
|
|
GetPathString(pfp->hpath, rgchPath, ARRAYSIZE(rgchPath));
|
|
|
|
if (PathExists(rgchPath))
|
|
{
|
|
UnmarkFolderTwinDeletionPending(pfp);
|
|
|
|
tr = AddFolderObjectTwinFromFolderTwin(pfp, EMPTY_STRING, hcic);
|
|
|
|
if (tr == TR_SUCCESS)
|
|
{
|
|
EXPANDSUBTREETWININFO esti;
|
|
|
|
esti.pfp = pfp;
|
|
esti.ucbSubtreeRootPathLen = lstrlen(rgchPath) * sizeof(TCHAR); // UNICODE really cb?
|
|
esti.hcic = hcic;
|
|
esti.crlp = crlp;
|
|
esti.lpCallbackData = lpCallbackData;
|
|
esti.tr = TR_SUCCESS;
|
|
|
|
tr = ExpandSubtree(pfp->hpath, &GenerateObjectTwinFromFolderTwinProc,
|
|
&esti);
|
|
|
|
ASSERT(tr != TR_SUCCESS ||
|
|
esti.tr == TR_SUCCESS);
|
|
|
|
if (tr == TR_SUCCESS ||
|
|
tr == TR_ABORT)
|
|
tr = esti.tr;
|
|
}
|
|
}
|
|
else
|
|
MarkFolderTwinDeletionPending(pfp);
|
|
|
|
return(tr);
|
|
}
|
|
|
|
|
|
/*
|
|
** IsFolderToExpand()
|
|
**
|
|
**
|
|
**
|
|
** Arguments:
|
|
**
|
|
** Returns: TWINRESULT
|
|
**
|
|
** Side Effects: none
|
|
*/
|
|
PRIVATE_CODE BOOL IsFolderToExpand(LPCTSTR pcszFolder)
|
|
{
|
|
BOOL bExpandMe = TRUE;
|
|
int i;
|
|
|
|
for (i = 0; i < ARRAY_ELEMENTS(MrgcpcszFoldersToAvoid); i++)
|
|
{
|
|
if (ComparePathStrings(pcszFolder, MrgcpcszFoldersToAvoid[i])
|
|
== CR_EQUAL)
|
|
{
|
|
bExpandMe = FALSE;
|
|
break;
|
|
}
|
|
}
|
|
|
|
return(bExpandMe);
|
|
}
|
|
|
|
|
|
/*
|
|
** FakeObjectTwinFromFolderTwin()
|
|
**
|
|
**
|
|
**
|
|
** Arguments:
|
|
**
|
|
** Returns:
|
|
**
|
|
** Side Effects: none
|
|
*/
|
|
PRIVATE_CODE TWINRESULT FakeObjectTwinFromFolderTwin(PCFOLDERPAIR pcfp,
|
|
LPCTSTR pcszSubPath,
|
|
LPCTSTR pcszName,
|
|
HCLSIFACECACHE hcic,
|
|
POBJECTTWIN *ppot1,
|
|
POBJECTTWIN *ppot2)
|
|
{
|
|
TWINRESULT tr = TR_OUT_OF_MEMORY;
|
|
HPATHLIST hpl;
|
|
HPATH hpath1;
|
|
|
|
ASSERT(IS_VALID_STRUCT_PTR(pcfp, CFOLDERPAIR));
|
|
ASSERT(IS_VALID_STRING_PTR(pcszSubPath, CSTR));
|
|
ASSERT(IS_VALID_STRING_PTR(pcszName, CSTR));
|
|
ASSERT(IS_VALID_HANDLE(hcic, CLSIFACECACHE));
|
|
ASSERT(IS_VALID_WRITE_PTR(ppot1, POBJECTTWIN));
|
|
ASSERT(IS_VALID_WRITE_PTR(ppot2, POBJECTTWIN));
|
|
|
|
/* If the common sub path is non-empty, append it to the path strings. */
|
|
|
|
hpl = GetBriefcasePathList(pcfp->pfpd->hbr);
|
|
|
|
if (AddChildPath(hpl, pcfp->hpath, pcszSubPath, &hpath1))
|
|
{
|
|
HPATH hpath2;
|
|
|
|
if (AddChildPath(hpl, pcfp->pfpOther->hpath, pcszSubPath, &hpath2))
|
|
{
|
|
/* Add the two object twins. */
|
|
|
|
tr = TwinObjects(pcfp->pfpd->hbr, hcic, hpath1, hpath2, pcszName,
|
|
ppot1, ppot2);
|
|
|
|
DeletePath(hpath2);
|
|
}
|
|
|
|
DeletePath(hpath1);
|
|
}
|
|
|
|
return(tr);
|
|
}
|
|
|
|
|
|
/*
|
|
** AddFolderObjectTwinFromFolderTwin()
|
|
**
|
|
**
|
|
**
|
|
** Arguments:
|
|
**
|
|
** Returns:
|
|
**
|
|
** Side Effects: none
|
|
*/
|
|
PRIVATE_CODE TWINRESULT AddFolderObjectTwinFromFolderTwin(PCFOLDERPAIR pcfp,
|
|
LPCTSTR pcszSubPath,
|
|
HCLSIFACECACHE hcic)
|
|
{
|
|
TWINRESULT tr;
|
|
POBJECTTWIN pot1;
|
|
POBJECTTWIN pot2;
|
|
|
|
ASSERT(IS_VALID_STRUCT_PTR(pcfp, CFOLDERPAIR));
|
|
ASSERT(IS_VALID_STRING_PTR(pcszSubPath, CSTR));
|
|
ASSERT(IS_VALID_HANDLE(hcic, CLSIFACECACHE));
|
|
|
|
/* Add the two object twins. */
|
|
|
|
tr = FakeObjectTwinFromFolderTwin(pcfp, pcszSubPath, EMPTY_STRING, hcic,
|
|
&pot1, &pot2);
|
|
|
|
/* An attempted redundant add is ok. */
|
|
|
|
if (tr == TR_DUPLICATE_TWIN)
|
|
tr = TR_SUCCESS;
|
|
|
|
if (tr == TR_SUCCESS)
|
|
/* Cache folder object twin file stamps. */
|
|
SetObjectTwinFileStampCondition(pot1, IntToPtr(FS_COND_EXISTS));
|
|
|
|
return(tr);
|
|
}
|
|
|
|
|
|
/*
|
|
** AddFileObjectTwinFromFolderTwin()
|
|
**
|
|
** Adds a pair of object twins generated by a folder twin.
|
|
**
|
|
** Arguments: pfp - pointer to folder pair that generated the two object
|
|
** twins
|
|
** pcszSubPath - common path off of folder pair roots describing
|
|
** object's location
|
|
** pcszName - name of object twins
|
|
**
|
|
** Returns: TWINRESULT
|
|
**
|
|
** Side Effects: none
|
|
*/
|
|
PRIVATE_CODE TWINRESULT AddFileObjectTwinFromFolderTwin(PCFOLDERPAIR pcfp,
|
|
LPCTSTR pcszSubPath,
|
|
PCWIN32_FIND_DATA pcwfd,
|
|
HCLSIFACECACHE hcic)
|
|
{
|
|
TWINRESULT tr;
|
|
POBJECTTWIN pot1;
|
|
POBJECTTWIN pot2;
|
|
|
|
ASSERT(IS_VALID_STRUCT_PTR(pcfp, CFOLDERPAIR));
|
|
ASSERT(IS_VALID_STRING_PTR(pcszSubPath, CSTR));
|
|
ASSERT(IS_VALID_READ_PTR(pcwfd, CWIN32_FIND_DATA));
|
|
ASSERT(IS_VALID_HANDLE(hcic, CLSIFACECACHE));
|
|
|
|
/* Add the two object twins. */
|
|
|
|
tr = FakeObjectTwinFromFolderTwin(pcfp, pcszSubPath, pcwfd->cFileName, hcic,
|
|
&pot1, &pot2);
|
|
|
|
/* An attempted redundant add is ok. */
|
|
|
|
if (tr == TR_DUPLICATE_TWIN)
|
|
tr = TR_SUCCESS;
|
|
|
|
if (tr == TR_SUCCESS)
|
|
{
|
|
/* Cache object twin file stamp. */
|
|
|
|
CopyFileStampFromFindData(pcwfd, &(pot1->fsCurrent));
|
|
|
|
SetStubFlag(&(pot1->stub), STUB_FL_FILE_STAMP_VALID);
|
|
}
|
|
|
|
return(tr);
|
|
}
|
|
|
|
|
|
/*
|
|
** NameComponentsIntersect()
|
|
**
|
|
**
|
|
**
|
|
** Arguments:
|
|
**
|
|
** Returns:
|
|
**
|
|
** Side Effects: none
|
|
*/
|
|
PRIVATE_CODE BOOL NameComponentsIntersect(LPCTSTR pcszComponent1,
|
|
LPCTSTR pcszComponent2)
|
|
{
|
|
BOOL bIntersect;
|
|
|
|
ASSERT(IS_VALID_STRING_PTR(pcszComponent1, CSTR));
|
|
ASSERT(IS_VALID_STRING_PTR(pcszComponent2, CSTR));
|
|
|
|
while (! IS_COMPONENT_TERMINATOR(*pcszComponent1) && ! IS_COMPONENT_TERMINATOR(*pcszComponent2) &&
|
|
COMPONENT_CHARS_MATCH(*pcszComponent1, *pcszComponent2))
|
|
{
|
|
pcszComponent1 = CharNext(pcszComponent1);
|
|
pcszComponent2 = CharNext(pcszComponent2);
|
|
}
|
|
|
|
if (*pcszComponent1 == ASTERISK ||
|
|
*pcszComponent2 == ASTERISK ||
|
|
*pcszComponent1 == *pcszComponent2)
|
|
bIntersect = TRUE;
|
|
else
|
|
{
|
|
LPCTSTR pcszTrailer;
|
|
|
|
if (! *pcszComponent1 || *pcszComponent1 == PERIOD)
|
|
pcszTrailer = pcszComponent2;
|
|
else
|
|
pcszTrailer = pcszComponent1;
|
|
|
|
while (*pcszTrailer == QMARK)
|
|
pcszTrailer++;
|
|
|
|
if (IS_COMPONENT_TERMINATOR(*pcszTrailer))
|
|
bIntersect = TRUE;
|
|
else
|
|
bIntersect = FALSE;
|
|
}
|
|
|
|
return(bIntersect);
|
|
}
|
|
|
|
|
|
/*
|
|
** AttributesMatch()
|
|
**
|
|
**
|
|
**
|
|
** Arguments:
|
|
**
|
|
** Returns:
|
|
**
|
|
** Side Effects: none
|
|
**
|
|
** An object's attributes match the master attributes iff the object's
|
|
** attributes do not contain any set bits that are not also set in the master
|
|
** attributes.
|
|
*/
|
|
PRIVATE_CODE BOOL AttributesMatch(DWORD dwMasterAttributes,
|
|
DWORD dwObjectAttributes)
|
|
{
|
|
// We don't consider a difference in compression to be enough to call
|
|
// the file different, especially since that attribute is impossible
|
|
// to reconcile in some cases.
|
|
|
|
dwObjectAttributes &= ~(FILE_ATTRIBUTE_COMPRESSED);
|
|
|
|
return(! (dwObjectAttributes & (~dwMasterAttributes)));
|
|
}
|
|
|
|
|
|
/*
|
|
** PrepareForFolderTwinExpansion()
|
|
**
|
|
**
|
|
**
|
|
** Arguments:
|
|
**
|
|
** Returns: void
|
|
**
|
|
** Side Effects: none
|
|
**
|
|
** N.b., this function should be called before the outermost call to
|
|
** MyExpandIntersectingFolderTwins().
|
|
*/
|
|
PRIVATE_CODE void PrepareForFolderTwinExpansion(HBRFCASE hbr)
|
|
{
|
|
ASSERT(IS_VALID_HANDLE(hbr, BRFCASE));
|
|
|
|
ClearFlagInArrayOfStubs(GetBriefcaseFolderPairPtrArray(hbr), STUB_FL_USED);
|
|
|
|
EVAL(EnumObjectTwins(hbr,
|
|
(ENUMGENERATEDOBJECTTWINSPROC)&ClearStubFlagWrapper,
|
|
IntToPtr(STUB_FL_FILE_STAMP_VALID)));
|
|
|
|
return;
|
|
}
|
|
|
|
|
|
/*
|
|
** MyExpandIntersectingFolderTwins()
|
|
**
|
|
** Expands all folder twins intersecting a pair of folder twins.
|
|
**
|
|
** Arguments:
|
|
**
|
|
** Returns: TWINRESULT
|
|
**
|
|
** Side Effects: Marks expanded folder pairs used.
|
|
**
|
|
** N.b., PrepareForFolderTwinExpansion(pfp->pfpd->hbr) should be called before
|
|
** the first time this function is called.
|
|
*/
|
|
PRIVATE_CODE TWINRESULT MyExpandIntersectingFolderTwins(PFOLDERPAIR pfp,
|
|
HCLSIFACECACHE hcic,
|
|
CREATERECLISTPROC crlp,
|
|
LPARAM lpCallbackData)
|
|
{
|
|
TWINRESULT tr;
|
|
|
|
/* lpCallbackData may be any value. */
|
|
|
|
ASSERT(IS_VALID_STRUCT_PTR(pfp, CFOLDERPAIR));
|
|
ASSERT(IS_VALID_HANDLE(hcic, CLSIFACECACHE));
|
|
ASSERT(! crlp ||
|
|
IS_VALID_CODE_PTR(crlp, CREATERECLISTPROC));
|
|
|
|
/*
|
|
* N.b., pfp may already be marked used here, but may intersect folder twins
|
|
* that have not yet been expanded.
|
|
*/
|
|
|
|
tr = HalfExpandIntersectingFolderTwins(pfp, hcic, crlp, lpCallbackData);
|
|
|
|
if (tr == TR_SUCCESS)
|
|
{
|
|
ASSERT(IsStubFlagSet(&(pfp->stub), STUB_FL_USED));
|
|
|
|
tr = HalfExpandIntersectingFolderTwins(pfp->pfpOther, hcic, crlp,
|
|
lpCallbackData);
|
|
}
|
|
|
|
return(tr);
|
|
}
|
|
|
|
|
|
/*
|
|
** HalfExpandIntersectingFolderTwins()
|
|
**
|
|
** Expands all folder twins intersecting one half of a pair of folder twins.
|
|
**
|
|
** Arguments:
|
|
**
|
|
** Returns: TWINRESULT
|
|
**
|
|
** Side Effects: Marks expanded folder pairs used.
|
|
**
|
|
** N.b., this function is only meant to be called from
|
|
** MyExpandIntersectingFolderTwins().
|
|
*/
|
|
PRIVATE_CODE TWINRESULT HalfExpandIntersectingFolderTwins(
|
|
PFOLDERPAIR pfp,
|
|
HCLSIFACECACHE hcic,
|
|
CREATERECLISTPROC crlp,
|
|
LPARAM lpCallbackData)
|
|
{
|
|
TWINRESULT tr = TR_SUCCESS;
|
|
|
|
/* lpCallbackData may be any value. */
|
|
|
|
ASSERT(IS_VALID_STRUCT_PTR(pfp, CFOLDERPAIR));
|
|
ASSERT(IS_VALID_HANDLE(hcic, CLSIFACECACHE));
|
|
ASSERT(! crlp ||
|
|
IS_VALID_CODE_PTR(crlp, CREATERECLISTPROC));
|
|
|
|
if (IsStubFlagClear(&(pfp->stub), STUB_FL_UNLINKED))
|
|
{
|
|
BOOL bArgIsSubtree;
|
|
HPTRARRAY hpaFolderPairs;
|
|
ARRAYINDEX ai;
|
|
ARRAYINDEX aicFolderPairs;
|
|
|
|
bArgIsSubtree = IsStubFlagSet(&(pfp->stub), STUB_FL_SUBTREE);
|
|
|
|
hpaFolderPairs = GetBriefcaseFolderPairPtrArray(pfp->pfpd->hbr);
|
|
aicFolderPairs = GetPtrCount(hpaFolderPairs);
|
|
|
|
for (ai = 0; ai < aicFolderPairs; ai++)
|
|
{
|
|
PFOLDERPAIR pfpCur;
|
|
|
|
pfpCur = (PFOLDERPAIR)GetPtr(hpaFolderPairs, ai);
|
|
|
|
ASSERT(IS_VALID_STRUCT_PTR(pfpCur, CFOLDERPAIR));
|
|
|
|
if (IsStubFlagClear(&(pfpCur->stub), STUB_FL_USED) &&
|
|
NamesIntersect(GetString(pfp->pfpd->hsName),
|
|
GetString(pfpCur->pfpd->hsName)))
|
|
{
|
|
BOOL bCurIsSubtree;
|
|
BOOL bExpand = FALSE;
|
|
|
|
bCurIsSubtree = IsStubFlagSet(&(pfpCur->stub), STUB_FL_SUBTREE);
|
|
|
|
if (bCurIsSubtree)
|
|
{
|
|
if (bArgIsSubtree)
|
|
bExpand = SubtreesIntersect(pfp->hpath, pfpCur->hpath);
|
|
else
|
|
bExpand = IsPathPrefix(pfp->hpath, pfpCur->hpath);
|
|
}
|
|
else
|
|
{
|
|
if (bArgIsSubtree)
|
|
bExpand = IsPathPrefix(pfpCur->hpath, pfp->hpath);
|
|
else
|
|
bExpand = (ComparePaths(pfp->hpath, pfpCur->hpath) == CR_EQUAL);
|
|
}
|
|
|
|
/* Expand folder twin and mark it used. */
|
|
|
|
if (bExpand)
|
|
{
|
|
/*
|
|
* Mark all generated object twins as non-existent or unavailable.
|
|
* Expand available folder twin.
|
|
*/
|
|
|
|
if (IsPathVolumeAvailable(pfp->hpath))
|
|
{
|
|
EVAL(EnumGeneratedObjectTwins(pfp,
|
|
&SetObjectTwinFileStampCondition,
|
|
IntToPtr(FS_COND_DOES_NOT_EXIST)));
|
|
|
|
if (bCurIsSubtree)
|
|
tr = ExpandSubtreeTwin(pfpCur, hcic, crlp, lpCallbackData);
|
|
else
|
|
tr = ExpandFolderTwin(pfpCur, hcic, crlp, lpCallbackData);
|
|
|
|
if (tr != TR_SUCCESS)
|
|
break;
|
|
}
|
|
else
|
|
{
|
|
EVAL(EnumGeneratedObjectTwins(pfp, &SetObjectTwinFileStampCondition,
|
|
IntToPtr(FS_COND_UNAVAILABLE)));
|
|
|
|
WARNING_OUT((TEXT("HalfExpandIntersectingFolderTwins(): Unavailable folder %s skipped."),
|
|
DebugGetPathString(pfp->hpath)));
|
|
}
|
|
|
|
SetStubFlag(&(pfp->stub), STUB_FL_USED);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
return(tr);
|
|
}
|
|
|
|
|
|
#ifdef DEBUG
|
|
|
|
/*
|
|
** IsValidPCEXPANDSUBTREETWININFO()
|
|
**
|
|
**
|
|
**
|
|
** Arguments:
|
|
**
|
|
** Returns:
|
|
**
|
|
** Side Effects: none
|
|
*/
|
|
PRIVATE_CODE BOOL IsValidPCEXPANDSUBTREETWININFO(PCEXPANDSUBTREETWININFO pcesi)
|
|
{
|
|
/* lpCallbackData may be any value. */
|
|
|
|
return(IS_VALID_READ_PTR(pcesi, CEXPANDSUBTREETWININFO) &&
|
|
IS_VALID_STRUCT_PTR(pcesi->pfp, CFOLDERPAIR) &&
|
|
EVAL(pcesi->ucbSubtreeRootPathLen > 0) &&
|
|
IS_VALID_HANDLE(pcesi->hcic, CLSIFACECACHE) &&
|
|
IsValidTWINRESULT(pcesi->tr));
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
/****************************** Public Functions *****************************/
|
|
|
|
|
|
/*
|
|
** ExpandSubtree()
|
|
**
|
|
**
|
|
**
|
|
** Arguments:
|
|
**
|
|
** Returns: TWINRESULT
|
|
**
|
|
** Side Effects: none
|
|
*/
|
|
PUBLIC_CODE TWINRESULT ExpandSubtree(HPATH hpathRoot, EXPANDSUBTREEPROC esp,
|
|
PVOID pvRefData)
|
|
{
|
|
TWINRESULT tr;
|
|
PFINDSTATE pfs;
|
|
|
|
/* pvRefData may be any value. */
|
|
|
|
ASSERT(IS_VALID_HANDLE(hpathRoot, PATH));
|
|
ASSERT(IS_VALID_CODE_PTR(esp, EXPANDSUBTREEPROC));
|
|
|
|
ASSERT(IsPathVolumeAvailable(hpathRoot));
|
|
|
|
if (AllocateMemory(MAX_FOLDER_DEPTH * sizeof(pfs[0]), &pfs))
|
|
{
|
|
/* Copy subtree root folder to beginning of search path buffer. */
|
|
|
|
TCHAR rgchSearchSpec[MAX_PATH_LEN];
|
|
LPTSTR pszPathSuffix;
|
|
int iFind;
|
|
LPTSTR pszStartOfSubPath;
|
|
BOOL bFound;
|
|
#ifdef DEBUG
|
|
/* Are we leaking WIN32_FIND_DATA structures? */
|
|
ULONG ulcOpenFinds = 0;
|
|
#endif
|
|
|
|
rgchSearchSpec[0] = TEXT('\0');
|
|
GetPathRootString(hpathRoot, rgchSearchSpec, ARRAYSIZE(rgchSearchSpec));
|
|
pszPathSuffix = rgchSearchSpec + lstrlen(rgchSearchSpec);
|
|
GetPathSuffixString(hpathRoot, pszPathSuffix);
|
|
|
|
pszStartOfSubPath = rgchSearchSpec + lstrlen(rgchSearchSpec);
|
|
|
|
TRACE_OUT((TEXT("ExpandSubtree(): Expanding subtree rooted at %s."),
|
|
rgchSearchSpec));
|
|
|
|
/* Append *.* file specification. */
|
|
|
|
CatPath(rgchSearchSpec, STAR_DOT_STAR, ARRAYSIZE(rgchSearchSpec));
|
|
|
|
/* Begin search at subtree root. */
|
|
|
|
iFind = 0;
|
|
|
|
pfs[iFind].hff = FindFirstFile(rgchSearchSpec, &(pfs[iFind].wfd));
|
|
|
|
#ifdef DEBUG
|
|
if (pfs[iFind].hff != INVALID_HANDLE_VALUE)
|
|
ulcOpenFinds++;
|
|
#endif
|
|
|
|
bFound = (pfs[iFind].hff != INVALID_HANDLE_VALUE);
|
|
|
|
/* Rip off *.*. */
|
|
|
|
DeleteLastPathElement(pszPathSuffix);
|
|
|
|
/* Search subtree depth first. */
|
|
|
|
tr = TR_SUCCESS;
|
|
|
|
while (bFound && tr == TR_SUCCESS)
|
|
{
|
|
/* Did we find a directory to expand? */
|
|
|
|
if (IS_ATTR_DIR(pfs[iFind].wfd.dwFileAttributes))
|
|
{
|
|
if (IsFolderToExpand(pfs[iFind].wfd.cFileName))
|
|
{
|
|
/* Yes. Dive down into it. */
|
|
|
|
/* Append the new directory to the current search path. */
|
|
|
|
CatPath(rgchSearchSpec, pfs[iFind].wfd.cFileName, ARRAYSIZE(rgchSearchSpec));
|
|
|
|
TRACE_OUT((TEXT("ExpandSubtree(): Diving into subfolder %s."),
|
|
rgchSearchSpec));
|
|
|
|
/* Append *.* file specification. */
|
|
|
|
CatPath(rgchSearchSpec, STAR_DOT_STAR, ARRAYSIZE(rgchSearchSpec));
|
|
|
|
/* Start search in the new directory. */
|
|
|
|
ASSERT(iFind < INT_MAX);
|
|
iFind++;
|
|
pfs[iFind].hff = FindFirstFile(rgchSearchSpec, &(pfs[iFind].wfd));
|
|
|
|
bFound = (pfs[iFind].hff != INVALID_HANDLE_VALUE);
|
|
|
|
#ifdef DEBUG
|
|
if (bFound)
|
|
ulcOpenFinds++;
|
|
#endif
|
|
|
|
/* Rip off *.*. */
|
|
|
|
DeleteLastPathElement(pszPathSuffix);
|
|
}
|
|
else
|
|
/* Continue search in this directory. */
|
|
bFound = FindNextFile(pfs[iFind].hff, &(pfs[iFind].wfd));
|
|
}
|
|
else
|
|
{
|
|
/* Found a file. */
|
|
|
|
TRACE_OUT((TEXT("ExpandSubtree(): Found file %s\\%s."),
|
|
rgchSearchSpec,
|
|
pfs[iFind].wfd.cFileName));
|
|
|
|
if ((*esp)(rgchSearchSpec, &(pfs[iFind].wfd), pvRefData))
|
|
bFound = FindNextFile(pfs[iFind].hff, &(pfs[iFind].wfd));
|
|
else
|
|
tr = TR_ABORT;
|
|
}
|
|
|
|
if (tr == TR_SUCCESS)
|
|
{
|
|
while (! bFound)
|
|
{
|
|
/* Find failed. Climb back up one directory level. */
|
|
|
|
if (pfs[iFind].hff != INVALID_HANDLE_VALUE)
|
|
{
|
|
FindClose(pfs[iFind].hff);
|
|
#ifdef DEBUG
|
|
ulcOpenFinds--;
|
|
#endif
|
|
}
|
|
|
|
if (iFind > 0)
|
|
{
|
|
DeleteLastPathElement(pszPathSuffix);
|
|
iFind--;
|
|
|
|
if (IsFolderToExpand(pfs[iFind].wfd.cFileName))
|
|
{
|
|
TRACE_OUT((TEXT("ExpandSubtree(): Found folder %s\\%s."),
|
|
rgchSearchSpec,
|
|
pfs[iFind].wfd.cFileName));
|
|
|
|
if (! (*esp)(rgchSearchSpec, &(pfs[iFind].wfd), pvRefData))
|
|
{
|
|
tr = TR_ABORT;
|
|
break;
|
|
}
|
|
}
|
|
|
|
bFound = FindNextFile(pfs[iFind].hff, &(pfs[iFind].wfd));
|
|
}
|
|
else
|
|
{
|
|
ASSERT(! iFind);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
if (tr != TR_SUCCESS)
|
|
{
|
|
/* Close all open find operations on failure. */
|
|
|
|
while (iFind >= 0)
|
|
{
|
|
if (pfs[iFind].hff != INVALID_HANDLE_VALUE)
|
|
{
|
|
FindClose(pfs[iFind].hff);
|
|
iFind--;
|
|
#ifdef DEBUG
|
|
ulcOpenFinds--;
|
|
#endif
|
|
}
|
|
}
|
|
}
|
|
|
|
ASSERT(! ulcOpenFinds);
|
|
|
|
FreeMemory(pfs);
|
|
|
|
TRACE_OUT((TEXT("ExpandSubtree(): Subtree expansion complete.")));
|
|
}
|
|
else
|
|
tr = TR_OUT_OF_MEMORY;
|
|
|
|
return(tr);
|
|
}
|
|
|
|
|
|
/*
|
|
** ClearStubFlagWrapper()
|
|
**
|
|
**
|
|
**
|
|
** Arguments:
|
|
**
|
|
** Returns:
|
|
**
|
|
** Side Effects: none
|
|
*/
|
|
PUBLIC_CODE BOOL ClearStubFlagWrapper(PSTUB pstub, PVOID dwFlags)
|
|
{
|
|
ASSERT(IS_VALID_STRUCT_PTR(pstub, CSTUB));
|
|
ASSERT(FLAGS_ARE_VALID(PtrToUlong(dwFlags), ALL_STUB_FLAGS));
|
|
|
|
ClearStubFlag(pstub, PtrToUlong(dwFlags));
|
|
|
|
return(TRUE);
|
|
}
|
|
|
|
|
|
/*
|
|
** SetStubFlagWrapper()
|
|
**
|
|
**
|
|
**
|
|
** Arguments:
|
|
**
|
|
** Returns:
|
|
**
|
|
** Side Effects: none
|
|
*/
|
|
PUBLIC_CODE BOOL SetStubFlagWrapper(PSTUB pstub, PVOID dwFlags)
|
|
{
|
|
ASSERT(IS_VALID_STRUCT_PTR(pstub, CSTUB));
|
|
ASSERT(FLAGS_ARE_VALID(PtrToUlong(dwFlags), ALL_STUB_FLAGS));
|
|
|
|
SetStubFlag(pstub, PtrToUlong(dwFlags));
|
|
|
|
return(TRUE);
|
|
}
|
|
|
|
|
|
/*
|
|
** ExpandIntersectingFolderTwins()
|
|
**
|
|
**
|
|
**
|
|
** Arguments:
|
|
**
|
|
** Returns: TWINRESULT
|
|
**
|
|
** Side Effects: Leaves only the folder pairs expanded marked used.
|
|
*/
|
|
PUBLIC_CODE TWINRESULT ExpandIntersectingFolderTwins(PFOLDERPAIR pfp,
|
|
CREATERECLISTPROC crlp,
|
|
LPARAM lpCallbackData)
|
|
{
|
|
TWINRESULT tr;
|
|
HCLSIFACECACHE hcic;
|
|
|
|
/* lpCallbackData may be any value. */
|
|
|
|
ASSERT(IS_VALID_STRUCT_PTR(pfp, CFOLDERPAIR));
|
|
ASSERT(! crlp ||
|
|
IS_VALID_CODE_PTR(crlp, CREATERECLISTPROC));
|
|
|
|
ASSERT(IsStubFlagClear(&(pfp->stub), STUB_FL_UNLINKED));
|
|
|
|
if (CreateClassInterfaceCache(&hcic))
|
|
{
|
|
/* Prepare for call to MyExpandIntersectingFolderTwins(). */
|
|
|
|
PrepareForFolderTwinExpansion(pfp->pfpd->hbr);
|
|
|
|
tr = MyExpandIntersectingFolderTwins(pfp, hcic, crlp, lpCallbackData);
|
|
|
|
DestroyClassInterfaceCache(hcic);
|
|
}
|
|
else
|
|
tr = TR_OUT_OF_MEMORY;
|
|
|
|
return(tr);
|
|
}
|
|
|
|
|
|
/*
|
|
** ExpandFolderTwinsIntersectingTwinList()
|
|
**
|
|
**
|
|
**
|
|
** Arguments:
|
|
**
|
|
** Returns:
|
|
**
|
|
** Side Effects: Leaves only the folder pairs expanded marked used.
|
|
*/
|
|
PUBLIC_CODE TWINRESULT ExpandFolderTwinsIntersectingTwinList(
|
|
HTWINLIST htl,
|
|
CREATERECLISTPROC crlp,
|
|
LPARAM lpCallbackData)
|
|
{
|
|
TWINRESULT tr;
|
|
HCLSIFACECACHE hcic;
|
|
|
|
/* lpCallbackData may be any value. */
|
|
|
|
ASSERT(IS_VALID_HANDLE(htl, TWINLIST));
|
|
ASSERT(! crlp ||
|
|
IS_VALID_CODE_PTR(crlp, CREATERECLISTPROC));
|
|
|
|
if (CreateClassInterfaceCache(&hcic))
|
|
{
|
|
ARRAYINDEX aicTwins;
|
|
ARRAYINDEX ai;
|
|
|
|
tr = TR_SUCCESS;
|
|
|
|
/* Prepare for calls to MyExpandIntersectingFolderTwins(). */
|
|
|
|
PrepareForFolderTwinExpansion(GetTwinListBriefcase(htl));
|
|
|
|
aicTwins = GetTwinListCount(htl);
|
|
|
|
for (ai = 0; ai < aicTwins; ai++)
|
|
{
|
|
HTWIN htwin;
|
|
|
|
htwin = GetTwinFromTwinList(htl, ai);
|
|
|
|
/* Expand only live folder twins. */
|
|
|
|
if (((PCSTUB)htwin)->st == ST_FOLDERPAIR)
|
|
{
|
|
tr = MyExpandIntersectingFolderTwins((PFOLDERPAIR)htwin, hcic,
|
|
crlp, lpCallbackData);
|
|
|
|
if (tr != TR_SUCCESS)
|
|
break;
|
|
}
|
|
}
|
|
|
|
DestroyClassInterfaceCache(hcic);
|
|
}
|
|
else
|
|
tr = TR_OUT_OF_MEMORY;
|
|
|
|
return(tr);
|
|
}
|
|
|
|
|
|
/*
|
|
** TryToGenerateObjectTwin()
|
|
**
|
|
**
|
|
**
|
|
** Arguments:
|
|
**
|
|
** Returns:
|
|
**
|
|
** Side Effects: none
|
|
*/
|
|
PUBLIC_CODE TWINRESULT TryToGenerateObjectTwin(HBRFCASE hbr, HPATH hpathFolder,
|
|
LPCTSTR pcszName,
|
|
PBOOL pbGenerated,
|
|
POBJECTTWIN *ppot)
|
|
{
|
|
TWINRESULT tr;
|
|
HCLSIFACECACHE hcic;
|
|
|
|
ASSERT(IS_VALID_HANDLE(hbr, BRFCASE));
|
|
ASSERT(IS_VALID_HANDLE(hpathFolder, PATH));
|
|
ASSERT(IS_VALID_STRING_PTR(pcszName, CSTR));
|
|
ASSERT(IS_VALID_WRITE_PTR(pbGenerated, BOOL));
|
|
ASSERT(IS_VALID_WRITE_PTR(ppot, POBJECTTWIN));
|
|
|
|
if (CreateClassInterfaceCache(&hcic))
|
|
{
|
|
HPTRARRAY hpaFolderPairs;
|
|
ARRAYINDEX aicPtrs;
|
|
ARRAYINDEX ai;
|
|
|
|
tr = TR_SUCCESS;
|
|
*pbGenerated = FALSE;
|
|
|
|
hpaFolderPairs = GetBriefcaseFolderPairPtrArray(hbr);
|
|
|
|
aicPtrs = GetPtrCount(hpaFolderPairs);
|
|
ASSERT(! (aicPtrs % 2));
|
|
|
|
for (ai = 0; ai < aicPtrs; ai++)
|
|
{
|
|
PCFOLDERPAIR pcfp;
|
|
|
|
pcfp = GetPtr(hpaFolderPairs, ai);
|
|
|
|
if (FolderTwinGeneratesObjectTwin(pcfp, hpathFolder, pcszName))
|
|
{
|
|
TCHAR rgchSubPath[MAX_PATH_LEN];
|
|
LPCTSTR pcszSubPath;
|
|
POBJECTTWIN potOther;
|
|
|
|
if (IsStubFlagSet(&(pcfp->stub), STUB_FL_SUBTREE))
|
|
pcszSubPath = FindChildPathSuffix(pcfp->hpath, hpathFolder,
|
|
rgchSubPath);
|
|
else
|
|
pcszSubPath = EMPTY_STRING;
|
|
|
|
tr = FakeObjectTwinFromFolderTwin(pcfp, pcszSubPath, pcszName,
|
|
hcic, ppot, &potOther);
|
|
|
|
if (tr == TR_SUCCESS)
|
|
*pbGenerated = TRUE;
|
|
else
|
|
ASSERT(tr != TR_DUPLICATE_TWIN);
|
|
|
|
break;
|
|
}
|
|
}
|
|
|
|
DestroyClassInterfaceCache(hcic);
|
|
}
|
|
else
|
|
tr = TR_OUT_OF_MEMORY;
|
|
|
|
ASSERT(tr != TR_SUCCESS ||
|
|
! *pbGenerated ||
|
|
IS_VALID_STRUCT_PTR(*ppot, COBJECTTWIN));
|
|
|
|
return(tr);
|
|
}
|
|
|
|
|
|
/*
|
|
** NamesIntersect()
|
|
**
|
|
** Determines whether or not two names may refer to the same object. Both
|
|
** names may contain wildcards ('*' or '?').
|
|
**
|
|
** Arguments: pcszName1 - first name
|
|
** pcszName2 - second name
|
|
**
|
|
** Returns: TRUE if the two names intersect. FALSE if not.
|
|
**
|
|
** Side Effects: none
|
|
**
|
|
** A "name" is broken up into two components: a "base" and an optional
|
|
** "extension", e.g., "BASE" or "BASE.EXT".
|
|
**
|
|
** "Intersecting names" are defined as follows:
|
|
**
|
|
** 1) An asterisk matches 0 or more characters in the base or extension.
|
|
** 2) Any characters after an asterisk in the base or extension are ignored.
|
|
** 3) A question mark matches exactly one character, or no character if it
|
|
** appears at the end of the base or extension.
|
|
**
|
|
** N.b., this function does not perform any checking on the validity of the two
|
|
** names.
|
|
*/
|
|
PUBLIC_CODE BOOL NamesIntersect(LPCTSTR pcszName1, LPCTSTR pcszName2)
|
|
{
|
|
BOOL bIntersect = FALSE;
|
|
|
|
ASSERT(IS_VALID_STRING_PTR(pcszName1, CSTR));
|
|
ASSERT(IS_VALID_STRING_PTR(pcszName2, CSTR));
|
|
|
|
if (NameComponentsIntersect(pcszName1, pcszName2))
|
|
{
|
|
LPCTSTR pcszExt1;
|
|
LPCTSTR pcszExt2;
|
|
|
|
/* Get extensions, skipping leading periods. */
|
|
|
|
pcszExt1 = ExtractExtension(pcszName1);
|
|
if (*pcszExt1 == PERIOD)
|
|
pcszExt1 = CharNext(pcszExt1);
|
|
|
|
pcszExt2 = ExtractExtension(pcszName2);
|
|
if (*pcszExt2 == PERIOD)
|
|
pcszExt2 = CharNext(pcszExt2);
|
|
|
|
bIntersect = NameComponentsIntersect(pcszExt1, pcszExt2);
|
|
}
|
|
|
|
return(bIntersect);
|
|
}
|
|
|
|
|
|
#ifdef DEBUG
|
|
|
|
/*
|
|
** IsValidTWINRESULT()
|
|
**
|
|
**
|
|
**
|
|
** Arguments:
|
|
**
|
|
** Returns:
|
|
**
|
|
** Side Effects: none
|
|
*/
|
|
PUBLIC_CODE BOOL IsValidTWINRESULT(TWINRESULT tr)
|
|
{
|
|
BOOL bResult;
|
|
|
|
switch (tr)
|
|
{
|
|
case TR_SUCCESS:
|
|
case TR_RH_LOAD_FAILED:
|
|
case TR_SRC_OPEN_FAILED:
|
|
case TR_SRC_READ_FAILED:
|
|
case TR_DEST_OPEN_FAILED:
|
|
case TR_DEST_WRITE_FAILED:
|
|
case TR_ABORT:
|
|
case TR_UNAVAILABLE_VOLUME:
|
|
case TR_OUT_OF_MEMORY:
|
|
case TR_FILE_CHANGED:
|
|
case TR_DUPLICATE_TWIN:
|
|
case TR_DELETED_TWIN:
|
|
case TR_HAS_FOLDER_TWIN_SRC:
|
|
case TR_INVALID_PARAMETER:
|
|
case TR_REENTERED:
|
|
case TR_SAME_FOLDER:
|
|
case TR_SUBTREE_CYCLE_FOUND:
|
|
case TR_NO_MERGE_HANDLER:
|
|
case TR_MERGE_INCOMPLETE:
|
|
case TR_TOO_DIFFERENT:
|
|
case TR_BRIEFCASE_LOCKED:
|
|
case TR_BRIEFCASE_OPEN_FAILED:
|
|
case TR_BRIEFCASE_READ_FAILED:
|
|
case TR_BRIEFCASE_WRITE_FAILED:
|
|
case TR_CORRUPT_BRIEFCASE:
|
|
case TR_NEWER_BRIEFCASE:
|
|
case TR_NO_MORE:
|
|
bResult = TRUE;
|
|
break;
|
|
|
|
default:
|
|
bResult = FALSE;
|
|
ERROR_OUT((TEXT("IsValidTWINRESULT(): Invalid TWINRESULT %d."),
|
|
tr));
|
|
break;
|
|
}
|
|
|
|
return(bResult);
|
|
}
|
|
|
|
#endif
|