summaryrefslogtreecommitdiff
path: root/synchronization.cpp
diff options
context:
space:
mode:
authorDaniel Wilhelm <daniel@wili.li>2014-04-18 17:16:21 +0200
committerDaniel Wilhelm <daniel@wili.li>2014-04-18 17:16:21 +0200
commit88a2d0007db222c339f0b6a17794a2014a241892 (patch)
tree75105ef49b3a52b7ee176a1ad480e7652e49825f /synchronization.cpp
parent4.2 (diff)
downloadFreeFileSync-88a2d0007db222c339f0b6a17794a2014a241892.tar.gz
FreeFileSync-88a2d0007db222c339f0b6a17794a2014a241892.tar.bz2
FreeFileSync-88a2d0007db222c339f0b6a17794a2014a241892.zip
4.3
Diffstat (limited to 'synchronization.cpp')
-rw-r--r--synchronization.cpp1423
1 files changed, 864 insertions, 559 deletions
diff --git a/synchronization.cpp b/synchronization.cpp
index 66c7d262..8a5027be 100644
--- a/synchronization.cpp
+++ b/synchronization.cpp
@@ -8,7 +8,7 @@
#include <memory>
#include <deque>
#include <stdexcept>
-#include <wx/msgdlg.h>
+#include <wx/utils.h>
#include <wx/log.h>
#include <wx/file.h>
#include <wx+/string_conv.h>
@@ -32,36 +32,55 @@
using namespace zen;
+namespace
+{
+inline
+int getCUD(const SyncStatistics& stat)
+{
+ return stat.getCreate() +
+ stat.getUpdate() +
+ stat.getDelete();
+}
+}
+
void SyncStatistics::init()
{
- createLeft = 0;
- createRight = 0;
- overwriteLeft = 0;
- overwriteRight = 0;
- deleteLeft = 0;
- deleteRight = 0;
- conflict = 0;
- rowsTotal = 0;
+ createLeft = 0;
+ createRight = 0;
+ updateLeft = 0;
+ updateRight = 0;
+ deleteLeft = 0;
+ deleteRight = 0;
+ conflict = 0;
+ rowsTotal = 0;
}
SyncStatistics::SyncStatistics(const FolderComparison& folderCmp)
{
init();
- std::for_each(begin(folderCmp), end(folderCmp), [&](const BaseDirMapping& baseMap) { getNumbersRecursively(baseMap); });
+ std::for_each(begin(folderCmp), end(folderCmp), [&](const BaseDirMapping& baseMap) { recurse(baseMap); });
}
SyncStatistics::SyncStatistics(const HierarchyObject& hierObj)
{
init();
- getNumbersRecursively(hierObj);
+ recurse(hierObj);
+}
+
+
+SyncStatistics::SyncStatistics(const FileMapping& fileObj)
+{
+ init();
+ getFileNumbers(fileObj);
+ rowsTotal += 1;
}
inline
-void SyncStatistics::getNumbersRecursively(const HierarchyObject& hierObj)
+void SyncStatistics::recurse(const HierarchyObject& hierObj)
{
std::for_each(hierObj.refSubDirs().begin(), hierObj.refSubDirs().end(),
[&](const DirMapping& dirObj) { getDirNumbers(dirObj); });
@@ -101,13 +120,25 @@ void SyncStatistics::getFileNumbers(const FileMapping& fileObj)
++deleteRight;
break;
+ case SO_MOVE_LEFT_TARGET:
+ ++updateLeft;
+ break;
+
+ case SO_MOVE_RIGHT_TARGET:
+ ++updateRight;
+ break;
+
+ case SO_MOVE_LEFT_SOURCE: //ignore
+ case SO_MOVE_RIGHT_SOURCE: //
+ break;
+
case SO_OVERWRITE_LEFT:
- ++overwriteLeft;
+ ++updateLeft;
dataToProcess += fileObj.getFileSize<RIGHT_SIDE>();
break;
case SO_OVERWRITE_RIGHT:
- ++overwriteRight;
+ ++updateRight;
dataToProcess += fileObj.getFileSize<LEFT_SIDE>();
break;
@@ -118,11 +149,11 @@ void SyncStatistics::getFileNumbers(const FileMapping& fileObj)
break;
case SO_COPY_METADATA_TO_LEFT:
- ++overwriteLeft;
+ ++updateLeft;
break;
case SO_COPY_METADATA_TO_RIGHT:
- ++overwriteRight;
+ ++updateRight;
break;
case SO_DO_NOTHING:
@@ -155,12 +186,12 @@ void SyncStatistics::getLinkNumbers(const SymLinkMapping& linkObj)
case SO_OVERWRITE_LEFT:
case SO_COPY_METADATA_TO_LEFT:
- ++overwriteLeft;
+ ++updateLeft;
break;
case SO_OVERWRITE_RIGHT:
case SO_COPY_METADATA_TO_RIGHT:
- ++overwriteRight;
+ ++updateRight;
break;
case SO_UNRESOLVED_CONFLICT:
@@ -169,6 +200,11 @@ void SyncStatistics::getLinkNumbers(const SymLinkMapping& linkObj)
firstConflicts.push_back(std::make_pair(linkObj.getObjRelativeName(), linkObj.getSyncOpConflict()));
break;
+ case SO_MOVE_LEFT_SOURCE:
+ case SO_MOVE_RIGHT_SOURCE:
+ case SO_MOVE_LEFT_TARGET:
+ case SO_MOVE_RIGHT_TARGET:
+ assert(false);
case SO_DO_NOTHING:
case SO_EQUAL:
break;
@@ -209,20 +245,24 @@ void SyncStatistics::getDirNumbers(const DirMapping& dirObj)
break;
case SO_COPY_METADATA_TO_LEFT:
- ++overwriteLeft;
+ ++updateLeft;
break;
case SO_COPY_METADATA_TO_RIGHT:
- ++overwriteRight;
+ ++updateRight;
break;
+ case SO_MOVE_LEFT_SOURCE:
+ case SO_MOVE_RIGHT_SOURCE:
+ case SO_MOVE_LEFT_TARGET:
+ case SO_MOVE_RIGHT_TARGET:
+ assert(false);
case SO_DO_NOTHING:
case SO_EQUAL:
break;
}
- //recurse into sub-dirs
- getNumbersRecursively(dirObj);
+ recurse(dirObj);
}
@@ -245,7 +285,7 @@ std::vector<zen::FolderPairSyncCfg> zen::extractSyncCfg(const MainConfiguration&
output.push_back(
FolderPairSyncCfg(syncCfg.directionCfg.var == DirectionConfig::AUTOMATIC,
syncCfg.handleDeletion,
- toZ(syncCfg.customDeletionDirectory)));
+ syncCfg.customDeletionDirectory));
}
return output;
@@ -257,7 +297,7 @@ namespace
bool synchronizationNeeded(const SyncStatistics& statisticsTotal)
{
return statisticsTotal.getCreate() +
- statisticsTotal.getOverwrite() +
+ statisticsTotal.getUpdate() +
statisticsTotal.getDelete() +
//conflicts (unless excluded) justify a sync! Also note: if this method returns false, no warning about unresolved conflicts were shown!
statisticsTotal.getConflict() != 0;
@@ -269,18 +309,18 @@ bool synchronizationNeeded(const SyncStatistics& statisticsTotal)
bool significantDifferenceDetected(const SyncStatistics& folderPairStat)
{
//initial file copying shall not be detected as major difference
- if (folderPairStat.getCreate<LEFT_SIDE>() == 0 &&
- folderPairStat.getOverwrite() == 0 &&
- folderPairStat.getDelete() == 0 &&
- folderPairStat.getConflict() == 0) return false;
+ if (folderPairStat.getCreate<LEFT_SIDE>() == 0 &&
+ folderPairStat.getUpdate () == 0 &&
+ folderPairStat.getDelete () == 0 &&
+ folderPairStat.getConflict() == 0) return false;
if (folderPairStat.getCreate<RIGHT_SIDE>() == 0 &&
- folderPairStat.getOverwrite() == 0 &&
- folderPairStat.getDelete() == 0 &&
- folderPairStat.getConflict() == 0) return false;
+ folderPairStat.getUpdate () == 0 &&
+ folderPairStat.getDelete () == 0 &&
+ folderPairStat.getConflict() == 0) return false;
- const int changedRows = folderPairStat.getCreate() +
- folderPairStat.getOverwrite() +
- folderPairStat.getDelete() +
+ const int changedRows = folderPairStat.getCreate () +
+ folderPairStat.getUpdate () +
+ folderPairStat.getDelete () +
folderPairStat.getConflict();
return changedRows >= 10 && changedRows > 0.5 * folderPairStat.getRowCount();
@@ -361,10 +401,10 @@ SyncProcess::SyncProcess(xmlAccess::OptionalDialogs& warnings,
transactionalFileCopy_(transactionalFileCopy),
m_warnings(warnings),
procCallback(handler)
- {
-if (runWithBackgroundPriority)
-procBackground.reset(new ScheduleForBackgroundProcessing);
- }
+{
+ if (runWithBackgroundPriority)
+ procBackground.reset(new ScheduleForBackgroundProcessing);
+}
//--------------------------------------------------------------------------------------------------------------
namespace
@@ -377,7 +417,7 @@ class DeletionHandling //e.g. generate name of alternate deletion directory (uni
public:
DeletionHandling(DeletionPolicy handleDel,
const Zstring& custDelFolder,
- const Zstring& baseDir, //with separator postfix
+ const Zstring& baseDirPf, //with separator postfix
ProcessCallback& procCallback);
~DeletionHandling(); //always (try to) clean up, even if synchronization is aborted!
@@ -387,9 +427,9 @@ public:
void removeFile (const Zstring& relativeName) const; //throw FileError
void removeFolder(const Zstring& relativeName) const; //throw FileError
- const wxString& getTxtRemovingFile () const { return txtRemovingFile; } //
- const wxString& getTxtRemovingSymLink() const { return txtRemovingSymlink; } //status text templates
- const wxString& getTxtRemovingDir () const { return txtRemovingDirectory; } //
+ const std::wstring& getTxtRemovingFile () const { return txtRemovingFile; } //
+ const std::wstring& getTxtRemovingSymLink() const { return txtRemovingSymlink; } //status text templates
+ const std::wstring& getTxtRemovingDir () const { return txtRemovingDirectory; } //
//evaluate whether a deletion will actually free space within a volume
bool deletionFreesSpace() const;
@@ -401,12 +441,12 @@ private:
Zstring sessionDelDir; //target deletion folder for current folder pair (with timestamp, ends with path separator)
- Zstring baseDir_; //with separator postfix
+ Zstring baseDirPf_; //with separator postfix
//preloaded status texts:
- wxString txtRemovingFile;
- wxString txtRemovingSymlink;
- wxString txtRemovingDirectory;
+ std::wstring txtRemovingFile;
+ std::wstring txtRemovingSymlink;
+ std::wstring txtRemovingDirectory;
bool cleanedUp;
};
@@ -414,41 +454,41 @@ private:
DeletionHandling::DeletionHandling(DeletionPolicy handleDel,
const Zstring& custDelFolder,
- const Zstring& baseDir, //with separator postfix
+ const Zstring& baseDirPf, //with separator postfix
ProcessCallback& procCallback) :
deletionType(handleDel),
procCallback_(&procCallback),
- baseDir_(baseDir),
+ baseDirPf_(baseDirPf),
cleanedUp(false)
{
#ifdef FFS_WIN
- if (baseDir.empty() ||
- (deletionType == MOVE_TO_RECYCLE_BIN && recycleBinStatus(baseDir) != STATUS_REC_EXISTS))
+ if (baseDirPf.empty() ||
+ (deletionType == MOVE_TO_RECYCLE_BIN && recycleBinStatus(baseDirPf) != STATUS_REC_EXISTS))
deletionType = DELETE_PERMANENTLY; //Windows' ::SHFileOperation() will do this anyway, but we have a better and faster deletion routine (e.g. on networks)
#endif
switch (deletionType)
{
case DELETE_PERMANENTLY:
- txtRemovingFile = replaceCpy(_("Deleting file %x" ), L"%x", L"\n\"%x\"", false);
- txtRemovingDirectory = replaceCpy(_("Deleting folder %x" ), L"%x", L"\n\"%x\"", false);
- txtRemovingSymlink = replaceCpy(_("Deleting symbolic link %x"), L"%x", L"\n\"%x\"", false);
+ txtRemovingFile = replaceCpy(_("Deleting file %x" ), L"%x", L"\"%x\"", false);
+ txtRemovingDirectory = replaceCpy(_("Deleting folder %x" ), L"%x", L"\"%x\"", false);
+ txtRemovingSymlink = replaceCpy(_("Deleting symbolic link %x"), L"%x", L"\"%x\"", false);
break;
case MOVE_TO_RECYCLE_BIN:
- sessionDelDir = getSessionDeletionDir(baseDir_, Zstr("FFS "));
+ sessionDelDir = getSessionDeletionDir(baseDirPf_, Zstr("FFS "));
- txtRemovingFile = replaceCpy(_("Moving file %x to recycle bin" ), L"%x", L"\n\"%x\"", false);
- txtRemovingDirectory = replaceCpy(_("Moving folder %x to recycle bin" ), L"%x", L"\n\"%x\"", false);
- txtRemovingSymlink = replaceCpy(_("Moving symbolic link %x to recycle bin"), L"%x", L"\n\"%x\"", false);
+ txtRemovingFile = replaceCpy(_("Moving file %x to recycle bin" ), L"%x", L"\"%x\"", false);
+ txtRemovingDirectory = replaceCpy(_("Moving folder %x to recycle bin" ), L"%x", L"\"%x\"", false);
+ txtRemovingSymlink = replaceCpy(_("Moving symbolic link %x to recycle bin"), L"%x", L"\"%x\"", false);
break;
case MOVE_TO_CUSTOM_DIRECTORY:
sessionDelDir = getSessionDeletionDir(custDelFolder);
- txtRemovingFile = replaceCpy(replaceCpy(_("Moving file %x to %y" ), L"%x", L"\n\"%x\"", false), L"%y", L"\"" + utf8CvrtTo<wxString>(custDelFolder) + L"\"", false);
- txtRemovingDirectory = replaceCpy(replaceCpy(_("Moving folder %x to %y" ), L"%x", L"\n\"%x\"", false), L"%y", L"\"" + utf8CvrtTo<wxString>(custDelFolder) + L"\"", false);
- txtRemovingSymlink = replaceCpy(replaceCpy(_("Moving symbolic link %x to %y"), L"%x", L"\n\"%x\"", false), L"%y", L"\"" + utf8CvrtTo<wxString>(custDelFolder) + L"\"", false);
+ txtRemovingFile = replaceCpy(replaceCpy(_("Moving file %x to %y" ), L"%x", L"\"%x\"", false), L"%y", L"\"" + utf8CvrtTo<std::wstring>(custDelFolder) + L"\"", false);
+ txtRemovingDirectory = replaceCpy(replaceCpy(_("Moving folder %x to %y" ), L"%x", L"\"%x\"", false), L"%y", L"\"" + utf8CvrtTo<std::wstring>(custDelFolder) + L"\"", false);
+ txtRemovingSymlink = replaceCpy(replaceCpy(_("Moving symbolic link %x to %y"), L"%x", L"\"%x\"", false), L"%y", L"\"" + utf8CvrtTo<std::wstring>(custDelFolder) + L"\"", false);
break;
}
}
@@ -497,12 +537,12 @@ struct CallbackRemoveDirImpl : public CallbackRemoveDir
virtual void notifyFileDeletion(const Zstring& filename)
{
- delHandling_.procCallback_->reportStatus(replaceCpy(delHandling_.getTxtRemovingFile(), L"%x", utf8CvrtTo<wxString>(filename)));
+ delHandling_.procCallback_->reportStatus(replaceCpy(delHandling_.getTxtRemovingFile(), L"%x", utf8CvrtTo<std::wstring>(filename)));
}
virtual void notifyDirDeletion(const Zstring& dirname)
{
- delHandling_.procCallback_->reportStatus(replaceCpy(delHandling_.getTxtRemovingDir(), L"%x", utf8CvrtTo<wxString>(dirname)));
+ delHandling_.procCallback_->reportStatus(replaceCpy(delHandling_.getTxtRemovingDir(), L"%x", utf8CvrtTo<std::wstring>(dirname)));
}
private:
@@ -513,7 +553,7 @@ private:
void DeletionHandling::removeFile(const Zstring& relativeName) const
{
- const Zstring fullName = baseDir_ + relativeName;
+ const Zstring fullName = baseDirPf_ + relativeName;
switch (deletionType)
{
@@ -562,7 +602,7 @@ void DeletionHandling::removeFile(const Zstring& relativeName) const
void DeletionHandling::removeFolder(const Zstring& relativeName) const
{
- const Zstring fullName = baseDir_ + relativeName;
+ const Zstring fullName = baseDirPf_ + relativeName;
switch (deletionType)
{
@@ -621,7 +661,7 @@ bool DeletionHandling::deletionFreesSpace() const
case MOVE_TO_RECYCLE_BIN:
return false; //in general... (unless Recycle Bin is full)
case MOVE_TO_CUSTOM_DIRECTORY:
- switch (zen::onSameVolume(baseDir_, sessionDelDir))
+ switch (zen::onSameVolume(baseDirPf_, sessionDelDir))
{
case IS_SAME_YES:
return false;
@@ -642,20 +682,21 @@ namespace
class DiskSpaceNeeded
{
public:
- DiskSpaceNeeded(const BaseDirMapping& baseObj, bool freeSpaceDelLeft, bool freeSpaceDelRight) :
- freeSpaceDelLeft_(freeSpaceDelLeft),
- freeSpaceDelRight_(freeSpaceDelRight)
+ static std::pair<Int64, Int64> calculate(const BaseDirMapping& baseObj, bool freeSpaceDelLeft, bool freeSpaceDelRight)
{
- processRecursively(baseObj);
+ DiskSpaceNeeded inst(baseObj, freeSpaceDelLeft, freeSpaceDelRight);
+ return std::make_pair(inst.spaceNeededLeft, inst.spaceNeededRight);
}
- std::pair<zen::Int64, zen::Int64> getSpaceTotal() const
+private:
+ DiskSpaceNeeded(const BaseDirMapping& baseObj, bool freeSpaceDelLeft, bool freeSpaceDelRight) :
+ freeSpaceDelLeft_(freeSpaceDelLeft),
+ freeSpaceDelRight_(freeSpaceDelRight)
{
- return std::make_pair(spaceNeededLeft, spaceNeededRight);
+ recurse(baseObj);
}
-private:
- void processRecursively(const HierarchyObject& hierObj)
+ void recurse(const HierarchyObject& hierObj)
{
//don't process directories
@@ -664,33 +705,33 @@ private:
switch (i->getSyncOperation()) //evaluate comparison result and sync direction
{
case SO_CREATE_NEW_LEFT:
- spaceNeededLeft += to<zen::Int64>(i->getFileSize<RIGHT_SIDE>());
+ spaceNeededLeft += to<Int64>(i->getFileSize<RIGHT_SIDE>());
break;
case SO_CREATE_NEW_RIGHT:
- spaceNeededRight += to<zen::Int64>(i->getFileSize<LEFT_SIDE>());
+ spaceNeededRight += to<Int64>(i->getFileSize<LEFT_SIDE>());
break;
case SO_DELETE_LEFT:
if (freeSpaceDelLeft_)
- spaceNeededLeft -= to<zen::Int64>(i->getFileSize<LEFT_SIDE>());
+ spaceNeededLeft -= to<Int64>(i->getFileSize<LEFT_SIDE>());
break;
case SO_DELETE_RIGHT:
if (freeSpaceDelRight_)
- spaceNeededRight -= to<zen::Int64>(i->getFileSize<RIGHT_SIDE>());
+ spaceNeededRight -= to<Int64>(i->getFileSize<RIGHT_SIDE>());
break;
case SO_OVERWRITE_LEFT:
if (freeSpaceDelLeft_)
- spaceNeededLeft -= to<zen::Int64>(i->getFileSize<LEFT_SIDE>());
- spaceNeededLeft += to<zen::Int64>(i->getFileSize<RIGHT_SIDE>());
+ spaceNeededLeft -= to<Int64>(i->getFileSize<LEFT_SIDE>());
+ spaceNeededLeft += to<Int64>(i->getFileSize<RIGHT_SIDE>());
break;
case SO_OVERWRITE_RIGHT:
if (freeSpaceDelRight_)
- spaceNeededRight -= to<zen::Int64>(i->getFileSize<RIGHT_SIDE>());
- spaceNeededRight += to<zen::Int64>(i->getFileSize<LEFT_SIDE>());
+ spaceNeededRight -= to<Int64>(i->getFileSize<RIGHT_SIDE>());
+ spaceNeededRight += to<Int64>(i->getFileSize<LEFT_SIDE>());
break;
case SO_DO_NOTHING:
@@ -698,6 +739,10 @@ private:
case SO_UNRESOLVED_CONFLICT:
case SO_COPY_METADATA_TO_LEFT:
case SO_COPY_METADATA_TO_RIGHT:
+ case SO_MOVE_LEFT_SOURCE:
+ case SO_MOVE_RIGHT_SOURCE:
+ case SO_MOVE_LEFT_TARGET:
+ case SO_MOVE_RIGHT_TARGET:
break;
}
@@ -705,78 +750,20 @@ private:
//[...]
//recurse into sub-dirs
- std::for_each(hierObj.refSubDirs().begin(), hierObj.refSubDirs().end(), [&](const HierarchyObject& subDir) { this->processRecursively(subDir); });
+ std::for_each(hierObj.refSubDirs().begin(), hierObj.refSubDirs().end(), [&](const HierarchyObject& subDir) { this->recurse(subDir); });
//for (auto& subDir : hierObj.refSubDirs())
- // processRecursively(subDir);
+ // recurse(subDir);
}
const bool freeSpaceDelLeft_;
const bool freeSpaceDelRight_;
- zen::Int64 spaceNeededLeft;
- zen::Int64 spaceNeededRight;
+ Int64 spaceNeededLeft;
+ Int64 spaceNeededRight;
};
}
//----------------------------------------------------------------------------------------
-//test if current sync-line will result in deletion of files or
-//big file is overwritten by smaller one -> used to avoid disc space bottlenecks (at least if permanent deletion is active)
-inline
-bool diskSpaceIsReduced(const FileMapping& fileObj)
-{
- switch (fileObj.getSyncOperation()) //evaluate comparison result and sync direction
- {
- case SO_DELETE_LEFT:
- case SO_DELETE_RIGHT:
- return true;
-
- case SO_OVERWRITE_LEFT:
- return fileObj.getFileSize<LEFT_SIDE>() > fileObj.getFileSize<RIGHT_SIDE>();
-
- case SO_OVERWRITE_RIGHT:
- return fileObj.getFileSize<LEFT_SIDE>() < fileObj.getFileSize<RIGHT_SIDE>();
-
- case SO_CREATE_NEW_LEFT:
- case SO_CREATE_NEW_RIGHT:
- case SO_DO_NOTHING:
- case SO_EQUAL:
- case SO_UNRESOLVED_CONFLICT:
- case SO_COPY_METADATA_TO_LEFT:
- case SO_COPY_METADATA_TO_RIGHT:
- return false;
- }
- assert(false);
- return false; //dummy
-}
-
-
-inline
-bool diskSpaceIsReduced(const DirMapping& dirObj)
-{
- switch (dirObj.getSyncOperation()) //evaluate comparison result and sync direction
- {
- case SO_DELETE_LEFT:
- case SO_DELETE_RIGHT:
- return true;
-
- case SO_OVERWRITE_LEFT:
- case SO_OVERWRITE_RIGHT:
- assert(false);
- case SO_CREATE_NEW_LEFT:
- case SO_CREATE_NEW_RIGHT:
- case SO_DO_NOTHING:
- case SO_EQUAL:
- case SO_UNRESOLVED_CONFLICT:
- case SO_COPY_METADATA_TO_LEFT:
- case SO_COPY_METADATA_TO_RIGHT:
- return false;
- }
- assert(false);
- return false; //dummy
-}
-//---------------------------------------------------------------------------------------------------------------
-
-
class zen::SynchronizeFolderPair
{
public:
@@ -801,36 +788,58 @@ public:
txtOverwritingFile (replaceCpy(_("Overwriting file %x" ), L"%x", L"\"%x\"", false)),
txtOverwritingLink (replaceCpy(_("Overwriting symbolic link %x"), L"%x", L"\"%x\"", false)),
txtVerifying (replaceCpy(_("Verifying file %x" ), L"%x", L"\"%x\"", false)),
- txtWritingAttributes(replaceCpy(_("Updating attributes of %x" ), L"%x", L"\"%x\"", false)) {}
+ txtWritingAttributes(replaceCpy(_("Updating attributes of %x" ), L"%x", L"\"%x\"", false)),
+ txtMovingFile (replaceCpy(replaceCpy(_("Moving file %x to %y"), L"%x", L"\"%x\"", false), L"%y", L"\"%y\"", false)) {}
void startSync(BaseDirMapping& baseMap)
{
- //loop through all files twice; reason: first delete files (or overwrite big ones with smaller ones), then copy rest
- execute<FIRST_PASS >(baseMap);
- execute<SECOND_PASS>(baseMap);
+ runZeroPass(baseMap); //first process file moves
+ runPass<PASS_ONE>(baseMap); //delete files (or overwrite big ones with smaller ones)
+ runPass<PASS_TWO>(baseMap); //copy rest
}
private:
enum PassId
{
- FIRST_PASS, //delete files
- SECOND_PASS //create, modify
+ PASS_ONE, //delete files
+ PASS_TWO, //create, modify
+ PASS_NEVER //skip
};
+ static PassId getPass(const FileMapping& fileObj);
+ static PassId getPass(const SymLinkMapping& linkObj);
+ static PassId getPass(const DirMapping& dirObj);
+
+ template <SelectedSide side>
+ void prepare2StepMove(FileMapping& sourceObj, FileMapping& targetObj); //throw FileError
+ bool createParentDir(FileSystemObject& fsObj); //throw FileError
+ template <SelectedSide side>
+ void manageFileMove(FileMapping& sourceObj, FileMapping& targetObj); //throw FileError
+
+ void runZeroPass(HierarchyObject& hierObj);
template <PassId pass>
- void execute(HierarchyObject& hierObj);
+ void runPass(HierarchyObject& hierObj);
+
+ void synchronizeFile(FileMapping& fileObj) const;
+ template <SelectedSide side> void synchronizeFileInt(FileMapping& fileObj, SyncOperation syncOp) const;
+
+ void synchronizeLink(SymLinkMapping& linkObj) const;
+ template <SelectedSide sideTrg> void synchronizeLinkInt(SymLinkMapping& linkObj, SyncOperation syncOp) const;
+
+ void synchronizeFolder(DirMapping& dirObj) const;
+ template <SelectedSide sideTrg> void synchronizeFolderInt(DirMapping& dirObj, SyncOperation syncOp) const;
- void synchronizeFile (FileMapping& fileObj) const;
- void synchronizeLink (SymLinkMapping& linkObj) const;
- void synchronizeFolder(DirMapping& dirObj) const;
+ void reportInfo (const std::wstring& rawText, const Zstring& objname) const { procCallback_.reportInfo (replaceCpy(rawText, L"%x", utf8CvrtTo<std::wstring>(objname))); };
+ void reportStatus(const std::wstring& rawText, const Zstring& objname) const { procCallback_.reportStatus(replaceCpy(rawText, L"%x", utf8CvrtTo<std::wstring>(objname))); };
//more low level helper
- template <zen::SelectedSide side>
- void deleteSymlink(const SymLinkMapping& linkObj) const;
template <SelectedSide side, class DelTargetCommand>
- void copyFileUpdatingTo(const FileMapping& fileObj, const DelTargetCommand& cmd, FileDescriptor& sourceAttr) const;
+ void copyFileUpdatingTo(const FileMapping& fileObj, const DelTargetCommand& cmd, FileAttrib& newAttr) const;
void verifyFileCopy(const Zstring& source, const Zstring& target) const;
+ template <SelectedSide side>
+ const DeletionHandling& getDelHandling() const;
+
ProcessCallback& procCallback_;
#ifdef FFS_WIN
shadow::ShadowCopy* shadowCopyHandler_; //optional!
@@ -843,198 +852,556 @@ private:
const bool transactionalFileCopy;
//preload status texts
- const wxString txtCreatingFile;
- const wxString txtCreatingLink;
- const wxString txtCreatingFolder;
- const wxString txtOverwritingFile;
- const wxString txtOverwritingLink;
- const wxString txtVerifying;
- const wxString txtWritingAttributes;
+ const std::wstring txtCreatingFile;
+ const std::wstring txtCreatingLink;
+ const std::wstring txtCreatingFolder;
+ const std::wstring txtOverwritingFile;
+ const std::wstring txtOverwritingLink;
+ const std::wstring txtVerifying;
+ const std::wstring txtWritingAttributes;
+ const std::wstring txtMovingFile;
};
+//---------------------------------------------------------------------------------------------------------------
+namespace zen
+{
+template <> inline
+const DeletionHandling& SynchronizeFolderPair::getDelHandling<LEFT_SIDE>() const { return delHandlingLeft_; }
+
+template <> inline
+const DeletionHandling& SynchronizeFolderPair::getDelHandling<RIGHT_SIDE>() const { return delHandlingRight_; }
+}
+
+
+/*
+__________________________
+|Move algorithm, 0th pass|
+--------------------------
+1. loop over hierarchy and find "move source"
+
+2. check whether parent directory of "move source" is going to be deleted or location of "move source" may lead to name clash with other dir/symlink
+ -> no: delay move until 2nd pass
+
+3. create move target's parent directory recursively + execute move
+ do we have name clash?
+ -> prepare a 2-step move operation: 1. move source to root and update "move target" accordingly 2. delay move until 2nd pass
+
+4. If any of the operations above did not succeed (even after retry), update statistics and revert to "copy + delete"
+ Note: first pass may delete "move source"!!!
+
+__________________
+|killer-scenarios|
+------------------
+propagate the following move sequences:
+I) a -> a/a caveat sync'ing parent directory first leads to circular dependency!
+
+II) a/a -> a caveat: fixing name clash will remove source!
+
+III) c -> d caveat: move-sequence needs to be processed in correct order!
+ b -> c/b
+ a -> b/a
+*/
+
+namespace
+{
+template <class Mapping> inline
+bool haveNameClash(const Zstring& shortname, Mapping& m)
+{
+ return std::find_if(m.begin(), m.end(),
+ [&](const typename Mapping::value_type& obj) { return EqualFilename()(obj.getObjShortName(), shortname); }) != m.end();
+}
+
+
+Zstring findUniqueTempName(const Zstring& filename)
+{
+ Zstring output = filename + zen::TEMP_FILE_ENDING;
+
+ //ensure uniqueness
+ for (int i = 1; somethingExists(output); ++i)
+ output = filename + Zchar('_') + toString<Zstring>(i) + zen::TEMP_FILE_ENDING;
+
+ return output;
+}
+}
+
+
+template <SelectedSide side>
+void SynchronizeFolderPair::prepare2StepMove(FileMapping& sourceObj,
+ FileMapping& targetObj) //throw FileError
+{
+ const Zstring& source = sourceObj.getFullName<side>();
+ const Zstring& tmpTarget = findUniqueTempName(sourceObj.getBaseDirPf<side>() + sourceObj.getShortName<side>());
+ //this could still lead to a name-clash in obscure cases, if some file ex. on the other side with
+ //the very same (.ffs_tmp) name and is copied before the second step of the move is executed
+ //good news: even in this pathologic case, this may only prevent the copy of the other file, but not the move
+
+ reportInfo(replaceCpy(txtMovingFile, L"%y", utf8CvrtTo<std::wstring>(tmpTarget)), source);
+
+ renameFile(source, tmpTarget); //throw FileError;
+
+ //update file hierarchy
+ const FileDescriptor descrSource(sourceObj.getLastWriteTime<side>(),
+ sourceObj.getFileSize <side>(),
+ sourceObj.getFileId <side>());
+
+ sourceObj.removeObject<side>();
+
+ FileMapping& tempFile = sourceObj.root().addSubFile<side>(afterLast(tmpTarget, FILE_NAME_SEPARATOR), descrSource);
+
+ //prepare move in second pass
+ tempFile.setSyncDir(side == LEFT_SIDE ? SYNC_DIR_LEFT : SYNC_DIR_RIGHT);
+
+ targetObj.setMoveRef(tempFile .getId());
+ tempFile .setMoveRef(targetObj.getId());
+
+ //NO statistics update!
+ procCallback_.requestUiRefresh(); //may throw
+}
+
+
+bool SynchronizeFolderPair::createParentDir(FileSystemObject& fsObj) //throw FileError, "false" on name clash
+{
+ if (DirMapping* parentDir = dynamic_cast<DirMapping*>(&fsObj.parent()))
+ {
+ if (!createParentDir(*parentDir))
+ return false;
+
+ //detect (and try to resolve) file type conflicts: 1. symlinks 2. files
+ const Zstring& shortname = parentDir->getObjShortName();
+ if (haveNameClash(shortname, parentDir->parent().refSubLinks()) ||
+ haveNameClash(shortname, parentDir->parent().refSubFiles()))
+ return false;
+
+ //in this context "parentDir" cannot be scheduled for deletion since it contains a "move target"!
+ //note: if parentDir were deleted, we'd end up destroying "fsObj"!
+ assert(parentDir->getSyncOperation() != SO_DELETE_LEFT &&
+ parentDir->getSyncOperation() != SO_DELETE_RIGHT);
+
+ synchronizeFolder(*parentDir); //throw FileError
+ }
+ return true;
+}
+
+
+template <SelectedSide side>
+void SynchronizeFolderPair::manageFileMove(FileMapping& sourceObj,
+ FileMapping& targetObj) //throw FileError
+{
+ assert((sourceObj.getSyncOperation() == SO_MOVE_LEFT_SOURCE && targetObj.getSyncOperation() == SO_MOVE_LEFT_TARGET && side == LEFT_SIDE) ||
+ (sourceObj.getSyncOperation() == SO_MOVE_RIGHT_SOURCE && targetObj.getSyncOperation() == SO_MOVE_RIGHT_TARGET && side == RIGHT_SIDE));
+
+ const bool sourceWillBeDeleted = [&]() -> bool
+ {
+ if (DirMapping* parentDir = dynamic_cast<DirMapping*>(&sourceObj.parent()))
+ {
+ switch (parentDir->getSyncOperation()) //evaluate comparison result and sync direction
+ {
+ case SO_DELETE_LEFT:
+ case SO_DELETE_RIGHT:
+ return true; //we need to do something about it
+ case SO_MOVE_LEFT_SOURCE:
+ case SO_MOVE_RIGHT_SOURCE:
+ case SO_MOVE_LEFT_TARGET:
+ case SO_MOVE_RIGHT_TARGET:
+ case SO_OVERWRITE_LEFT:
+ case SO_OVERWRITE_RIGHT:
+ case SO_CREATE_NEW_LEFT:
+ case SO_CREATE_NEW_RIGHT:
+ case SO_DO_NOTHING:
+ case SO_EQUAL:
+ case SO_UNRESOLVED_CONFLICT:
+ case SO_COPY_METADATA_TO_LEFT:
+ case SO_COPY_METADATA_TO_RIGHT:
+ break;
+ }
+ }
+ return false;
+ }();
+
+ auto haveNameClash = [](const FileMapping& fileObj)
+ {
+ return ::haveNameClash(fileObj.getObjShortName(), fileObj.parent().refSubLinks()) ||
+ ::haveNameClash(fileObj.getObjShortName(), fileObj.parent().refSubDirs());
+ };
+
+ if (sourceWillBeDeleted || haveNameClash(sourceObj))
+ {
+ //prepare for move now: - revert to 2-step move on name clashes
+ if (haveNameClash(targetObj) ||
+ !createParentDir(targetObj)) //throw FileError
+ return prepare2StepMove<side>(sourceObj, targetObj); //throw FileError
+
+ //finally start move! this should work now:
+ synchronizeFile(sourceObj); //throw FileError
+ }
+ //else: sourceObj will not be deleted, and is not standing in the way => delay to second pass
+ //note: this case may include "move sources" from two-step sub-routine!
+}
+
+
+void SynchronizeFolderPair::runZeroPass(HierarchyObject& hierObj)
+{
+ //search for file move-operations
+
+ for (auto iter = hierObj.refSubFiles().begin(); iter != hierObj.refSubFiles().end(); ++iter) //VS 2010 crashes if we use for_each + lambda here...
+ {
+ FileMapping& fileObj = *iter;
+
+ const SyncOperation syncOp = fileObj.getSyncOperation();
+ switch (syncOp) //evaluate comparison result and sync direction
+ {
+ case SO_MOVE_LEFT_SOURCE:
+ case SO_MOVE_RIGHT_SOURCE:
+ {
+ FileMapping* sourceObj = &fileObj;
+ if (FileMapping* targetObj = dynamic_cast<FileMapping*>(FileSystemObject::retrieve(fileObj.getMoveRef())))
+ {
+ if (!tryReportingError(procCallback_, [&] { return syncOp == SO_MOVE_LEFT_SOURCE ? this->manageFileMove<LEFT_SIDE>(*sourceObj, *targetObj) : this->manageFileMove<RIGHT_SIDE>(*sourceObj, *targetObj); }))
+ {
+ //move operation has failed! We cannot allow to continue and have move source's parent directory deleted, messing up statistics!
+ // => revert to ordinary "copy + delete"
+
+ auto getStat = [&]() -> std::pair<int, Int64>
+ {
+ SyncStatistics statSrc(*sourceObj);
+ SyncStatistics statTrg(*targetObj);
+
+ return std::make_pair(getCUD(statSrc) + getCUD(statTrg),
+ to<Int64>(statSrc.getDataToProcess() + statTrg.getDataToProcess()));
+ };
+
+ const auto statBefore = getStat();
+ sourceObj->setMoveRef(NULL);
+ targetObj->setMoveRef(NULL);
+ const auto statAfter = getStat();
+ //fix statistics to match "copy + delete"
+ procCallback_.updateProcessedData(statBefore.first - statAfter.first, statBefore.second - statAfter.second);
+ }
+ }
+ }
+ break;
+ case SO_MOVE_LEFT_TARGET: //it's enough to try each move-pair *once*
+ case SO_MOVE_RIGHT_TARGET: //
+ case SO_DELETE_LEFT:
+ case SO_DELETE_RIGHT:
+ case SO_OVERWRITE_LEFT:
+ case SO_OVERWRITE_RIGHT:
+ case SO_CREATE_NEW_LEFT:
+ case SO_CREATE_NEW_RIGHT:
+ case SO_DO_NOTHING:
+ case SO_EQUAL:
+ case SO_UNRESOLVED_CONFLICT:
+ case SO_COPY_METADATA_TO_LEFT:
+ case SO_COPY_METADATA_TO_RIGHT:
+ break;
+ }
+ }
+
+ std::for_each(hierObj.refSubDirs().begin(), hierObj.refSubDirs().end(),
+ [&](DirMapping& dirObj) { this->runZeroPass(dirObj); /*recurse */ });
+}
+//---------------------------------------------------------------------------------------------------------------
+
+
+//1st, 2nd pass requirements:
+// - avoid disk space shortage: 1. delete files, 2. overwrite big with small files first
+// - support change in type: overwrite file by directory, symlink by file, ect.
+
+inline
+SynchronizeFolderPair::PassId SynchronizeFolderPair::getPass(const FileMapping& fileObj)
+{
+ switch (fileObj.getSyncOperation()) //evaluate comparison result and sync direction
+ {
+ case SO_DELETE_LEFT:
+ case SO_DELETE_RIGHT:
+ return PASS_ONE;
+
+ case SO_OVERWRITE_LEFT:
+ return fileObj.getFileSize<LEFT_SIDE>() > fileObj.getFileSize<RIGHT_SIDE>() ? PASS_ONE : PASS_TWO;
+
+ case SO_OVERWRITE_RIGHT:
+ return fileObj.getFileSize<LEFT_SIDE>() < fileObj.getFileSize<RIGHT_SIDE>() ? PASS_ONE : PASS_TWO;
+
+ case SO_MOVE_LEFT_SOURCE: //
+ case SO_MOVE_RIGHT_SOURCE: // [!]
+ return PASS_NEVER;
+ case SO_MOVE_LEFT_TARGET: //
+ case SO_MOVE_RIGHT_TARGET: //to be processed in second pass, after "move target" parent directory was created!
+ return PASS_TWO;
+
+ case SO_CREATE_NEW_LEFT:
+ case SO_CREATE_NEW_RIGHT:
+ case SO_DO_NOTHING:
+ case SO_EQUAL:
+ case SO_UNRESOLVED_CONFLICT:
+ case SO_COPY_METADATA_TO_LEFT:
+ case SO_COPY_METADATA_TO_RIGHT:
+ return PASS_TWO;
+ }
+ assert(false);
+ return PASS_TWO; //dummy
+}
+
+
+inline
+SynchronizeFolderPair::PassId SynchronizeFolderPair::getPass(const SymLinkMapping& linkObj)
+{
+ switch (linkObj.getSyncOperation()) //evaluate comparison result and sync direction
+ {
+ case SO_DELETE_LEFT:
+ case SO_DELETE_RIGHT:
+ return PASS_ONE; //make sure to delete symlinks in first pass, and equally named file or dir in second pass: usecase "overwrite symlink with regular file"!
+
+ case SO_MOVE_LEFT_SOURCE:
+ case SO_MOVE_RIGHT_SOURCE:
+ case SO_MOVE_LEFT_TARGET:
+ case SO_MOVE_RIGHT_TARGET:
+ assert(false);
+ case SO_OVERWRITE_LEFT:
+ case SO_OVERWRITE_RIGHT:
+ case SO_CREATE_NEW_LEFT:
+ case SO_CREATE_NEW_RIGHT:
+ case SO_DO_NOTHING:
+ case SO_EQUAL:
+ case SO_UNRESOLVED_CONFLICT:
+ case SO_COPY_METADATA_TO_LEFT:
+ case SO_COPY_METADATA_TO_RIGHT:
+ return PASS_TWO;
+ }
+ assert(false);
+ return PASS_TWO; //dummy
+}
+
+
+inline
+SynchronizeFolderPair::PassId SynchronizeFolderPair::getPass(const DirMapping& dirObj)
+{
+ switch (dirObj.getSyncOperation()) //evaluate comparison result and sync direction
+ {
+ case SO_DELETE_LEFT:
+ case SO_DELETE_RIGHT:
+ return PASS_ONE;
+
+ case SO_OVERWRITE_LEFT:
+ case SO_OVERWRITE_RIGHT:
+ case SO_MOVE_LEFT_SOURCE:
+ case SO_MOVE_RIGHT_SOURCE:
+ case SO_MOVE_LEFT_TARGET:
+ case SO_MOVE_RIGHT_TARGET:
+ assert(false);
+ case SO_CREATE_NEW_LEFT:
+ case SO_CREATE_NEW_RIGHT:
+ case SO_DO_NOTHING:
+ case SO_EQUAL:
+ case SO_UNRESOLVED_CONFLICT:
+ case SO_COPY_METADATA_TO_LEFT:
+ case SO_COPY_METADATA_TO_RIGHT:
+ return PASS_TWO;
+ }
+ assert(false);
+ return PASS_TWO; //dummy
+}
template <SynchronizeFolderPair::PassId pass>
-void SynchronizeFolderPair::execute(HierarchyObject& hierObj)
+void SynchronizeFolderPair::runPass(HierarchyObject& hierObj)
{
//synchronize files:
std::for_each(hierObj.refSubFiles().begin(), hierObj.refSubFiles().end(),
[&](FileMapping& fileObj)
{
- const bool letsDoThis = (pass == FIRST_PASS) == diskSpaceIsReduced(fileObj); //to be deleted files on first pass, rest on second!
- if (letsDoThis)
- tryReportingError(procCallback_, [&]() { synchronizeFile(fileObj); });
+ if (pass == getPass(fileObj))
+ tryReportingError(procCallback_, [&] { synchronizeFile(fileObj); });
});
- //synchronize symbolic links: (process in second step only)
- if (pass == SECOND_PASS)
- std::for_each(hierObj.refSubLinks().begin(), hierObj.refSubLinks().end(),
- [&](SymLinkMapping& linkObj) { tryReportingError(procCallback_, [&]() { synchronizeLink(linkObj); }); });
+ //synchronize symbolic links:
+ std::for_each(hierObj.refSubLinks().begin(), hierObj.refSubLinks().end(),
+ [&](SymLinkMapping& linkObj)
+ {
+ if (pass == getPass(linkObj))
+ tryReportingError(procCallback_, [&] { synchronizeLink(linkObj); });
+ });
//synchronize folders:
std::for_each(hierObj.refSubDirs().begin(), hierObj.refSubDirs().end(),
[&](DirMapping& dirObj)
{
- const bool letsDoThis = (pass == FIRST_PASS) == diskSpaceIsReduced(dirObj); //to be deleted dirs on first pass, rest on second!
- if (letsDoThis) //if we created all folders on first pass it would look strange for initial mirror sync when all folders are created at once
- tryReportingError(procCallback_, [&]() { synchronizeFolder(dirObj); });
+ if (pass == getPass(dirObj))
+ tryReportingError(procCallback_, [&] { synchronizeFolder(dirObj); });
- //recursion!
- this->execute<pass>(dirObj);
+ this->runPass<pass>(dirObj); //recurse
});
}
+//---------------------------------------------------------------------------------------------------------------
-void SynchronizeFolderPair::synchronizeFile(FileMapping& fileObj) const
+namespace
{
- wxString logText;
- Zstring target;
-
- switch (fileObj.getSyncOperation()) //evaluate comparison result and sync direction
+inline
+bool getTargetDir(SyncOperation syncOp, SelectedSide* side)
+{
+ switch (syncOp)
{
case SO_CREATE_NEW_LEFT:
- target = fileObj.getBaseDirPf<LEFT_SIDE>() + fileObj.getRelativeName<RIGHT_SIDE>(); //can't use "getFullName" as target is not yet existing
+ case SO_DELETE_LEFT:
+ case SO_OVERWRITE_LEFT:
+ case SO_COPY_METADATA_TO_LEFT:
+ case SO_MOVE_LEFT_SOURCE:
+ case SO_MOVE_LEFT_TARGET:
+ *side = LEFT_SIDE;
+ return true;
- logText = txtCreatingFile;
- replace(logText, L"%x", utf8CvrtTo<wxString>(target));
- procCallback_.reportInfo(logText);
+ case SO_CREATE_NEW_RIGHT:
+ case SO_DELETE_RIGHT:
+ case SO_OVERWRITE_RIGHT:
+ case SO_COPY_METADATA_TO_RIGHT:
+ case SO_MOVE_RIGHT_SOURCE:
+ case SO_MOVE_RIGHT_TARGET:
+ *side = RIGHT_SIDE;
+ return true;
- try
- {
- FileDescriptor sourceAttr;
- copyFileUpdatingTo<LEFT_SIDE>(fileObj,
- []() {}, //no target to delete
- sourceAttr);
+ case SO_DO_NOTHING:
+ case SO_EQUAL:
+ case SO_UNRESOLVED_CONFLICT:
+ break; //nothing to do
+ }
+ return false;
+}
+}
- fileObj.copyTo<LEFT_SIDE>(&sourceAttr); //update FileMapping
- }
- catch (FileError&)
- {
- if (fileExists(fileObj.getFullName<RIGHT_SIDE>()))
- throw;
- //source deleted meanwhile...
- procCallback_.updateProcessedData(0, to<zen::Int64>(fileObj.getFileSize<RIGHT_SIDE>()));
- fileObj.removeObject<RIGHT_SIDE>();
- }
- break;
+inline
+void SynchronizeFolderPair::synchronizeFile(FileMapping& fileObj) const
+{
+ const SyncOperation syncOp = fileObj.getSyncOperation();
+
+ SelectedSide sideTrg = LEFT_SIDE;
+
+ if (getTargetDir(syncOp, &sideTrg))
+ {
+ if (sideTrg == LEFT_SIDE)
+ synchronizeFileInt<LEFT_SIDE>(fileObj, syncOp);
+ else
+ synchronizeFileInt<RIGHT_SIDE>(fileObj, syncOp);
+ }
+}
+
+
+template <SelectedSide sideTrg>
+void SynchronizeFolderPair::synchronizeFileInt(FileMapping& fileObj, SyncOperation syncOp) const
+{
+ static const SelectedSide sideSrc = OtherSide<sideTrg>::result;
+
+ switch (syncOp)
+ {
+ case SO_CREATE_NEW_LEFT:
case SO_CREATE_NEW_RIGHT:
- target = fileObj.getBaseDirPf<RIGHT_SIDE>() + fileObj.getRelativeName<LEFT_SIDE>();
+ {
+ const Zstring& target = fileObj.getBaseDirPf<sideTrg>() + fileObj.getRelativeName<sideSrc>(); //can't use "getFullName" as target is not yet existing
- logText = txtCreatingFile;
- replace(logText, L"%x", utf8CvrtTo<wxString>(target));
- procCallback_.reportInfo(logText);
+ reportInfo(txtCreatingFile, target);
try
{
- FileDescriptor sourceAttr;
- copyFileUpdatingTo<RIGHT_SIDE>(fileObj,
- []() {}, //no target to delete
- sourceAttr);
+ FileAttrib newAttr;
+ copyFileUpdatingTo<sideTrg>(fileObj, [] {}, /*no target to delete*/ newAttr);
- fileObj.copyTo<RIGHT_SIDE>(&sourceAttr); //update FileMapping
+ const FileDescriptor descrSource(newAttr.modificationTime, newAttr.fileSize, newAttr.sourceFileId);
+ const FileDescriptor descrTarget(newAttr.modificationTime, newAttr.fileSize, newAttr.targetFileId);
+ fileObj.syncTo<sideTrg>(descrTarget, &descrSource); //update FileMapping
}
catch (FileError&)
{
- if (fileExists(fileObj.getFullName<LEFT_SIDE>()))
+ if (fileExists(fileObj.getFullName<sideSrc>()))
throw;
//source deleted meanwhile...
- procCallback_.updateProcessedData(0, to<zen::Int64>(fileObj.getFileSize<LEFT_SIDE>()));
- fileObj.removeObject<LEFT_SIDE>();
+ procCallback_.updateProcessedData(0, to<zen::Int64>(fileObj.getFileSize<sideSrc>()));
+ fileObj.removeObject<sideSrc>();
}
- break;
+ }
+ break;
case SO_DELETE_LEFT:
- logText = replaceCpy(delHandlingLeft_.getTxtRemovingFile(), L"%x", utf8CvrtTo<wxString>(fileObj.getFullName<LEFT_SIDE>()));
- procCallback_.reportInfo(logText);
+ case SO_DELETE_RIGHT:
+ reportInfo(getDelHandling<sideTrg>().getTxtRemovingFile(), fileObj.getFullName<sideTrg>());
- delHandlingLeft_.removeFile(fileObj.getObjRelativeName()); //throw FileError
- fileObj.removeObject<LEFT_SIDE>(); //update FileMapping
+ getDelHandling<sideTrg>().removeFile(fileObj.getObjRelativeName()); //throw FileError
+ fileObj.removeObject<sideTrg>(); //update FileMapping
break;
- case SO_DELETE_RIGHT:
- logText = replaceCpy(delHandlingRight_.getTxtRemovingFile(), L"%x", utf8CvrtTo<wxString>(fileObj.getFullName<RIGHT_SIDE>()));
- procCallback_.reportInfo(logText);
+ case SO_MOVE_LEFT_SOURCE:
+ case SO_MOVE_LEFT_TARGET:
+ case SO_MOVE_RIGHT_SOURCE:
+ case SO_MOVE_RIGHT_TARGET:
+ if (FileMapping* targetObj = dynamic_cast<FileMapping*>(FileSystemObject::retrieve(fileObj.getMoveRef())))
+ {
+ FileMapping* sourceObj = &fileObj;
- delHandlingRight_.removeFile(fileObj.getObjRelativeName()); //throw FileError
- fileObj.removeObject<RIGHT_SIDE>(); //update FileMapping
- break;
+ if (syncOp != SO_MOVE_LEFT_SOURCE && syncOp != SO_MOVE_RIGHT_SOURCE)
+ std::swap(sourceObj, targetObj);
- case SO_OVERWRITE_LEFT:
- {
- target = fileObj.getBaseDirPf<LEFT_SIDE>() + fileObj.getRelativeName<RIGHT_SIDE>(); //respect differences in case of source object
+ assert((sourceObj->getSyncOperation() == SO_MOVE_LEFT_SOURCE && targetObj->getSyncOperation() == SO_MOVE_LEFT_TARGET && sideTrg == LEFT_SIDE) ||
+ (sourceObj->getSyncOperation() == SO_MOVE_RIGHT_SOURCE && targetObj->getSyncOperation() == SO_MOVE_RIGHT_TARGET && sideTrg == RIGHT_SIDE));
- logText = txtOverwritingFile;
- replace(logText, L"%x", utf8CvrtTo<wxString>(target));
- procCallback_.reportInfo(logText);
+ const Zstring& source = sourceObj->getFullName<sideTrg>();
+ const Zstring& target = targetObj->getBaseDirPf<sideTrg>() + targetObj->getRelativeName<sideSrc>();
- FileDescriptor sourceAttr;
- copyFileUpdatingTo<LEFT_SIDE>(fileObj,
- [&]() //delete target at appropriate time
- {
- procCallback_.reportStatus(replaceCpy(delHandlingLeft_.getTxtRemovingFile(), L"%x", utf8CvrtTo<wxString>(fileObj.getFullName<LEFT_SIDE>())));
+ reportInfo(replaceCpy(txtMovingFile, L"%y", utf8CvrtTo<std::wstring>(target)), source);
- delHandlingLeft_.removeFile(fileObj.getObjRelativeName()); //throw FileError
- fileObj.removeObject<LEFT_SIDE>(); //remove file from FileMapping, to keep in sync (if subsequent copying fails!!)
+ renameFile(source, target); //throw FileError;
- procCallback_.reportStatus(logText); //restore status text copy file
- }, sourceAttr);
+ const FileDescriptor descrTarget(sourceObj->getLastWriteTime<sideTrg>(),
+ sourceObj->getFileSize <sideTrg>(),
+ sourceObj->getFileId <sideTrg>());
- fileObj.copyTo<LEFT_SIDE>(&sourceAttr); //update FileMapping
- }
- break;
+ sourceObj->removeObject<sideTrg>(); //
+ targetObj->syncTo<sideTrg>(descrTarget); //update FileMapping
+ }
+ break;
+ case SO_OVERWRITE_LEFT:
case SO_OVERWRITE_RIGHT:
{
- target = fileObj.getBaseDirPf<RIGHT_SIDE>() + fileObj.getRelativeName<LEFT_SIDE>(); //respect differences in case of source object
+ const Zstring& target = fileObj.getBaseDirPf<sideTrg>() + fileObj.getRelativeName<sideSrc>(); //respect differences in case of source object
- logText = txtOverwritingFile;
- replace(logText, L"%x", utf8CvrtTo<wxString>(target));
- procCallback_.reportInfo(logText);
+ reportInfo(txtOverwritingFile, target);
- FileDescriptor sourceAttr;
- copyFileUpdatingTo<RIGHT_SIDE>(fileObj,
- [&]() //delete target at appropriate time
+ FileAttrib newAttr;
+ copyFileUpdatingTo<sideTrg>(fileObj,
+ [&] //delete target at appropriate time
{
- procCallback_.reportStatus(replaceCpy(delHandlingRight_.getTxtRemovingFile(), L"%x", utf8CvrtTo<wxString>(fileObj.getFullName<RIGHT_SIDE>())));
+ reportStatus(this->getDelHandling<sideTrg>().getTxtRemovingFile(), fileObj.getFullName<sideTrg>());
- delHandlingRight_.removeFile(fileObj.getObjRelativeName()); //throw FileError
- fileObj.removeObject<RIGHT_SIDE>(); //remove file from FileMapping, to keep in sync (if subsequent copying fails!!)
+ this->getDelHandling<sideTrg>().removeFile(fileObj.getObjRelativeName()); //throw FileError
+ fileObj.removeObject<sideTrg>(); //remove file from FileMapping, to keep in sync (if subsequent copying fails!!)
- procCallback_.reportStatus(logText); //restore status text copy file
- }, sourceAttr);
+ reportStatus(txtOverwritingFile, target); //restore status text copy file
+ }, newAttr);
- fileObj.copyTo<RIGHT_SIDE>(&sourceAttr); //update FileMapping
+ const FileDescriptor descrSource(newAttr.modificationTime, newAttr.fileSize, newAttr.sourceFileId);
+ const FileDescriptor descrTarget(newAttr.modificationTime, newAttr.fileSize, newAttr.targetFileId);
+ fileObj.syncTo<sideTrg>(descrTarget, &descrSource); //update FileMapping
}
break;
case SO_COPY_METADATA_TO_LEFT:
- logText = replaceCpy(txtWritingAttributes, L"%x", utf8CvrtTo<wxString>(fileObj.getFullName<LEFT_SIDE>()));
- procCallback_.reportInfo(logText);
-
- if (fileObj.getShortName<LEFT_SIDE>() != fileObj.getShortName<RIGHT_SIDE>()) //adapt difference in case (windows only)
- renameFile(fileObj.getFullName<LEFT_SIDE>(),
- beforeLast(fileObj.getFullName<LEFT_SIDE>(), FILE_NAME_SEPARATOR) + FILE_NAME_SEPARATOR + fileObj.getShortName<RIGHT_SIDE>()); //throw FileError;
-
- if (!sameFileTime(fileObj.getLastWriteTime<LEFT_SIDE>(), fileObj.getLastWriteTime<RIGHT_SIDE>(), 2)) //respect 2 second FAT/FAT32 precision
- setFileTime(fileObj.getFullName<LEFT_SIDE>(), fileObj.getLastWriteTime<RIGHT_SIDE>(), SYMLINK_FOLLOW); //throw FileError
- //do NOT read *current* source file time, but use buffered value which corresponds to time of comparison!
-
- fileObj.copyTo<LEFT_SIDE>(NULL); //-> both sides *should* be completely equal now...
- break;
-
case SO_COPY_METADATA_TO_RIGHT:
- logText = replaceCpy(txtWritingAttributes, L"%x", utf8CvrtTo<wxString>(fileObj.getFullName<RIGHT_SIDE>()));
- procCallback_.reportInfo(logText);
+ {
+ reportInfo(txtWritingAttributes, fileObj.getFullName<sideTrg>());
- if (fileObj.getShortName<LEFT_SIDE>() != fileObj.getShortName<RIGHT_SIDE>()) //adapt difference in case (windows only)
- renameFile(fileObj.getFullName<RIGHT_SIDE>(),
- beforeLast(fileObj.getFullName<RIGHT_SIDE>(), FILE_NAME_SEPARATOR) + FILE_NAME_SEPARATOR + fileObj.getShortName<LEFT_SIDE>()); //throw FileError;
+ if (fileObj.getShortName<sideTrg>() != fileObj.getShortName<sideSrc>()) //adapt difference in case (windows only)
+ renameFile(fileObj.getFullName<sideTrg>(),
+ beforeLast(fileObj.getFullName<sideTrg>(), FILE_NAME_SEPARATOR) + FILE_NAME_SEPARATOR + fileObj.getShortName<sideSrc>()); //throw FileError;
- if (!sameFileTime(fileObj.getLastWriteTime<LEFT_SIDE>(), fileObj.getLastWriteTime<RIGHT_SIDE>(), 2)) //respect 2 second FAT/FAT32 precision
- setFileTime(fileObj.getFullName<RIGHT_SIDE>(), fileObj.getLastWriteTime<LEFT_SIDE>(), SYMLINK_FOLLOW); //throw FileError
+ if (!sameFileTime(fileObj.getLastWriteTime<sideTrg>(), fileObj.getLastWriteTime<sideSrc>(), 2)) //respect 2 second FAT/FAT32 precision
+ setFileTime(fileObj.getFullName<sideTrg>(), fileObj.getLastWriteTime<sideSrc>(), SYMLINK_FOLLOW); //throw FileError
+ //do NOT read *current* source file time, but use buffered value which corresponds to time of comparison!
- fileObj.copyTo<RIGHT_SIDE>(NULL); //-> both sides *should* be completely equal now...
- break;
+ const FileDescriptor descrTarget(fileObj.getLastWriteTime<sideSrc>(),
+ fileObj.getFileSize <sideTrg >(),
+ fileObj.getFileId <sideTrg >());
+ fileObj.syncTo<sideTrg>(descrTarget); //-> both sides *should* be completely equal now...
+ }
+ break;
case SO_DO_NOTHING:
case SO_EQUAL:
@@ -1049,137 +1416,112 @@ void SynchronizeFolderPair::synchronizeFile(FileMapping& fileObj) const
}
+inline
void SynchronizeFolderPair::synchronizeLink(SymLinkMapping& linkObj) const
{
- wxString logText;
- Zstring target;
+ const SyncOperation syncOp = linkObj.getSyncOperation();
- switch (linkObj.getSyncOperation()) //evaluate comparison result and sync direction
+ SelectedSide sideTrg = LEFT_SIDE;
+
+ if (getTargetDir(syncOp, &sideTrg))
{
- case SO_CREATE_NEW_LEFT:
- target = linkObj.getBaseDirPf<LEFT_SIDE>() + linkObj.getRelativeName<RIGHT_SIDE>();
+ if (sideTrg == LEFT_SIDE)
+ synchronizeLinkInt<LEFT_SIDE>(linkObj, syncOp);
+ else
+ synchronizeLinkInt<RIGHT_SIDE>(linkObj, syncOp);
+ }
+}
- logText = txtCreatingLink;
- replace(logText, L"%x", utf8CvrtTo<wxString>(target));
- procCallback_.reportInfo(logText);
- try
- {
- zen::copySymlink(linkObj.getFullName<RIGHT_SIDE>(), target, copyFilePermissions); //throw FileError
+template <SelectedSide sideTrg>
+void SynchronizeFolderPair::synchronizeLinkInt(SymLinkMapping& linkObj, SyncOperation syncOp) const
+{
+ static const SelectedSide sideSrc = OtherSide<sideTrg>::result;
- linkObj.copyTo<LEFT_SIDE>(); //update SymLinkMapping
- }
- catch (FileError&)
- {
- if (fileExists(linkObj.getFullName<RIGHT_SIDE>()))
- throw;
- //source deleted meanwhile...
- linkObj.removeObject<RIGHT_SIDE>();
- }
- break;
+ auto deleteSymlink = [&]
+ {
+ switch (linkObj.getLinkType<sideTrg>())
+ {
+ case LinkDescriptor::TYPE_DIR:
+ this->getDelHandling<sideTrg>().removeFolder(linkObj.getObjRelativeName()); //throw FileError
+ break;
+
+ case LinkDescriptor::TYPE_FILE: //Windows: true file symlink; Linux: file-link or broken link
+ this->getDelHandling<sideTrg>().removeFile(linkObj.getObjRelativeName()); //throw FileError
+ break;
+ }
+ };
+ switch (syncOp)
+ {
+ case SO_CREATE_NEW_LEFT:
case SO_CREATE_NEW_RIGHT:
- target = linkObj.getBaseDirPf<RIGHT_SIDE>() + linkObj.getRelativeName<LEFT_SIDE>();
+ {
+ const Zstring& target = linkObj.getBaseDirPf<sideTrg>() + linkObj.getRelativeName<sideSrc>();
- logText = txtCreatingLink;
- replace(logText, L"%x", utf8CvrtTo<wxString>(target));
- procCallback_.reportInfo(logText);
+ reportInfo(txtCreatingLink, target);
try
{
- zen::copySymlink(linkObj.getFullName<LEFT_SIDE>(), target, copyFilePermissions); //throw FileError
+ zen::copySymlink(linkObj.getFullName<sideSrc>(), target, copyFilePermissions); //throw FileError
- linkObj.copyTo<RIGHT_SIDE>(); //update SymLinkMapping
+ linkObj.copyTo<sideTrg>(); //update SymLinkMapping
}
catch (FileError&)
{
- if (fileExists(linkObj.getFullName<LEFT_SIDE>()))
+ if (fileExists(linkObj.getFullName<sideSrc>()))
throw;
//source deleted meanwhile...
- linkObj.removeObject<LEFT_SIDE>();
+ linkObj.removeObject<sideSrc>();
}
- break;
+ }
+ break;
case SO_DELETE_LEFT:
- logText = replaceCpy(delHandlingLeft_.getTxtRemovingSymLink(), L"%x", utf8CvrtTo<wxString>(linkObj.getFullName<LEFT_SIDE>()));
- procCallback_.reportInfo(logText);
-
- deleteSymlink<LEFT_SIDE>(linkObj); //throw FileError
-
- linkObj.removeObject<LEFT_SIDE>(); //update SymLinkMapping
- break;
-
case SO_DELETE_RIGHT:
- logText = replaceCpy(delHandlingRight_.getTxtRemovingSymLink(), L"%x", utf8CvrtTo<wxString>(linkObj.getFullName<RIGHT_SIDE>()));
- procCallback_.reportInfo(logText);
+ reportInfo(getDelHandling<sideTrg>().getTxtRemovingSymLink(), linkObj.getFullName<sideTrg>());
- deleteSymlink<RIGHT_SIDE>(linkObj); //throw FileError
+ deleteSymlink(); //throw FileError
- linkObj.removeObject<RIGHT_SIDE>(); //update SymLinkMapping
+ linkObj.removeObject<sideTrg>(); //update SymLinkMapping
break;
case SO_OVERWRITE_LEFT:
- target = linkObj.getBaseDirPf<LEFT_SIDE>() + linkObj.getRelativeName<RIGHT_SIDE>(); //respect differences in case of source object
-
- logText = txtOverwritingLink;
- replace(logText, L"%x", utf8CvrtTo<wxString>(target));
- procCallback_.reportInfo(logText);
-
- procCallback_.reportStatus(replaceCpy(delHandlingLeft_.getTxtRemovingSymLink(), L"%x", utf8CvrtTo<wxString>(linkObj.getFullName<LEFT_SIDE>())));
- deleteSymlink<LEFT_SIDE>(linkObj); //throw FileError
- linkObj.removeObject<LEFT_SIDE>(); //remove file from FileMapping, to keep in sync (if subsequent copying fails!!)
-
- procCallback_.reportStatus(logText); //restore status text
- zen::copySymlink(linkObj.getFullName<RIGHT_SIDE>(), target, copyFilePermissions); //throw FileError
-
- linkObj.copyTo<LEFT_SIDE>(); //update SymLinkMapping
- break;
-
case SO_OVERWRITE_RIGHT:
- target = linkObj.getBaseDirPf<RIGHT_SIDE>() + linkObj.getRelativeName<LEFT_SIDE>(); //respect differences in case of source object
-
- logText = txtOverwritingLink;
- replace(logText, L"%x", utf8CvrtTo<wxString>(target));
- procCallback_.reportInfo(logText);
+ {
+ const Zstring& target = linkObj.getBaseDirPf<sideTrg>() + linkObj.getRelativeName<sideSrc>(); //respect differences in case of source object
- procCallback_.reportStatus(replaceCpy(delHandlingRight_.getTxtRemovingSymLink(), L"%x", utf8CvrtTo<wxString>(linkObj.getFullName<RIGHT_SIDE>())));
- deleteSymlink<RIGHT_SIDE>(linkObj); //throw FileError
- linkObj.removeObject<RIGHT_SIDE>(); //remove file from FileMapping, to keep in sync (if subsequent copying fails!!)
+ reportInfo(txtOverwritingLink, target);
- procCallback_.reportStatus(logText); //restore status text
- zen::copySymlink(linkObj.getFullName<LEFT_SIDE>(), target, copyFilePermissions); //throw FileError
+ reportStatus(getDelHandling<sideTrg>().getTxtRemovingSymLink(), linkObj.getFullName<sideTrg>());
+ deleteSymlink(); //throw FileError
+ linkObj.removeObject<sideTrg>(); //remove file from FileMapping, to keep in sync (if subsequent copying fails!!)
- linkObj.copyTo<RIGHT_SIDE>(); //update SymLinkMapping
- break;
+ reportStatus(txtOverwritingLink, target); //restore status text
+ zen::copySymlink(linkObj.getFullName<sideSrc>(), target, copyFilePermissions); //throw FileError
+ linkObj.copyTo<sideTrg>(); //update SymLinkMapping
+ }
+ break;
case SO_COPY_METADATA_TO_LEFT:
- logText = replaceCpy(txtWritingAttributes, L"%x", utf8CvrtTo<wxString>(linkObj.getFullName<LEFT_SIDE>()));
- procCallback_.reportInfo(logText);
-
- if (linkObj.getShortName<LEFT_SIDE>() != linkObj.getShortName<RIGHT_SIDE>()) //adapt difference in case (windows only)
- renameFile(linkObj.getFullName<LEFT_SIDE>(),
- beforeLast(linkObj.getFullName<LEFT_SIDE>(), FILE_NAME_SEPARATOR) + FILE_NAME_SEPARATOR + linkObj.getShortName<RIGHT_SIDE>()); //throw FileError;
-
- if (!sameFileTime(linkObj.getLastWriteTime<LEFT_SIDE>(), linkObj.getLastWriteTime<RIGHT_SIDE>(), 2)) //respect 2 second FAT/FAT32 precision
- setFileTime(linkObj.getFullName<LEFT_SIDE>(), linkObj.getLastWriteTime<RIGHT_SIDE>(), SYMLINK_DIRECT); //throw FileError
-
- linkObj.copyTo<LEFT_SIDE>(); //-> both sides *should* be completely equal now...
- break;
-
case SO_COPY_METADATA_TO_RIGHT:
- logText = replaceCpy(txtWritingAttributes, L"%x", utf8CvrtTo<wxString>(linkObj.getFullName<RIGHT_SIDE>()));
- procCallback_.reportInfo(logText);
+ reportInfo(txtWritingAttributes, linkObj.getFullName<sideTrg>());
- if (linkObj.getShortName<LEFT_SIDE>() != linkObj.getShortName<RIGHT_SIDE>()) //adapt difference in case (windows only)
- renameFile(linkObj.getFullName<RIGHT_SIDE>(),
- beforeLast(linkObj.getFullName<RIGHT_SIDE>(), FILE_NAME_SEPARATOR) + FILE_NAME_SEPARATOR + linkObj.getShortName<LEFT_SIDE>()); //throw FileError;
+ if (linkObj.getShortName<sideTrg>() != linkObj.getShortName<sideSrc>()) //adapt difference in case (windows only)
+ renameFile(linkObj.getFullName<sideTrg>(),
+ beforeLast(linkObj.getFullName<sideTrg>(), FILE_NAME_SEPARATOR) + FILE_NAME_SEPARATOR + linkObj.getShortName<sideSrc>()); //throw FileError;
- if (!sameFileTime(linkObj.getLastWriteTime<LEFT_SIDE>(), linkObj.getLastWriteTime<RIGHT_SIDE>(), 2)) //respect 2 second FAT/FAT32 precision
- setFileTime(linkObj.getFullName<RIGHT_SIDE>(), linkObj.getLastWriteTime<LEFT_SIDE>(), SYMLINK_DIRECT); //throw FileError
+ if (!sameFileTime(linkObj.getLastWriteTime<sideTrg>(), linkObj.getLastWriteTime<sideSrc>(), 2)) //respect 2 second FAT/FAT32 precision
+ setFileTime(linkObj.getFullName<sideTrg>(), linkObj.getLastWriteTime<sideSrc>(), SYMLINK_DIRECT); //throw FileError
- linkObj.copyTo<RIGHT_SIDE>(); //-> both sides *should* be completely equal now...
+ linkObj.copyTo<sideTrg>(); //-> both sides *should* be completely equal now...
break;
+ case SO_MOVE_LEFT_SOURCE:
+ case SO_MOVE_RIGHT_SOURCE:
+ case SO_MOVE_LEFT_TARGET:
+ case SO_MOVE_RIGHT_TARGET:
+ assert(false);
case SO_DO_NOTHING:
case SO_EQUAL:
case SO_UNRESOLVED_CONFLICT:
@@ -1193,126 +1535,89 @@ void SynchronizeFolderPair::synchronizeLink(SymLinkMapping& linkObj) const
}
+inline
void SynchronizeFolderPair::synchronizeFolder(DirMapping& dirObj) const
{
- wxString logText;
- Zstring target;
+ const SyncOperation syncOp = dirObj.getSyncOperation();
- //synchronize folders:
- switch (dirObj.getSyncOperation()) //evaluate comparison result and sync direction
- {
- case SO_CREATE_NEW_LEFT:
- //some check to catch the error that directory on source has been deleted externally after "compare"...
- if (!dirExists(dirObj.getFullName<RIGHT_SIDE>()))
- {
- // throw FileError(_ ("Source directory does not exist anymore:") + "\n\"" + dirObj.getFullName<RIGHT_SIDE>() + "\"");
- const SyncStatistics subObjects(dirObj); //DON'T forget to notify about implicitly deleted objects!
- procCallback_.updateProcessedData(subObjects.getCreate() + subObjects.getOverwrite() + subObjects.getDelete(), to<zen::Int64>(subObjects.getDataToProcess()));
+ SelectedSide sideTrg = LEFT_SIDE;
- dirObj.refSubFiles().clear(); //...then remove sub-objects
- dirObj.refSubLinks().clear(); //
- dirObj.refSubDirs ().clear(); //
- dirObj.removeObject<RIGHT_SIDE>();
- }
- else
- {
- target = dirObj.getBaseDirPf<LEFT_SIDE>() + dirObj.getRelativeName<RIGHT_SIDE>();
+ if (getTargetDir(syncOp, &sideTrg))
+ {
+ if (sideTrg == LEFT_SIDE)
+ synchronizeFolderInt<LEFT_SIDE>(dirObj, syncOp);
+ else
+ synchronizeFolderInt<RIGHT_SIDE>(dirObj, syncOp);
+ }
+}
- logText = replaceCpy(txtCreatingFolder, L"%x", utf8CvrtTo<wxString>(target));
- procCallback_.reportInfo(logText);
- createDirectory(target, dirObj.getFullName<RIGHT_SIDE>(), copyFilePermissions); //no symlink copying!
- dirObj.copyTo<LEFT_SIDE>(); //update DirMapping
- }
- break;
+template <SelectedSide sideTrg>
+void SynchronizeFolderPair::synchronizeFolderInt(DirMapping& dirObj, SyncOperation syncOp) const
+{
+ static const SelectedSide sideSrc = OtherSide<sideTrg>::result;
+ switch (syncOp)
+ {
+ case SO_CREATE_NEW_LEFT:
case SO_CREATE_NEW_RIGHT:
- //some check to catch the error that directory on source has been deleted externally after "compare"...
- if (!dirExists(dirObj.getFullName<LEFT_SIDE>()))
+ if (dirExists(dirObj.getFullName<sideSrc>()))
{
- //throw FileError(_ ("Source directory does not exist anymore:") + "\n\"" + dirObj.getFullName<LEFT_SIDE>() + "\"");
- const SyncStatistics subObjects(dirObj); //DON'T forget to notify about implicitly deleted objects!
- procCallback_.updateProcessedData(subObjects.getCreate() + subObjects.getOverwrite() + subObjects.getDelete(), to<zen::Int64>(subObjects.getDataToProcess()));
+ const Zstring& target = dirObj.getBaseDirPf<sideTrg>() + dirObj.getRelativeName<sideSrc>();
- dirObj.refSubFiles().clear(); //...then remove sub-objects
- dirObj.refSubLinks().clear(); //
- dirObj.refSubDirs ().clear(); //
- dirObj.removeObject<LEFT_SIDE>();
+ reportInfo(txtCreatingFolder, target);
+ createDirectory(target, dirObj.getFullName<sideSrc>(), copyFilePermissions); //no symlink copying!
+ dirObj.copyTo<sideTrg>(); //update DirMapping
}
- else
+ else //source directory has been deleted externally after "compare"...
{
- target = dirObj.getBaseDirPf<RIGHT_SIDE>() + dirObj.getRelativeName<LEFT_SIDE>();
-
- logText = replaceCpy(txtCreatingFolder, L"%x", utf8CvrtTo<wxString>(target));
- procCallback_.reportInfo(logText);
+ // throw FileError(_ ("Source directory does not exist anymore:") + "\n\"" + dirObj.getFullName<sideSrc>() + "\"");
+ const SyncStatistics subStats(dirObj); //DON'T forget to notify about implicitly deleted objects!
+ procCallback_.updateProcessedData(getCUD(subStats), to<zen::Int64>(subStats.getDataToProcess()));
- createDirectory(target, dirObj.getFullName<LEFT_SIDE>(), copyFilePermissions); //no symlink copying!
- dirObj.copyTo<RIGHT_SIDE>(); //update DirMapping
+ dirObj.refSubFiles().clear(); //...then remove sub-objects
+ dirObj.refSubLinks().clear(); //
+ dirObj.refSubDirs ().clear(); //
+ dirObj.removeObject<sideSrc>();
}
break;
case SO_COPY_METADATA_TO_LEFT:
- logText = replaceCpy(txtWritingAttributes, L"%x", utf8CvrtTo<wxString>(dirObj.getFullName<LEFT_SIDE>()));
- procCallback_.reportInfo(logText);
-
- if (dirObj.getShortName<LEFT_SIDE>() != dirObj.getShortName<RIGHT_SIDE>()) //adapt difference in case (windows only)
- renameFile(dirObj.getFullName<LEFT_SIDE>(),
- beforeLast(dirObj.getFullName<LEFT_SIDE>(), FILE_NAME_SEPARATOR) + FILE_NAME_SEPARATOR + dirObj.getShortName<RIGHT_SIDE>()); //throw FileError;
- //copyFileTimes(dirObj.getFullName<RIGHT_SIDE>(), dirObj.getFullName<LEFT_SIDE>(), true); //throw FileError -> is executed after sub-objects have finished synchronization
-
- dirObj.copyTo<LEFT_SIDE>(); //-> both sides *should* be completely equal now...
- break;
-
case SO_COPY_METADATA_TO_RIGHT:
- logText = replaceCpy(txtWritingAttributes, L"%x", utf8CvrtTo<wxString>(dirObj.getFullName<RIGHT_SIDE>()));
- procCallback_.reportInfo(logText);
+ reportInfo(txtWritingAttributes, dirObj.getFullName<sideTrg>());
- if (dirObj.getShortName<LEFT_SIDE>() != dirObj.getShortName<RIGHT_SIDE>()) //adapt difference in case (windows only)
- renameFile(dirObj.getFullName<RIGHT_SIDE>(),
- beforeLast(dirObj.getFullName<RIGHT_SIDE>(), FILE_NAME_SEPARATOR) + FILE_NAME_SEPARATOR + dirObj.getShortName<LEFT_SIDE>()); //throw FileError;
- //copyFileTimes(dirObj.getFullName<LEFT_SIDE>(), dirObj.getFullName<RIGHT_SIDE>(), true); //throw FileError -> is executed after sub-objects have finished synchronization
+ if (dirObj.getShortName<sideTrg>() != dirObj.getShortName<sideSrc>()) //adapt difference in case (windows only)
+ renameFile(dirObj.getFullName<sideTrg>(),
+ beforeLast(dirObj.getFullName<sideTrg>(), FILE_NAME_SEPARATOR) + FILE_NAME_SEPARATOR + dirObj.getShortName<sideSrc>()); //throw FileError;
+ //copyFileTimes -> useless at this time: modification time changes with each child-object creation/deletion
- dirObj.copyTo<RIGHT_SIDE>(); //-> both sides *should* be completely equal now...
+ dirObj.copyTo<sideTrg>(); //-> both sides *should* be completely equal now...
break;
case SO_DELETE_LEFT:
- //status information
- logText = replaceCpy(delHandlingLeft_.getTxtRemovingDir(), L"%x", utf8CvrtTo<wxString>(dirObj.getFullName<LEFT_SIDE>()));
- procCallback_.reportInfo(logText);
+ case SO_DELETE_RIGHT:
+ {
+ reportInfo(getDelHandling<sideTrg>().getTxtRemovingDir(), dirObj.getFullName<sideTrg>());
- delHandlingLeft_.removeFolder(dirObj.getObjRelativeName()); //throw FileError
- {
- //progress indicator update: DON'T forget to notify about implicitly deleted objects!
- const SyncStatistics subObjects(dirObj);
- //...then remove everything
- dirObj.refSubFiles().clear();
- dirObj.refSubLinks().clear();
- dirObj.refSubDirs ().clear();
- procCallback_.updateProcessedData(subObjects.getCreate() + subObjects.getOverwrite() + subObjects.getDelete(), to<zen::Int64>(subObjects.getDataToProcess()));
- }
- dirObj.removeObject<LEFT_SIDE>(); //update DirMapping
- break;
+ getDelHandling<sideTrg>().removeFolder(dirObj.getObjRelativeName()); //throw FileError
- case SO_DELETE_RIGHT:
- //status information
- logText = replaceCpy(delHandlingRight_.getTxtRemovingDir(), L"%x", utf8CvrtTo<wxString>(dirObj.getFullName<RIGHT_SIDE>()));
- procCallback_.reportInfo(logText);
+ //progress indicator update: DON'T forget to notify about implicitly deleted objects!
+ const SyncStatistics subStats(dirObj);
+ dirObj.refSubFiles().clear(); //...then remove everything
+ dirObj.refSubLinks().clear();
+ dirObj.refSubDirs ().clear();
+ procCallback_.updateProcessedData(getCUD(subStats), to<zen::Int64>(subStats.getDataToProcess()));
- delHandlingRight_.removeFolder(dirObj.getObjRelativeName()); //throw FileError
- {
- //progress indicator update: DON'T forget to notify about implicitly deleted objects!
- const SyncStatistics subObjects(dirObj);
- //...then remove everything
- dirObj.refSubFiles().clear();
- dirObj.refSubLinks().clear();
- dirObj.refSubDirs ().clear();
- procCallback_.updateProcessedData(subObjects.getCreate() + subObjects.getOverwrite() + subObjects.getDelete(), to<zen::Int64>(subObjects.getDataToProcess()));
- }
- dirObj.removeObject<RIGHT_SIDE>(); //update DirMapping
- break;
+ dirObj.removeObject<sideTrg>(); //update DirMapping
+ }
+ break;
case SO_OVERWRITE_RIGHT:
case SO_OVERWRITE_LEFT:
+ case SO_MOVE_LEFT_SOURCE:
+ case SO_MOVE_RIGHT_SOURCE:
+ case SO_MOVE_LEFT_TARGET:
+ case SO_MOVE_RIGHT_TARGET:
assert(false);
case SO_UNRESOLVED_CONFLICT:
case SO_DO_NOTHING:
@@ -1336,31 +1641,27 @@ void makeSameLength(std::wstring& first, std::wstring& second)
second.resize(maxPref, L' ');
}
+
+/*
struct LessDependentDirectory : public std::binary_function<Zstring, Zstring, bool>
{
+-> a *very* bad idea: this is NOT a strict weak ordering! No transitivity of equivalence!
+
bool operator()(const Zstring& lhs, const Zstring& rhs) const
{
return LessFilename()(Zstring(lhs.c_str(), std::min(lhs.length(), rhs.length())),
Zstring(rhs.c_str(), std::min(lhs.length(), rhs.length())));
}
};
-
-struct EqualDependentDirectory : public std::binary_function<Zstring, Zstring, bool>
-{
- bool operator()(const Zstring& lhs, const Zstring& rhs) const
- {
- return EqualFilename()(Zstring(lhs.c_str(), std::min(lhs.length(), rhs.length())),
- Zstring(rhs.c_str(), std::min(lhs.length(), rhs.length())));
- }
-};
+*/
}
void SyncProcess::startSynchronizationProcess(const std::vector<FolderPairSyncCfg>& syncConfig, FolderComparison& folderCmp)
{
- //prevent shutdown while synchronization is in progress
- DisableStandby dummy;
- (void)dummy;
+ //prevent shutdown while synchronization is in progress
+ PreventStandby dummy;
+ (void)dummy;
#ifdef NDEBUG
wxLogNull noWxLogs; //prevent wxWidgets logging
@@ -1371,12 +1672,11 @@ void SyncProcess::startSynchronizationProcess(const std::vector<FolderPairSyncCf
if (syncConfig.size() != folderCmp.size())
throw std::logic_error("Programming Error: Contract violation!");
-
//inform about the total amount of data that will be processed from now on
const SyncStatistics statisticsTotal(folderCmp);
//keep at beginning so that all gui elements are initialized properly
- procCallback.initNewProcess(statisticsTotal.getCreate() + statisticsTotal.getOverwrite() + statisticsTotal.getDelete(),
+ procCallback.initNewProcess(getCUD(statisticsTotal),
to<zen::Int64>(statisticsTotal.getDataToProcess()),
ProcessCallback::PROCESS_SYNCHRONIZING);
@@ -1404,12 +1704,34 @@ void SyncProcess::startSynchronizationProcess(const std::vector<FolderPairSyncCf
//-------------------some basic checks:------------------------------------------
+ auto dependentDir = [](const Zstring& lhs, const Zstring& rhs) //note: this is NOT an equivalence relation!
+ {
+ return EqualFilename()(Zstring(lhs.c_str(), std::min(lhs.length(), rhs.length())),
+ Zstring(rhs.c_str(), std::min(lhs.length(), rhs.length())));
+ };
//aggregate information
- typedef std::set<Zstring, LessDependentDirectory> DirReadSet; //count (at least one) read access
- typedef std::map<Zstring, size_t, LessDependentDirectory> DirWriteMap; //count (read+)write accesses
- DirReadSet dirReadCount;
- DirWriteMap dirWriteCount;
+ std::map<Zstring, std::pair<size_t, size_t>> dirReadWriteCount; //count read/write accesses
+ auto incReadCount = [&](const Zstring& baseDir)
+ {
+ dirReadWriteCount[baseDir]; //create entry
+ for (auto iter = dirReadWriteCount.begin(); iter != dirReadWriteCount.end(); ++iter)
+ {
+ auto& countRef = iter->second;
+ if (dependentDir(baseDir, iter->first))
+ ++countRef.first;
+ }
+ };
+ auto incWriteCount = [&](const Zstring& baseDir)
+ {
+ dirReadWriteCount[baseDir]; //create entry
+ for (auto iter = dirReadWriteCount.begin(); iter != dirReadWriteCount.end(); ++iter)
+ {
+ auto& countRef = iter->second;
+ if (dependentDir(baseDir, iter->first))
+ ++countRef.second;
+ }
+ };
typedef std::vector<std::pair<Zstring, Zstring> > DirPairList;
DirPairList significantDiff;
@@ -1417,8 +1739,7 @@ void SyncProcess::startSynchronizationProcess(const std::vector<FolderPairSyncCf
typedef std::vector<std::pair<Zstring, std::pair<zen::Int64, zen::Int64> > > DirSpaceRequAvailList; //dirname / space required / space available
DirSpaceRequAvailList diskSpaceMissing;
- typedef std::set<Zstring, LessDependentDirectory> DirRecyclerMissing;
- DirRecyclerMissing recyclMissing;
+ std::set<Zstring> recyclMissing;
//start checking folder pairs
for (auto j = begin(folderCmp); j != end(folderCmp); ++j)
@@ -1435,13 +1756,13 @@ void SyncProcess::startSynchronizationProcess(const std::vector<FolderPairSyncCf
const SyncStatistics folderPairStat(*j);
//aggregate basic information
- const bool writeLeft = folderPairStat.getCreate <LEFT_SIDE>() +
- folderPairStat.getOverwrite<LEFT_SIDE>() +
- folderPairStat.getDelete <LEFT_SIDE>() > 0;
+ const bool writeLeft = folderPairStat.getCreate<LEFT_SIDE>() +
+ folderPairStat.getUpdate<LEFT_SIDE>() +
+ folderPairStat.getDelete<LEFT_SIDE>() > 0;
- const bool writeRight = folderPairStat.getCreate <RIGHT_SIDE>() +
- folderPairStat.getOverwrite<RIGHT_SIDE>() +
- folderPairStat.getDelete <RIGHT_SIDE>() > 0;
+ const bool writeRight = folderPairStat.getCreate<RIGHT_SIDE>() +
+ folderPairStat.getUpdate<RIGHT_SIDE>() +
+ folderPairStat.getDelete<RIGHT_SIDE>() > 0;
//skip folder pair if there is nothing to do (except for automatic mode, where data base needs to be written even in this case)
if (!writeLeft && !writeRight &&
@@ -1453,7 +1774,7 @@ void SyncProcess::startSynchronizationProcess(const std::vector<FolderPairSyncCf
//check empty input fields: basically this only makes sense if empty field is not target (and not automatic mode: because of db file creation)
- if ((j->getBaseDirPf<LEFT_SIDE>(). empty() && (writeLeft || folderPairCfg.inAutomaticMode)) ||
+ if ((j->getBaseDirPf<LEFT_SIDE >().empty() && (writeLeft || folderPairCfg.inAutomaticMode)) ||
(j->getBaseDirPf<RIGHT_SIDE>().empty() && (writeRight || folderPairCfg.inAutomaticMode)))
{
procCallback.reportFatalError(_("Target directory name must not be empty!"));
@@ -1462,30 +1783,32 @@ void SyncProcess::startSynchronizationProcess(const std::vector<FolderPairSyncCf
}
//aggregate information of folders used by multiple pairs in read/write access
- if (!EqualDependentDirectory()(j->getBaseDirPf<LEFT_SIDE>(), j->getBaseDirPf<RIGHT_SIDE>())) //true in general
+ if (!dependentDir(j->getBaseDirPf<LEFT_SIDE>(), j->getBaseDirPf<RIGHT_SIDE>())) //true in general
{
- if (writeLeft)
+ if (writeLeft && writeRight)
+ {
+ incWriteCount(j->getBaseDirPf<LEFT_SIDE >());
+ incWriteCount(j->getBaseDirPf<RIGHT_SIDE>());
+ }
+ else if (writeLeft)
{
- ++dirWriteCount[j->getBaseDirPf<LEFT_SIDE>()];
- if (writeRight)
- ++dirWriteCount[j->getBaseDirPf<RIGHT_SIDE>()];
- else
- dirReadCount.insert(j->getBaseDirPf<RIGHT_SIDE>());
+ incWriteCount(j->getBaseDirPf<LEFT_SIDE>());
+ incReadCount (j->getBaseDirPf<RIGHT_SIDE>());
}
else if (writeRight)
{
- dirReadCount.insert(j->getBaseDirPf<LEFT_SIDE>());
- ++dirWriteCount[j->getBaseDirPf<RIGHT_SIDE>()];
+ incReadCount (j->getBaseDirPf<LEFT_SIDE>());
+ incWriteCount(j->getBaseDirPf<RIGHT_SIDE>());
}
}
else //if folder pair contains two dependent folders, a warning was already issued after comparison; in this context treat as one write access at most
{
if (writeLeft || writeRight)
- ++dirWriteCount[j->getBaseDirPf<LEFT_SIDE>()];
+ incWriteCount(j->getBaseDirPf<LEFT_SIDE>());
}
- if (folderPairStat.getOverwrite() + folderPairStat.getDelete() > 0)
+ if (folderPairStat.getUpdate() + folderPairStat.getDelete() > 0)
{
if (folderPairCfg.handleDeletion == zen::MOVE_TO_CUSTOM_DIRECTORY)
{
@@ -1500,7 +1823,9 @@ void SyncProcess::startSynchronizationProcess(const std::vector<FolderPairSyncCf
}
//avoid data loss when source directory doesn't (temporarily?) exist anymore AND user chose to ignore errors (else we wouldn't arrive here)
- if (folderPairStat.getCreate() + folderPairStat.getOverwrite() + folderPairStat.getConflict() == 0 &&
+ if (folderPairStat.getCreate() +
+ folderPairStat.getUpdate() +
+ folderPairStat.getConflict() == 0 &&
folderPairStat.getDelete() > 0) //deletions only... (respect filtered items!)
{
Zstring missingSrcDir;
@@ -1522,9 +1847,8 @@ void SyncProcess::startSynchronizationProcess(const std::vector<FolderPairSyncCf
significantDiff.push_back(std::make_pair(j->getBaseDirPf<LEFT_SIDE>(), j->getBaseDirPf<RIGHT_SIDE>()));
//check for sufficient free diskspace in left directory
- const std::pair<zen::Int64, zen::Int64> spaceNeeded = DiskSpaceNeeded(*j,
- delHandlerFp.first.deletionFreesSpace(),
- delHandlerFp.second.deletionFreesSpace()).getSpaceTotal();
+ const std::pair<Int64, Int64> spaceNeeded = DiskSpaceNeeded::calculate(*j, delHandlerFp.first.deletionFreesSpace(),
+ delHandlerFp.second.deletionFreesSpace());
wxLongLong freeDiskSpaceLeft;
if (wxGetDiskSpace(toWx(j->getBaseDirPf<LEFT_SIDE>()), NULL, &freeDiskSpaceLeft))
{
@@ -1546,14 +1870,14 @@ void SyncProcess::startSynchronizationProcess(const std::vector<FolderPairSyncCf
#ifdef FFS_WIN
if (folderPairCfg.handleDeletion == MOVE_TO_RECYCLE_BIN)
{
- if (folderPairStat.getOverwrite<LEFT_SIDE>() +
- folderPairStat.getDelete <LEFT_SIDE>() > 0 &&
+ if (folderPairStat.getUpdate<LEFT_SIDE>() +
+ folderPairStat.getDelete<LEFT_SIDE>() > 0 &&
recycleBinStatus(j->getBaseDirPf<LEFT_SIDE>()) != STATUS_REC_EXISTS)
recyclMissing.insert(j->getBaseDirPf<LEFT_SIDE>());
- if (folderPairStat.getOverwrite<RIGHT_SIDE>() +
- folderPairStat.getDelete <RIGHT_SIDE>() > 0 &&
+ if (folderPairStat.getUpdate<RIGHT_SIDE>() +
+ folderPairStat.getDelete<RIGHT_SIDE>() > 0 &&
recycleBinStatus(j->getBaseDirPf<RIGHT_SIDE>()) != STATUS_REC_EXISTS)
recyclMissing.insert(j->getBaseDirPf<RIGHT_SIDE>());
@@ -1565,20 +1889,20 @@ void SyncProcess::startSynchronizationProcess(const std::vector<FolderPairSyncCf
if (statisticsTotal.getConflict() > 0)
{
//show the first few conflicts in warning message also:
- wxString warningMessage = wxString(_("Unresolved conflicts existing!")) +
- wxT(" (") + toStringSep(statisticsTotal.getConflict()) + wxT(")\n\n");
+ std::wstring warningMessage = _("Unresolved conflicts existing!") +
+ L" (" + toStringSep(statisticsTotal.getConflict()) + L")\n\n";
const SyncStatistics::ConflictTexts& firstConflicts = statisticsTotal.getFirstConflicts(); //get first few sync conflicts
for (SyncStatistics::ConflictTexts::const_iterator i = firstConflicts.begin(); i != firstConflicts.end(); ++i)
{
- wxString conflictDescription = i->second;
+ std::wstring conflictDescription = i->second;
//conflictDescription.Replace(wxT("\n"), wxT(" ")); //remove line-breaks
warningMessage += std::wstring(L"\"") + i->first + L"\": " + conflictDescription + L"\n\n";
}
if (statisticsTotal.getConflict() > static_cast<int>(firstConflicts.size()))
- warningMessage += wxT("[...]\n\n");
+ warningMessage += L"[...]\n\n";
warningMessage += _("You can ignore conflicts and continue synchronization.");
@@ -1589,13 +1913,14 @@ void SyncProcess::startSynchronizationProcess(const std::vector<FolderPairSyncCf
//check if more than 50% of total number of files/dirs are to be created/overwritten/deleted
if (!significantDiff.empty())
{
- wxString warningMessage = _("Significant difference detected:");
+ std::wstring warningMessage = _("Significant difference detected:");
for (DirPairList::const_iterator i = significantDiff.begin(); i != significantDiff.end(); ++i)
warningMessage += std::wstring(L"\n\n") +
i->first + L" <-> " + L"\n" +
i->second;
- warningMessage += wxString(L"\n\n") + _("More than 50% of the total number of files will be copied or deleted!");
+ warningMessage += L"\n\n";
+ warningMessage += _("More than 50% of the total number of files will be copied or deleted!");
procCallback.reportWarning(warningMessage, m_warnings.warningSignificantDifference);
}
@@ -1604,13 +1929,13 @@ void SyncProcess::startSynchronizationProcess(const std::vector<FolderPairSyncCf
//check for sufficient free diskspace
if (!diskSpaceMissing.empty())
{
- wxString warningMessage = _("Not enough free disk space available in:");
+ std::wstring warningMessage = _("Not enough free disk space available in:");
for (auto i = diskSpaceMissing.begin(); i != diskSpaceMissing.end(); ++i)
warningMessage += std::wstring(L"\n\n") +
L"\"" + i->first + L"\"\n" +
- _("Free disk space required:") + wxT(" ") + filesizeToShortString(to<UInt64>(i->second.first)) + L"\n" +
- _("Free disk space available:") + wxT(" ") + filesizeToShortString(to<UInt64>(i->second.second));
+ _("Free disk space required:") + L" " + filesizeToShortString(to<UInt64>(i->second.first)) + L"\n" +
+ _("Free disk space available:") + L" " + filesizeToShortString(to<UInt64>(i->second.second));
procCallback.reportWarning(warningMessage, m_warnings.warningNotEnoughDiskSpace);
}
@@ -1620,11 +1945,11 @@ void SyncProcess::startSynchronizationProcess(const std::vector<FolderPairSyncCf
#ifdef FFS_WIN
if (!recyclMissing.empty())
{
- wxString warningMessage = _("Recycle Bin is not available for the following paths! Files will be deleted permanently instead:");
+ std::wstring warningMessage = _("Recycle Bin is not available for the following paths! Files will be deleted permanently instead:");
warningMessage += L"\n";
std::for_each(recyclMissing.begin(), recyclMissing.end(),
- [&](const Zstring& path) { warningMessage += L"\n" + toWx(path); });
+ [&](const Zstring& path) { warningMessage += L"\n" + utf8CvrtTo<std::wstring>(path); });
procCallback.reportWarning(warningMessage, m_warnings.warningRecyclerMissing);
}
@@ -1632,15 +1957,18 @@ void SyncProcess::startSynchronizationProcess(const std::vector<FolderPairSyncCf
//check if folders are used by multiple pairs in read/write access
std::vector<Zstring> conflictDirs;
- for (DirWriteMap::const_iterator i = dirWriteCount.begin(); i != dirWriteCount.end(); ++i)
- if (i->second >= 2 || //multiple write accesses
- (i->second == 1 && dirReadCount.find(i->first) != dirReadCount.end())) //read/write access
- conflictDirs.push_back(i->first);
+ for (auto iter = dirReadWriteCount.cbegin(); iter != dirReadWriteCount.cend(); ++iter)
+ {
+ const auto& countRef = iter->second;
+ if (countRef.second >= 2 || //multiple write accesses
+ (countRef.second == 1 && countRef.first >= 1)) //read/write access
+ conflictDirs.push_back(iter->first);
+ }
if (!conflictDirs.empty())
{
- wxString warningMessage = wxString(_("A directory will be modified which is part of multiple folder pairs! Please review synchronization settings!")) + wxT("\n");
- for (std::vector<Zstring>::const_iterator i = conflictDirs.begin(); i != conflictDirs.end(); ++i)
+ std::wstring warningMessage = _("A directory will be modified which is part of multiple folder pairs! Please review synchronization settings!") + L"\n";
+ for (auto i = conflictDirs.begin(); i != conflictDirs.end(); ++i)
warningMessage += std::wstring(L"\n") +
L"\"" + *i + L"\"";
procCallback.reportWarning(warningMessage, m_warnings.warningMultiFolderWriteAccess);
@@ -1677,8 +2005,8 @@ void SyncProcess::startSynchronizationProcess(const std::vector<FolderPairSyncCf
makeSameLength(left, right);
const std::wstring statusTxt = _("Processing folder pair:") + L" \n" +
- L"\t" + left + L"\"" + j->getBaseDirPf<LEFT_SIDE>() + L"\"" + L" \n" +
- L"\t" + right + L"\"" + j->getBaseDirPf<RIGHT_SIDE>() + L"\"";
+ L" " + left + L"\"" + j->getBaseDirPf<LEFT_SIDE>() + L"\"" + L" \n" +
+ L" " + right + L"\"" + j->getBaseDirPf<RIGHT_SIDE>() + L"\"";
procCallback.reportInfo(statusTxt);
//------------------------------------------------------------------------------------------
@@ -1725,7 +2053,6 @@ void SyncProcess::startSynchronizationProcess(const std::vector<FolderPairSyncCf
if (folderPairCfg.inAutomaticMode)
{
procCallback.reportStatus(_("Generating database..."));
- procCallback.forceUiRefresh();
tryReportingError(procCallback, [&]() { zen::saveToDisk(*j); }); //throw FileError
guardUpdateDb.dismiss();
@@ -1737,7 +2064,7 @@ void SyncProcess::startSynchronizationProcess(const std::vector<FolderPairSyncCf
}
catch (const std::exception& e)
{
- procCallback.reportFatalError(wxString::FromUTF8(e.what()));
+ procCallback.reportFatalError(utf8CvrtTo<std::wstring>(e.what()));
}
}
@@ -1768,7 +2095,7 @@ public:
}
private:
- UInt64& bytesReported_;
+ UInt64& bytesReported_;
ProcessCallback& statusHandler_;
DelTargetCommand cmd_;
};
@@ -1776,13 +2103,13 @@ private:
//copy file while refreshing UI
template <SelectedSide side, class DelTargetCommand>
-void SynchronizeFolderPair::copyFileUpdatingTo(const FileMapping& fileObj, const DelTargetCommand& cmd, FileDescriptor& sourceAttr) const
+void SynchronizeFolderPair::copyFileUpdatingTo(const FileMapping& fileObj, const DelTargetCommand& cmd, FileAttrib& newAttr) const
{
const UInt64 totalBytesToCpy = fileObj.getFileSize<OtherSide<side>::result>();
Zstring source = fileObj.getFullName<OtherSide<side>::result>();
const Zstring& target = fileObj.getBaseDirPf<side>() + fileObj.getRelativeName<OtherSide<side>::result>();
- auto copyOperation = [&]()
+ auto copyOperation = [&]
{
//start of (possibly) long-running copy process: ensure status updates are performed regularly
UInt64 bytesReported;
@@ -1790,16 +2117,13 @@ void SynchronizeFolderPair::copyFileUpdatingTo(const FileMapping& fileObj, const
zen::ScopeGuard guardStatistics = zen::makeGuard([&]() { procCallback_.updateProcessedData(0, -1 * to<Int64>(bytesReported)); });
WhileCopying<DelTargetCommand> callback(bytesReported, procCallback_, cmd);
- FileAttrib fileAttr;
zen::copyFile(source, //type File implicitly means symlinks need to be dereferenced!
- target,
- copyFilePermissions,
- transactionalFileCopy,
- &callback,
- &fileAttr); //throw FileError, ErrorFileLocked
-
- sourceAttr = FileDescriptor(fileAttr.modificationTime, fileAttr.fileSize);
+ target,
+ copyFilePermissions,
+ transactionalFileCopy,
+ &callback,
+ &newAttr); //throw FileError, ErrorFileLocked
//inform about the (remaining) processed amount of data
procCallback_.updateProcessedData(0, to<Int64>(totalBytesToCpy) - to<Int64>(bytesReported));
@@ -1851,24 +2175,6 @@ void SynchronizeFolderPair::copyFileUpdatingTo(const FileMapping& fileObj, const
}
-template <zen::SelectedSide side>
-void SynchronizeFolderPair::deleteSymlink(const SymLinkMapping& linkObj) const
-{
- const DeletionHandling& delHandling = side == LEFT_SIDE ? delHandlingLeft_ : delHandlingRight_;
-
- switch (linkObj.getLinkType<side>())
- {
- case LinkDescriptor::TYPE_DIR:
- delHandling.removeFolder(linkObj.getObjRelativeName()); //throw FileError
- break;
-
- case LinkDescriptor::TYPE_FILE: //Windows: true file symlink; Linux: file-link or broken link
- delHandling.removeFile(linkObj.getObjRelativeName()); //throw FileError
- break;
- }
-}
-
-
//--------------------- data verification -------------------------
//callback functionality for status updates while verifying
@@ -1936,8 +2242,7 @@ private:
void SynchronizeFolderPair::verifyFileCopy(const Zstring& source, const Zstring& target) const
{
- wxString logText = replaceCpy(txtVerifying, L"%x", utf8CvrtTo<wxString>(target));
- procCallback_.reportInfo(logText);
+ procCallback_.reportInfo(replaceCpy(txtVerifying, L"%x", utf8CvrtTo<std::wstring>(target)));
VerifyStatusUpdater callback(procCallback_);
bgstack15