* @brief Implementation of DirScan (q.v.) and helper functions
*/
+#include "pch.h"
#include "DirScan.h"
#include <cassert>
#include <memory>
#include "FolderCmp.h"
#include "FileFilterHelper.h"
#include "IAbortable.h"
-#include "FolderCmp.h"
#include "DirItem.h"
#include "DirTravel.h"
#include "paths.h"
#include "MergeApp.h"
#include "OptionsDef.h"
#include "OptionsMgr.h"
+#include "PathContext.h"
+#include "DebugNew.h"
using Poco::NotificationQueue;
using Poco::Notification;
using Poco::Stopwatch;
// Static functions (ie, functions only used locally)
-void CompareDiffItem(DIFFITEM &di, CDiffContext * pCtxt);
-static void StoreDiffData(DIFFITEM &di, CDiffContext * pCtxt,
- const FolderCmp * pCmpData);
-static DIFFITEM *AddToList(const String& sLeftDir, const String& sRightDir, const DirItem * lent, const DirItem * rent,
+static void CompareDiffItem(FolderCmp &fc, DIFFITEM &di);
+static DIFFITEM *AddToList(const String &sLeftDir, const String &sRightDir, const DirItem *lent, const DirItem *rent,
unsigned code, DiffFuncStruct *myStruct, DIFFITEM *parent);
-static DIFFITEM *AddToList(const String& sDir1, const String& sDir2, const String& sDir3, const DirItem * ent1, const DirItem * ent2, const DirItem * ent3,
+static DIFFITEM *AddToList(const String &sDir1, const String &sDir2, const String &sDir3, const DirItem *ent1, const DirItem *ent2, const DirItem *ent3,
unsigned code, DiffFuncStruct *myStruct, DIFFITEM *parent, int nItems = 3);
-static void UpdateDiffItem(DIFFITEM & di, bool & bExists, CDiffContext *pCtxt);
-static int CompareItems(NotificationQueue& queue, DiffFuncStruct *myStruct, uintptr_t parentdiffpos);
+static void UpdateDiffItem(DIFFITEM &di, bool &bExists, CDiffContext *pCtxt);
+static int CompareItems(NotificationQueue &queue, DiffFuncStruct *myStruct, DIFFITEM *parentdiffpos);
class WorkNotification: public Poco::Notification
{
void run()
{
+ FolderCmp fc(m_pCtxt);
// keep the scripts alive during the Rescan
// when we exit the thread, we delete this and release the scripts
CAssureScriptsForThread scriptsForRescan;
if (pWorkNf != nullptr) {
m_pCtxt->m_pCompareStats->BeginCompare(&pWorkNf->data(), m_id);
if (!m_pCtxt->ShouldAbort())
- CompareDiffItem(pWorkNf->data(), m_pCtxt);
+ CompareDiffItem(fc, pWorkNf->data());
pWorkNf->queueResult().enqueueNotification(new WorkCompletedNotification(pWorkNf->data()));
}
pNf = m_queue.waitDequeueNotification();
* @brief Collect file- and folder-names to list.
* This function walks given folders and adds found subfolders and files into
* lists. There are two modes, determined by the @p depth:
- * - in non-recursive mode we walk only given folders, and add files.
+ * - in non-recursive mode we walk only given folders, and add files
* contained. Subfolders are added as folder items, not walked into.
* - in recursive mode we walk all subfolders and add the files they
* contain into list.
* @param [in] rightsubdir Right side subdirectory under root path
* @param [in] bRightUniq Is right-side folder unique folder?
* @param [in] myStruct Compare-related data, like context etc.
- * @param [in] casesensitive Is filename compare casesensitive?
+ * @param [in] casesensitive Is filename compare case sensitive?
* @param [in] depth Levels of subdirectories to scan, -1 scans all
* @param [in] parent Folder diff item to be scanned
* @param [in] bUniques If true, walk into unique folders.
String sDir[3];
String subprefix[3];
- int nIndex;
std::copy(paths.begin(), paths.end(), sDir);
if (!subdir[0].empty())
{
- for (nIndex = 0; nIndex < paths.GetSize(); nIndex++)
+ for (int nIndex = 0; nIndex < paths.GetSize(); nIndex++)
{
sDir[nIndex] = paths::ConcatPath(sDir[nIndex], subdir[nIndex]);
subprefix[nIndex] = subdir[nIndex] + backslash;
}
DirItemArray dirs[3], aFiles[3];
- for (nIndex = 0; nIndex < nDirs; nIndex++)
+ for (int nIndex = 0; nIndex < nDirs; nIndex++)
LoadAndSortFiles(sDir[nIndex], &dirs[nIndex], &aFiles[nIndex], casesensitive);
// Allow user to abort scanning
// i points to current directory in left list (leftDirs)
// j points to current directory in right list (rightDirs)
- for (nIndex = 0; nIndex < nDirs; nIndex++)
- if (dirs[nIndex].size() != 0 || aFiles[nIndex].size() != 0) break;
- if (nIndex == nDirs)
- return 0;
+ {
+ int nIndex;
+ for (nIndex = 0; nIndex < nDirs; nIndex++)
+ if (dirs[nIndex].size() != 0 || aFiles[nIndex].size() != 0) break;
+ if (nIndex == nDirs)
+ return 0;
+ }
DirItemArray::size_type i=0, j=0, k=0;
while (true)
}
break;
}
+
+ if (parent != nullptr)
+ {
+ for (int nIndex = 0; nIndex < nDirs; ++nIndex)
+ if (parent->diffcode.exists(nIndex) && parent->diffFileInfo[nIndex].size == DirItem::FILE_SIZE_NONE)
+ parent->diffFileInfo[nIndex].size = 0;
+
+ DIFFITEM *dic = parent->GetFirstChild();
+ while (dic)
+ {
+ for (int nIndex = 0; nIndex < nDirs; ++nIndex)
+ {
+ if (dic->diffFileInfo[nIndex].size != DirItem::FILE_SIZE_NONE)
+ parent->diffFileInfo[nIndex].size += dic->diffFileInfo[nIndex].size;
+ }
+ dic = dic->GetFwdSiblingLink();
+ }
+ }
+
return 1;
}
* @param parentdiffpos [in] Position of parent diff item
* @return >= 0 number of diff items, -1 if compare was aborted
*/
-int DirScan_CompareItems(DiffFuncStruct *myStruct, uintptr_t parentdiffpos)
+int DirScan_CompareItems(DiffFuncStruct *myStruct, DIFFITEM *parentdiffpos)
{
const int compareMethod = myStruct->context->GetCompareMethod();
int nworkers = 1;
return res;
}
-static int CompareItems(NotificationQueue& queue, DiffFuncStruct *myStruct, uintptr_t parentdiffpos)
+static int CompareItems(NotificationQueue& queue, DiffFuncStruct *myStruct, DIFFITEM *parentdiffpos)
{
NotificationQueue queueResult;
Stopwatch stopwatch;
int res = 0;
int count = 0;
bool bCompareFailure = false;
- if (parentdiffpos == 0)
+ if (parentdiffpos == nullptr)
myStruct->pSemaphore->wait();
stopwatch.start();
- uintptr_t pos = pCtxt->GetFirstChildDiffPosition(parentdiffpos);
- while (pos != 0)
+ DIFFITEM *pos = pCtxt->GetFirstChildDiffPosition(parentdiffpos);
+ while (pos != nullptr)
{
if (pCtxt->ShouldAbort())
break;
stopwatch.restart();
}
myStruct->pSemaphore->wait();
- uintptr_t curpos = pos;
+ DIFFITEM *curpos = pos;
DIFFITEM &di = pCtxt->GetNextSiblingDiffRefPosition(pos);
bool existsalldirs = di.diffcode.existAll();
if (di.diffcode.isDirectory() && pCtxt->m_bRecursive)
if (pWorkCompletedNf != nullptr) {
DIFFITEM &di = pWorkCompletedNf->data();
if (di.diffcode.isResultError()) {
- DIFFITEM *diParent = di.parent;
+ DIFFITEM *diParent = di.GetParentLink();
+ assert(diParent != nullptr);
if (diParent != nullptr)
{
diParent->diffcode.diffcode |= DIFFCODE::CMPERR;
* @param parentdiffpos [in] Position of parent diff item
* @return >= 0 number of diff items, -1 if compare was aborted
*/
-static int CompareRequestedItems(DiffFuncStruct *myStruct, uintptr_t parentdiffpos)
+static int CompareRequestedItems(DiffFuncStruct *myStruct, DIFFITEM *parentdiffpos)
{
CDiffContext *pCtxt = myStruct->context;
+ FolderCmp fc(pCtxt);
int res = 0;
- uintptr_t pos = pCtxt->GetFirstChildDiffPosition(parentdiffpos);
-
- while (pos != NULL)
+ bool bCompareFailure = false;
+ if (parentdiffpos == nullptr)
+ myStruct->pSemaphore->wait();
+ DIFFITEM *pos = pCtxt->GetFirstChildDiffPosition(parentdiffpos);
+ while (pos != nullptr)
{
if (pCtxt->ShouldAbort())
{
break;
}
- uintptr_t curpos = pos;
+ DIFFITEM *curpos = pos;
DIFFITEM &di = pCtxt->GetNextSiblingDiffRefPosition(pos);
bool existsalldirs = di.diffcode.existAll();
if (di.diffcode.isDirectory())
di.diffcode.diffcode |= DIFFCODE::DIFF;
res += ndiff;
}
- else if (ndiff == 0)
+ else
+ if (ndiff == 0)
{
if (existsalldirs)
di.diffcode.diffcode |= DIFFCODE::SAME;
+ }
+ else
+ if (ndiff == -1)
+ { // There were file IO-errors during sub-directory comparison.
+ di.diffcode.diffcode |= DIFFCODE::CMPERR;
+ bCompareFailure = true;
}
}
}
else
{
if (di.diffcode.isScanNeeded())
- CompareDiffItem(di, pCtxt);
+ {
+ CompareDiffItem(fc, di);
+ if (di.diffcode.isResultError()) {
+ DIFFITEM *diParent = di.GetParentLink();
+ assert(diParent != nullptr);
+ if (diParent != nullptr)
+ {
+ diParent->diffcode.diffcode |= DIFFCODE::CMPERR;
+ bCompareFailure = true;
+ }
+ }
+
+ }
}
if (di.diffcode.isResultDiff() ||
(!existsalldirs && !di.diffcode.isResultFiltered()))
res++;
}
- return res;
+ return bCompareFailure ? -1 : res;;
}
-int DirScan_CompareRequestedItems(DiffFuncStruct *myStruct, uintptr_t parentdiffpos)
+int DirScan_CompareRequestedItems(DiffFuncStruct *myStruct, DIFFITEM *parentdiffpos)
{
- CAssureScriptsForThread scriptsForRescan;
return CompareRequestedItems(myStruct, parentdiffpos);
}
-static int markChildrenForRescan(CDiffContext *pCtxt, uintptr_t parentdiffpos)
+static int markChildrenForRescan(CDiffContext *pCtxt, DIFFITEM *parentdiffpos)
{
int ncount = 0;
- uintptr_t pos = pCtxt->GetFirstChildDiffPosition(parentdiffpos);
- while (pos != NULL)
+ DIFFITEM *pos = pCtxt->GetFirstChildDiffPosition(parentdiffpos);
+ while (pos != nullptr)
{
- uintptr_t curpos = pos;
+ DIFFITEM *curpos = pos;
DIFFITEM &di = pCtxt->GetNextSiblingDiffRefPosition(pos);
if (di.diffcode.isDirectory())
ncount += markChildrenForRescan(pCtxt, curpos);
return ncount;
}
-int DirScan_UpdateMarkedItems(DiffFuncStruct *myStruct, uintptr_t parentdiffpos)
+int DirScan_UpdateMarkedItems(DiffFuncStruct *myStruct, DIFFITEM *parentdiffpos)
{
CDiffContext *pCtxt = myStruct->context;
- uintptr_t pos = pCtxt->GetFirstChildDiffPosition(parentdiffpos);
+ DIFFITEM *pos = pCtxt->GetFirstChildDiffPosition(parentdiffpos);
int ncount = 0;
-
- while (pos != NULL)
+
+ while (pos != nullptr)
{
if (pCtxt->ShouldAbort())
break;
- uintptr_t curpos = pos;
+ DIFFITEM *curpos = pos;
DIFFITEM &di = pCtxt->GetNextSiblingDiffRefPosition(pos);
- bool bItemsExist = true;
if (di.diffcode.isScanNeeded())
{
+ bool bItemsExist = true;
UpdateDiffItem(di, bItemsExist, pCtxt);
if (!bItemsExist)
- di.RemoveSelf();
- else if (!di.diffcode.isDirectory())
+ {
+ di.DelinkFromSiblings(); // delink from list of Siblings
+ delete &di; // Also delete all Children items
+ continue; // (... because `di` is now invalid)
+ }
+ if (!di.diffcode.isDirectory())
++ncount;
}
- if (bItemsExist && di.diffcode.isDirectory() && pCtxt->m_bRecursive)
+ if (di.diffcode.isDirectory() && pCtxt->m_bRecursive)
{
+ for (int i = 0; i < pCtxt->GetCompareDirs(); ++i)
+ if (di.diffcode.exists(i))
+ di.diffFileInfo[i].size = 0;
if (di.diffcode.isScanNeeded() && !di.diffcode.isResultFiltered())
{
di.RemoveChildren();
ncount += DirScan_UpdateMarkedItems(myStruct, curpos);
}
}
+ if (parentdiffpos != nullptr && pCtxt->m_bRecursive)
+ {
+ for (int nIndex = 0; nIndex < pCtxt->GetCompareDirs(); ++nIndex)
+ if (curpos->diffFileInfo[nIndex].size != DirItem::FILE_SIZE_NONE)
+ parentdiffpos->diffFileInfo[nIndex].size += curpos->diffFileInfo[nIndex].size;
+ }
}
return ncount;
}
* - false if items were deleted, so diffitem is not valid
* @param [in] pCtxt Compare context
*/
-static void UpdateDiffItem(DIFFITEM & di, bool & bExists, CDiffContext *pCtxt)
+static void UpdateDiffItem(DIFFITEM &di, bool & bExists, CDiffContext *pCtxt)
{
bExists = false;
di.diffcode.setSideNone();
*
* This function does the actual compare for previously gathered list of
* items. Basically we:
- * - ignore items matching filefilters
+ * - ignore items matching file filters
* - add non-ignored directories (no compare for directory items)
- * - add unique files
+ * - add unique files
* - compare files
*
* @param [in] di DiffItem to compare
* @todo For date compare, maybe we should use creation date if modification
* date is missing?
*/
-void CompareDiffItem(DIFFITEM &di, CDiffContext * pCtxt)
+static void CompareDiffItem(FolderCmp &fc, DIFFITEM &di)
{
+ CDiffContext *const pCtxt = fc.m_pCtxt;
int nDirs = pCtxt->GetCompareDirs();
// Clear rescan-request flag (not set by all codepaths)
di.diffcode.diffcode &= ~DIFFCODE::NEEDSCAN;
{
// We don't actually 'compare' directories, just add non-ignored
// directories to list.
- StoreDiffData(di, pCtxt, nullptr);
}
else
{
)
{
di.diffcode.diffcode |= DIFFCODE::INCLUDED;
- FolderCmp folderCmp;
- di.diffcode.diffcode |= folderCmp.prepAndCompareFiles(pCtxt, di);
- StoreDiffData(di, pCtxt, &folderCmp);
+ di.diffcode.diffcode |= fc.prepAndCompareFiles(di);
+ di.nsdiffs = fc.m_ndiffs;
+ di.nidiffs = fc.m_ntrivialdiffs;
+
+ for (int i = 0; i < nDirs; ++i)
+ {
+ // Set text statistics
+ if (di.diffcode.exists(i))
+ {
+ di.diffFileInfo[i].m_textStats = fc.m_diffFileData.m_textStats[i];
+ di.diffFileInfo[i].encoding = fc.m_diffFileData.m_FileLocation[i].encoding;
+ }
+ }
}
else
{
di.diffcode.diffcode |= DIFFCODE::SKIPPED;
- StoreDiffData(di, pCtxt, nullptr);
- }
- }
-}
-
-/**
- * @brief Send one file or directory result back through the diff context.
- * @param [in] di Data to store.
- * @param [in] pCtxt Compare context.
- * @param [in] pCmpData Folder compare data.
- */
-static void StoreDiffData(DIFFITEM &di, CDiffContext * pCtxt,
- const FolderCmp * pCmpData)
-{
- if (pCmpData != nullptr)
- {
- di.nsdiffs = pCmpData->m_ndiffs;
- di.nidiffs = pCmpData->m_ntrivialdiffs;
-
- for (int i = 0; i < pCtxt->GetCompareDirs(); ++i)
- {
- // Set text statistics
- if (di.diffcode.exists(i))
- {
- di.diffFileInfo[i].m_textStats = pCmpData->m_diffFileData.m_textStats[i];
- di.diffFileInfo[i].encoding = pCmpData->m_diffFileData.m_FileLocation[i].encoding;
- }
}
}
-
pCtxt->m_pCompareStats->AddItem(di.diffcode.diffcode);
- //pCtxt->AddDiff(di);
}
/**
* @brief Add one compare item to list.
*/
static DIFFITEM *AddToList(const String& sDir1, const String& sDir2, const String& sDir3,
- const DirItem * ent1, const DirItem * ent2, const DirItem * ent3,
- unsigned code, DiffFuncStruct *myStruct, DIFFITEM *parent, int nItems)
+ const DirItem *ent1, const DirItem *ent2, const DirItem *ent3,
+ unsigned code, DiffFuncStruct *myStruct, DIFFITEM *parent, int nItems /*= 3*/)
{
// We must store both paths - we cannot get paths later
// and we need unique item paths for example when items
// change to identical
- DIFFITEM *di = myStruct->context->AddDiff(parent);
+ DIFFITEM *di = myStruct->context->AddNewDiff(parent);
- di->parent = parent;
di->diffFileInfo[0].path = sDir1;
di->diffFileInfo[1].path = sDir2;
di->diffFileInfo[2].path = sDir3;
else
di->diffcode.diffcode = code | DIFFCODE::THREEWAY;
- myStruct->context->m_pCompareStats->IncreaseTotalItems();
- myStruct->pSemaphore->set();
+ if (myStruct->m_fncCollect)
+ {
+ myStruct->context->m_pCompareStats->IncreaseTotalItems();
+ myStruct->pSemaphore->set();
+ }
return di;
}