summaryrefslogtreecommitdiff
path: root/synchronization.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'synchronization.cpp')
-rw-r--r--synchronization.cpp350
1 files changed, 266 insertions, 84 deletions
diff --git a/synchronization.cpp b/synchronization.cpp
index 493bf077..8e0dc7de 100644
--- a/synchronization.cpp
+++ b/synchronization.cpp
@@ -1,7 +1,7 @@
// **************************************************************************
// * This file is part of the FreeFileSync project. It is distributed under *
// * GNU General Public License: http://www.gnu.org/licenses/gpl.html *
-// * Copyright (C) 2008-2010 ZenJu (zhnmju123 AT gmx.de) *
+// * Copyright (C) 2008-2011 ZenJu (zhnmju123 AT gmx.de) *
// **************************************************************************
//
#include "synchronization.h"
@@ -21,6 +21,8 @@
#include <boost/scoped_array.hpp>
#include <memory>
#include "library/db_file.h"
+#include "shared/disable_standby.h"
+#include "library/cmp_filetime.h"
#ifdef FFS_WIN
#include "shared/long_path_prefix.h"
@@ -58,27 +60,6 @@ SyncStatistics::SyncStatistics(const FolderComparison& folderCmp)
}
-int SyncStatistics::getCreate(bool inclLeft, bool inclRight) const
-{
- return (inclLeft ? createLeft : 0) +
- (inclRight ? createRight : 0);
-}
-
-
-int SyncStatistics::getOverwrite(bool inclLeft, bool inclRight) const
-{
- return (inclLeft ? overwriteLeft : 0) +
- (inclRight ? overwriteRight : 0);
-}
-
-
-int SyncStatistics::getDelete(bool inclLeft, bool inclRight) const
-{
- return (inclLeft ? deleteLeft : 0) +
- (inclRight ? deleteRight : 0);
-}
-
-
int SyncStatistics::getConflict() const
{
return conflict;
@@ -161,6 +142,14 @@ void SyncStatistics::getFileNumbers(const FileMapping& fileObj)
firstConflicts.push_back(std::make_pair(fileObj.getObjRelativeName(), fileObj.getSyncOpConflict()));
break;
+ case SO_COPY_METADATA_TO_LEFT:
+ ++overwriteLeft;
+ break;
+
+ case SO_COPY_METADATA_TO_RIGHT:
+ ++overwriteRight;
+ break;
+
case SO_DO_NOTHING:
case SO_EQUAL:
break;
@@ -190,10 +179,12 @@ void SyncStatistics::getLinkNumbers(const SymLinkMapping& linkObj)
break;
case SO_OVERWRITE_LEFT:
+ case SO_COPY_METADATA_TO_LEFT:
++overwriteLeft;
break;
case SO_OVERWRITE_RIGHT:
+ case SO_COPY_METADATA_TO_RIGHT:
++overwriteRight;
break;
@@ -242,6 +233,14 @@ void SyncStatistics::getDirNumbers(const DirMapping& dirObj)
firstConflicts.push_back(std::make_pair(dirObj.getObjRelativeName(), dirObj.getSyncOpConflict()));
break;
+ case SO_COPY_METADATA_TO_LEFT:
+ ++overwriteLeft;
+ break;
+
+ case SO_COPY_METADATA_TO_RIGHT:
+ ++overwriteRight;
+ break;
+
case SO_DO_NOTHING:
case SO_EQUAL:
break;
@@ -339,6 +338,8 @@ private:
case SO_DO_NOTHING:
case SO_EQUAL:
case SO_UNRESOLVED_CONFLICT:
+ case SO_COPY_METADATA_TO_LEFT:
+ case SO_COPY_METADATA_TO_RIGHT:
break;
}
@@ -421,11 +422,11 @@ bool ffs3::synchronizationNeeded(const FolderComparison& folderCmp)
bool significantDifferenceDetected(const SyncStatistics& folderPairStat)
{
//initial file copying shall not be detected as major difference
- if ( folderPairStat.getCreate(true, false) == 0 &&
+ if ( folderPairStat.getCreate<LEFT_SIDE>() == 0 &&
folderPairStat.getOverwrite() == 0 &&
folderPairStat.getDelete() == 0 &&
folderPairStat.getConflict() == 0) return false;
- if ( folderPairStat.getCreate(false, true) == 0 &&
+ if ( folderPairStat.getCreate<RIGHT_SIDE>() == 0 &&
folderPairStat.getOverwrite() == 0 &&
folderPairStat.getDelete() == 0 &&
folderPairStat.getConflict() == 0) return false;
@@ -859,6 +860,8 @@ bool diskSpaceIsReduced(const FileMapping& fileObj)
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;
}
return false; //dummy
@@ -881,11 +884,13 @@ bool diskSpaceIsReduced(const DirMapping& dirObj)
case SO_CREATE_NEW_RIGHT:
case SO_DO_NOTHING:
case SO_EQUAL:
+ case SO_COPY_METADATA_TO_LEFT:
+ case SO_COPY_METADATA_TO_RIGHT:
return false;
}
return false; //dummy
}
-//----------------------------------------------------------------------------------------
+//---------------------------------------------------------------------------------------------------------------
class ffs3::SynchronizeFolderPair
@@ -903,12 +908,13 @@ public:
delHandling_(delHandling),
verifyCopiedFiles_(syncProc.verifyCopiedFiles_),
copyFilePermissions_(syncProc.copyFilePermissions_),
- txtCopyingFile (wxToZ(_("Copying new file %x to %y")). Replace(Zstr("%x"), Zstr("\"%x\""), false).Replace(Zstr("%y"), Zstr("\n\"%y\""), false)),
+ txtCopyingFile (wxToZ(_("Copying new file %x to %y")). Replace(Zstr("%x"), Zstr("\"%x\""), false).Replace(Zstr("%y"), Zstr("\n\"%y\""), false)),
txtCopyingLink (wxToZ(_("Copying new Symbolic Link %x to %y")).Replace(Zstr("%x"), Zstr("\"%x\""), false).Replace(Zstr("%y"), Zstr("\n\"%y\""), false)),
- txtOverwritingFile(wxToZ(_("Overwriting file %x in %y")). Replace(Zstr("%x"), Zstr("\"%x\""), false).Replace(Zstr("%y"), Zstr("\n\"%y\""), false)),
+ txtOverwritingFile(wxToZ(_("Overwriting file %x in %y")). Replace(Zstr("%x"), Zstr("\"%x\""), false).Replace(Zstr("%y"), Zstr("\n\"%y\""), false)),
txtOverwritingLink(wxToZ(_("Overwriting Symbolic Link %x in %y")).Replace(Zstr("%x"), Zstr("\"%x\""), false).Replace(Zstr("%y"), Zstr("\n\"%y\""), false)),
txtCreatingFolder (wxToZ(_("Creating folder %x")).Replace(Zstr("%x"), Zstr("\n\"%x\""), false)),
- txtVerifying (wxToZ(_("Verifying file %x")). Replace(Zstr("%x"), Zstr("\n\"%x\""), false)) {}
+ txtVerifying (wxToZ(_("Verifying file %x")). Replace(Zstr("%x"), Zstr("\n\"%x\""), false)),
+ txtWritingAttributes(wxToZ(_("Updating attributes of %x")).Replace(Zstr("%x"), Zstr("\n\"%x\""), false)) {}
template <bool reduceDiskSpace> //"true" if files deletion shall happen only
@@ -948,6 +954,7 @@ private:
const Zstring txtOverwritingLink;
const Zstring txtCreatingFolder;
const Zstring txtVerifying;
+ const Zstring txtWritingAttributes;
};
@@ -985,10 +992,12 @@ void SynchronizeFolderPair::execute(HierarchyObject& hierObj)
switch (syncOp)
{
case SO_CREATE_NEW_LEFT:
- copyFileTimes(i->getFullName<RIGHT_SIDE>(), i->getFullName<LEFT_SIDE>(), true); //throw (FileError)
+ case SO_COPY_METADATA_TO_LEFT:
+ copyFileTimes(i->getFullName<RIGHT_SIDE>(), i->getFullName<LEFT_SIDE>(), true); //deref symlinks; throw (FileError)
break;
case SO_CREATE_NEW_RIGHT:
- copyFileTimes(i->getFullName<LEFT_SIDE>(), i->getFullName<RIGHT_SIDE>(), true); //throw (FileError)
+ case SO_COPY_METADATA_TO_RIGHT:
+ copyFileTimes(i->getFullName<LEFT_SIDE>(), i->getFullName<RIGHT_SIDE>(), true); //deref symlinks; throw (FileError)
break;
case SO_OVERWRITE_RIGHT:
case SO_OVERWRITE_LEFT:
@@ -1014,7 +1023,7 @@ void SynchronizeFolderPair::synchronizeFile(FileMapping& fileObj) const
switch (fileObj.getSyncOperation()) //evaluate comparison result and sync direction
{
case SO_CREATE_NEW_LEFT:
- target = fileObj.getBaseDirPf<LEFT_SIDE>() + fileObj.getRelativeName<RIGHT_SIDE>();
+ target = fileObj.getBaseDirPf<LEFT_SIDE>() + fileObj.getRelativeName<RIGHT_SIDE>(); //can't use "getFullName" as target is not yet existing
statusText = txtCopyingFile;
statusText.Replace(Zstr("%x"), fileObj.getShortName<RIGHT_SIDE>(), false);
@@ -1055,8 +1064,23 @@ void SynchronizeFolderPair::synchronizeFile(FileMapping& fileObj) const
delHandling_.removeFile<RIGHT_SIDE>(fileObj); //throw FileError()
break;
+ case SO_OVERWRITE_LEFT:
+ target = fileObj.getBaseDirPf<LEFT_SIDE>() + fileObj.getRelativeName<RIGHT_SIDE>(); //respect differences in case of source object
+
+ statusText = txtOverwritingFile;
+ statusText.Replace(Zstr("%x"), fileObj.getShortName<RIGHT_SIDE>(), false);
+ statusText.Replace(Zstr("%y"), fileObj.getFullName<LEFT_SIDE>().BeforeLast(common::FILE_NAME_SEPARATOR), false);
+ statusUpdater_.reportInfo(statusText);
+ statusUpdater_.requestUiRefresh(); //trigger display refresh
+
+ delHandling_.removeFile<LEFT_SIDE>(fileObj); //throw FileError()
+ fileObj.removeObject<LEFT_SIDE>(); //remove file from FileMapping, to keep in sync (if subsequent copying fails!!)
+
+ copyFileUpdating(fileObj.getFullName<RIGHT_SIDE>(), target, fileObj.getFileSize<RIGHT_SIDE>());
+ break;
+
case SO_OVERWRITE_RIGHT:
- target = fileObj.getBaseDirPf<RIGHT_SIDE>() + fileObj.getRelativeName<LEFT_SIDE>();
+ target = fileObj.getBaseDirPf<RIGHT_SIDE>() + fileObj.getRelativeName<LEFT_SIDE>(); //respect differences in case of source object
statusText = txtOverwritingFile;
statusText.Replace(Zstr("%x"), fileObj.getShortName<LEFT_SIDE>(), false);
@@ -1070,19 +1094,32 @@ void SynchronizeFolderPair::synchronizeFile(FileMapping& fileObj) const
copyFileUpdating(fileObj.getFullName<LEFT_SIDE>(), target, fileObj.getFileSize<LEFT_SIDE>());
break;
- case SO_OVERWRITE_LEFT:
- target = fileObj.getBaseDirPf<LEFT_SIDE>() + fileObj.getRelativeName<RIGHT_SIDE>();
+ case SO_COPY_METADATA_TO_LEFT:
+ statusText = txtWritingAttributes;
+ statusText.Replace(Zstr("%x"), fileObj.getFullName<LEFT_SIDE>(), false);
+ statusUpdater_.reportInfo(statusText);
+ statusUpdater_.requestUiRefresh(); //trigger display refresh
- statusText = txtOverwritingFile;
- statusText.Replace(Zstr("%x"), fileObj.getShortName<RIGHT_SIDE>(), false);
- statusText.Replace(Zstr("%y"), fileObj.getFullName<LEFT_SIDE>().BeforeLast(common::FILE_NAME_SEPARATOR), false);
+ if (fileObj.getShortName<LEFT_SIDE>() != fileObj.getShortName<RIGHT_SIDE>()) //adapt difference in case (windows only)
+ moveFile(fileObj.getFullName<LEFT_SIDE>(),
+ fileObj.getFullName<LEFT_SIDE>().BeforeLast(common::FILE_NAME_SEPARATOR) + common::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
+ copyFileTimes(fileObj.getFullName<RIGHT_SIDE>(), fileObj.getFullName<LEFT_SIDE>(), true); //deref symlinks; throw (FileError)
+ break;
+
+ case SO_COPY_METADATA_TO_RIGHT:
+ statusText = txtWritingAttributes;
+ statusText.Replace(Zstr("%x"), fileObj.getFullName<RIGHT_SIDE>(), false);
statusUpdater_.reportInfo(statusText);
statusUpdater_.requestUiRefresh(); //trigger display refresh
- delHandling_.removeFile<LEFT_SIDE>(fileObj); //throw FileError()
- fileObj.removeObject<LEFT_SIDE>(); //remove file from FileMapping, to keep in sync (if subsequent copying fails!!)
+ if (fileObj.getShortName<LEFT_SIDE>() != fileObj.getShortName<RIGHT_SIDE>()) //adapt difference in case (windows only)
+ moveFile(fileObj.getFullName<RIGHT_SIDE>(),
+ fileObj.getFullName<RIGHT_SIDE>().BeforeLast(common::FILE_NAME_SEPARATOR) + common::FILE_NAME_SEPARATOR + fileObj.getShortName<LEFT_SIDE>()); //throw (FileError);
- copyFileUpdating(fileObj.getFullName<RIGHT_SIDE>(), target, fileObj.getFileSize<RIGHT_SIDE>());
+ if (!sameFileTime(fileObj.getLastWriteTime<LEFT_SIDE>(), fileObj.getLastWriteTime<RIGHT_SIDE>(), 2)) ////respect 2 second FAT/FAT32 precision
+ copyFileTimes(fileObj.getFullName<LEFT_SIDE>(), fileObj.getFullName<RIGHT_SIDE>(), true); //deref symlinks; throw (FileError)
break;
case SO_DO_NOTHING:
@@ -1149,8 +1186,23 @@ void SynchronizeFolderPair::synchronizeLink(SymLinkMapping& linkObj) const
deleteSymlink<RIGHT_SIDE>(linkObj); //throw FileError()
break;
+ case SO_OVERWRITE_LEFT:
+ target = linkObj.getBaseDirPf<LEFT_SIDE>() + linkObj.getRelativeName<RIGHT_SIDE>(); //respect differences in case of source object
+
+ statusText = txtOverwritingLink;
+ statusText.Replace(Zstr("%x"), linkObj.getShortName<RIGHT_SIDE>(), false);
+ statusText.Replace(Zstr("%y"), linkObj.getFullName<LEFT_SIDE>().BeforeLast(common::FILE_NAME_SEPARATOR), false);
+ statusUpdater_.reportInfo(statusText);
+ statusUpdater_.requestUiRefresh(); //trigger display refresh
+
+ deleteSymlink<LEFT_SIDE>(linkObj); //throw FileError()
+ linkObj.removeObject<LEFT_SIDE>(); //remove file from FileMapping, to keep in sync (if subsequent copying fails!!)
+
+ copySymlink(linkObj.getFullName<RIGHT_SIDE>(), target, linkObj.getLinkType<RIGHT_SIDE>());
+ break;
+
case SO_OVERWRITE_RIGHT:
- target = linkObj.getBaseDirPf<RIGHT_SIDE>() + linkObj.getRelativeName<LEFT_SIDE>();
+ target = linkObj.getBaseDirPf<RIGHT_SIDE>() + linkObj.getRelativeName<LEFT_SIDE>(); //respect differences in case of source object
statusText = txtOverwritingLink;
statusText.Replace(Zstr("%x"), linkObj.getShortName<LEFT_SIDE>(), false);
@@ -1164,19 +1216,32 @@ void SynchronizeFolderPair::synchronizeLink(SymLinkMapping& linkObj) const
copySymlink(linkObj.getFullName<LEFT_SIDE>(), target, linkObj.getLinkType<LEFT_SIDE>());
break;
- case SO_OVERWRITE_LEFT:
- target = linkObj.getBaseDirPf<LEFT_SIDE>() + linkObj.getRelativeName<RIGHT_SIDE>();
+ case SO_COPY_METADATA_TO_LEFT:
+ statusText = txtWritingAttributes;
+ statusText.Replace(Zstr("%x"), linkObj.getFullName<LEFT_SIDE>(), false);
+ statusUpdater_.reportInfo(statusText);
+ statusUpdater_.requestUiRefresh(); //trigger display refresh
- statusText = txtOverwritingLink;
- statusText.Replace(Zstr("%x"), linkObj.getShortName<RIGHT_SIDE>(), false);
- statusText.Replace(Zstr("%y"), linkObj.getFullName<LEFT_SIDE>().BeforeLast(common::FILE_NAME_SEPARATOR), false);
+ if (linkObj.getShortName<LEFT_SIDE>() != linkObj.getShortName<RIGHT_SIDE>()) //adapt difference in case (windows only)
+ moveFile(linkObj.getFullName<LEFT_SIDE>(),
+ linkObj.getFullName<LEFT_SIDE>().BeforeLast(common::FILE_NAME_SEPARATOR) + common::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
+ copyFileTimes(linkObj.getFullName<RIGHT_SIDE>(), linkObj.getFullName<LEFT_SIDE>(), false); //don't deref symlinks; throw (FileError)
+ break;
+
+ case SO_COPY_METADATA_TO_RIGHT:
+ statusText = txtWritingAttributes;
+ statusText.Replace(Zstr("%x"), linkObj.getFullName<RIGHT_SIDE>(), false);
statusUpdater_.reportInfo(statusText);
statusUpdater_.requestUiRefresh(); //trigger display refresh
- deleteSymlink<LEFT_SIDE>(linkObj); //throw FileError()
- linkObj.removeObject<LEFT_SIDE>(); //remove file from FileMapping, to keep in sync (if subsequent copying fails!!)
+ if (linkObj.getShortName<LEFT_SIDE>() != linkObj.getShortName<RIGHT_SIDE>()) //adapt difference in case (windows only)
+ moveFile(linkObj.getFullName<RIGHT_SIDE>(),
+ linkObj.getFullName<RIGHT_SIDE>().BeforeLast(common::FILE_NAME_SEPARATOR) + common::FILE_NAME_SEPARATOR + linkObj.getShortName<LEFT_SIDE>()); //throw (FileError);
- copySymlink(linkObj.getFullName<RIGHT_SIDE>(), target, linkObj.getLinkType<RIGHT_SIDE>());
+ if (!sameFileTime(linkObj.getLastWriteTime<LEFT_SIDE>(), linkObj.getLastWriteTime<RIGHT_SIDE>(), 2)) ////respect 2 second FAT/FAT32 precision
+ copyFileTimes(linkObj.getFullName<LEFT_SIDE>(), linkObj.getFullName<RIGHT_SIDE>(), false); //don't deref symlinks; throw (FileError)
break;
case SO_DO_NOTHING:
@@ -1268,6 +1333,30 @@ void SynchronizeFolderPair::synchronizeFolder(DirMapping& dirObj) const
}
break;
+ case SO_COPY_METADATA_TO_LEFT:
+ statusText = txtWritingAttributes;
+ statusText.Replace(Zstr("%x"), dirObj.getFullName<LEFT_SIDE>(), false);
+ statusUpdater_.reportInfo(statusText);
+ statusUpdater_.requestUiRefresh(); //trigger display refresh
+
+ if (dirObj.getShortName<LEFT_SIDE>() != dirObj.getShortName<RIGHT_SIDE>()) //adapt difference in case (windows only)
+ moveFile(dirObj.getFullName<LEFT_SIDE>(),
+ dirObj.getFullName<LEFT_SIDE>().BeforeLast(common::FILE_NAME_SEPARATOR) + common::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
+ break;
+
+ case SO_COPY_METADATA_TO_RIGHT:
+ statusText = txtWritingAttributes;
+ statusText.Replace(Zstr("%x"), dirObj.getFullName<RIGHT_SIDE>(), false);
+ statusUpdater_.reportInfo(statusText);
+ statusUpdater_.requestUiRefresh(); //trigger display refresh
+
+ if (dirObj.getShortName<LEFT_SIDE>() != dirObj.getShortName<RIGHT_SIDE>()) //adapt difference in case (windows only)
+ moveFile(dirObj.getFullName<RIGHT_SIDE>(),
+ dirObj.getFullName<RIGHT_SIDE>().BeforeLast(common::FILE_NAME_SEPARATOR) + common::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
+ break;
+
case SO_OVERWRITE_RIGHT:
case SO_OVERWRITE_LEFT:
assert(false);
@@ -1303,6 +1392,24 @@ void makeSameLength(wxString& first, wxString& second)
first.Pad(maxPref - first.length(), wxT(' '), true);
second.Pad(maxPref - second.length(), wxT(' '), true);
}
+
+struct LessDependentDirectory : public std::binary_function<Zstring, Zstring, bool>
+{
+ 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())));
+ }
+};
}
@@ -1328,16 +1435,58 @@ void SyncProcess::startSynchronizationProcess(const std::vector<FolderPairSyncCf
if (syncConfig.size() != folderCmp.size())
throw std::logic_error("Programming Error: Contract violation!");
- std::vector<std::pair<bool, bool> > baseDirNeeded;
+ //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;
+
+ typedef std::vector<std::pair<Zstring, Zstring> > DirPairList;
+ DirPairList significantDiff;
+ typedef std::vector<std::pair<Zstring, std::pair<wxLongLong, wxLongLong> > > DirSpaceRequAvailList; //dirname / space required / space available
+ DirSpaceRequAvailList diskSpaceMissing;
+
+
+ //start checking folder pairs
for (FolderComparison::const_iterator j = folderCmp.begin(); j != folderCmp.end(); ++j)
{
+ //exclude some pathological case (leftdir, rightdir are empty)
+ if (EqualFilename()(j->getBaseDir<LEFT_SIDE>(), j->getBaseDir<RIGHT_SIDE>()))
+ continue;
+
const FolderPairSyncCfg& folderPairCfg = syncConfig[j - folderCmp.begin()];
const SyncStatistics statisticsFolderPair(*j);
- //save information whether base directories need to be created (if not yet existing)
- baseDirNeeded.push_back(std::make_pair(statisticsFolderPair.getCreate(true, false) > 0,
- statisticsFolderPair.getCreate(false, true) > 0));
+ //aggregate information of folders used by multiple pairs in read/write access
+ const bool writeLeft = statisticsFolderPair.getCreate <LEFT_SIDE>() +
+ statisticsFolderPair.getOverwrite<LEFT_SIDE>() +
+ statisticsFolderPair.getDelete <LEFT_SIDE>() > 0;
+
+ const bool writeRight = statisticsFolderPair.getCreate <RIGHT_SIDE>() +
+ statisticsFolderPair.getOverwrite<RIGHT_SIDE>() +
+ statisticsFolderPair.getDelete <RIGHT_SIDE>() > 0;
+ if (!EqualDependentDirectory()(j->getBaseDir<LEFT_SIDE>(), j->getBaseDir<RIGHT_SIDE>())) //true in general
+ {
+ if (writeLeft)
+ {
+ ++dirWriteCount[j->getBaseDir<LEFT_SIDE>()];
+ if (writeRight)
+ ++dirWriteCount[j->getBaseDir<RIGHT_SIDE>()];
+ else
+ dirReadCount.insert(j->getBaseDir<RIGHT_SIDE>());
+ }
+ else if (writeRight)
+ {
+ dirReadCount.insert(j->getBaseDir<LEFT_SIDE>());
+ ++dirWriteCount[j->getBaseDir<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->getBaseDir<LEFT_SIDE>()];
+ }
if (statisticsFolderPair.getOverwrite() + statisticsFolderPair.getDelete() > 0)
{
@@ -1373,13 +1522,7 @@ 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 (significantDifferenceDetected(statisticsFolderPair))
- {
- statusUpdater.reportWarning(wxString(_("Significant difference detected:")) + wxT("\n") +
- zToWx(j->getBaseDir<LEFT_SIDE>()) + wxT(" <-> ") + wxT("\n") +
- zToWx(j->getBaseDir<RIGHT_SIDE>()) + wxT("\n\n") +
- _("More than 50% of the total number of files will be copied or deleted!"),
- m_warnings.warningSignificantDifference);
- }
+ significantDiff.push_back(std::make_pair(j->getBaseDir<LEFT_SIDE>(), j->getBaseDir<RIGHT_SIDE>()));
//check for sufficient free diskspace in left directory
const std::pair<wxLongLong, wxLongLong> spaceNeeded = freeDiskSpaceNeeded(*j, folderPairCfg.handleDeletion, folderPairCfg.custDelFolder);
@@ -1389,11 +1532,7 @@ void SyncProcess::startSynchronizationProcess(const std::vector<FolderPairSyncCf
{
if (0 < freeDiskSpaceLeft && //zero disk space is either an error or not: in both cases this warning message is obsolete (WebDav seems to report 0)
freeDiskSpaceLeft < spaceNeeded.first)
- statusUpdater.reportWarning(wxString(_("Not enough free disk space available in:")) + wxT("\n") +
- wxT("\"") + zToWx(j->getBaseDir<LEFT_SIDE>()) + wxT("\"\n\n") +
- _("Total required free disk space:") + wxT(" ") + formatFilesizeToShortString(spaceNeeded.first) + wxT("\n") +
- _("Free disk space available:") + wxT(" ") + formatFilesizeToShortString(freeDiskSpaceLeft),
- m_warnings.warningNotEnoughDiskSpace);
+ diskSpaceMissing.push_back(std::make_pair(j->getBaseDir<LEFT_SIDE>(), std::make_pair(spaceNeeded.first, freeDiskSpaceLeft)));
}
//check for sufficient free diskspace in right directory
@@ -1402,11 +1541,7 @@ void SyncProcess::startSynchronizationProcess(const std::vector<FolderPairSyncCf
{
if (0 < freeDiskSpaceRight && //zero disk space is either an error or not: in both cases this warning message is obsolete (WebDav seems to report 0)
freeDiskSpaceRight < spaceNeeded.second)
- statusUpdater.reportWarning(wxString(_("Not enough free disk space available in:")) + wxT("\n") +
- wxT("\"") + zToWx(j->getBaseDir<RIGHT_SIDE>()) + wxT("\"\n\n") +
- _("Total required free disk space:") + wxT(" ") + formatFilesizeToShortString(spaceNeeded.second) + wxT("\n") +
- _("Free disk space available:") + wxT(" ") + formatFilesizeToShortString(freeDiskSpaceRight),
- m_warnings.warningNotEnoughDiskSpace);
+ diskSpaceMissing.push_back(std::make_pair(j->getBaseDir<RIGHT_SIDE>(), std::make_pair(spaceNeeded.second, freeDiskSpaceRight)));
}
}
@@ -1434,6 +1569,53 @@ void SyncProcess::startSynchronizationProcess(const std::vector<FolderPairSyncCf
statusUpdater.reportWarning(warningMessage, m_warnings.warningUnresolvedConflicts);
}
+
+ //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:");
+
+ for (DirPairList::const_iterator i = significantDiff.begin(); i != significantDiff.end(); ++i)
+ warningMessage += wxString(wxT("\n\n")) +
+ zToWx(i->first) + wxT(" <-> ") + wxT("\n") +
+ zToWx(i->second);
+ warningMessage += wxString(wxT("\n\n")) +_("More than 50% of the total number of files will be copied or deleted!");
+
+ statusUpdater.reportWarning(warningMessage, m_warnings.warningSignificantDifference);
+ }
+
+
+ //check for sufficient free diskspace
+ if (!diskSpaceMissing.empty())
+ {
+ wxString warningMessage = _("Not enough free disk space available in:");
+
+ for (DirSpaceRequAvailList::const_iterator i = diskSpaceMissing.begin(); i != diskSpaceMissing.end(); ++i)
+ warningMessage += wxString(wxT("\n\n")) +
+ wxT("\"") + zToWx(i->first) + wxT("\"\n") +
+ _("Total required free disk space:") + wxT(" ") + formatFilesizeToShortString(i->second.first) + wxT("\n") +
+ _("Free disk space available:") + wxT(" ") + formatFilesizeToShortString(i->second.second);
+
+ statusUpdater.reportWarning(warningMessage, m_warnings.warningNotEnoughDiskSpace);
+ }
+
+
+ //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);
+
+ 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)
+ warningMessage += wxString(wxT("\n")) +
+ wxT("\"") + zToWx(*i) + wxT("\"");
+ statusUpdater.reportWarning(warningMessage, m_warnings.warningMultiFolderWriteAccess);
+ }
+
//-------------------end of basic checks------------------------------------------
#ifdef FFS_WIN
@@ -1458,6 +1640,9 @@ void SyncProcess::startSynchronizationProcess(const std::vector<FolderPairSyncCf
try
{
+ //prevent shutdown while synchronization is in progress
+ util::DisableStandby dummy;
+
//loop through all directory pairs
assert(syncConfig.size() == folderCmp.size());
for (FolderComparison::iterator j = folderCmp.begin(); j != folderCmp.end(); ++j)
@@ -1479,20 +1664,17 @@ void SyncProcess::startSynchronizationProcess(const std::vector<FolderPairSyncCf
wxT("\t") + right + wxT("\"") + zToWx(j->getBaseDir<RIGHT_SIDE>()) + wxT("\"");
statusUpdater.reportInfo(wxToZ(statusTxt));
//------------------------------------------------------------------------------------------
- //(try to) create base dir first -> no symlink or attribute copying!
- if (baseDirNeeded[j - folderCmp.begin()].first)
- try
- {
- ffs3::createDirectory(j->getBaseDir<LEFT_SIDE>().BeforeLast(common::FILE_NAME_SEPARATOR));
- }
- catch (...) {}
-
- if (baseDirNeeded[j - folderCmp.begin()].second)
- try //create base dir first -> no symlink or attribute copying!
- {
- ffs3::createDirectory(j->getBaseDir<RIGHT_SIDE>().BeforeLast(common::FILE_NAME_SEPARATOR));
- }
- catch (...) {}
+ //(try to) create base dir first (if not yet existing) -> no symlink or attribute copying!
+ try
+ {
+ ffs3::createDirectory(j->getBaseDir<LEFT_SIDE>().BeforeLast(common::FILE_NAME_SEPARATOR));
+ }
+ catch (...) {}
+ try //create base dir first -> no symlink or attribute copying!
+ {
+ ffs3::createDirectory(j->getBaseDir<RIGHT_SIDE>().BeforeLast(common::FILE_NAME_SEPARATOR));
+ }
+ catch (...) {}
//------------------------------------------------------------------------------------------
//generate name of alternate deletion directory (unique for session AND folder pair)
bgstack15