summaryrefslogtreecommitdiff
path: root/synchronization.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'synchronization.cpp')
-rw-r--r--synchronization.cpp498
1 files changed, 260 insertions, 238 deletions
diff --git a/synchronization.cpp b/synchronization.cpp
index 59f3692d..66108ade 100644
--- a/synchronization.cpp
+++ b/synchronization.cpp
@@ -3,13 +3,15 @@
#include <wx/intl.h>
#include <wx/msgdlg.h>
#include <wx/log.h>
-#include "algorithm.h"
+#include "shared/stringConv.h"
+#include "ui/util.h"
#include "shared/systemConstants.h"
#include "library/statusHandler.h"
#include "shared/fileHandling.h"
#include <wx/file.h>
#include <boost/bind.hpp>
#include "shared/globalFunctions.h"
+#include <boost/scoped_array.hpp>
using namespace FreeFileSync;
@@ -27,10 +29,10 @@ void SyncStatistics::init()
}
-SyncStatistics::SyncStatistics(const BaseDirMapping& baseDir)
+SyncStatistics::SyncStatistics(const HierarchyObject& hierObj)
{
init();
- getNumbersRecursively(baseDir);
+ getNumbersRecursively(hierObj);
}
@@ -102,7 +104,7 @@ void SyncStatistics::getNumbersRecursively(const HierarchyObject& hierObj)
inline
void SyncStatistics::getFileNumbers(const FileMapping& fileObj)
{
- switch (FreeFileSync::getSyncOperation(fileObj)) //evaluate comparison result and sync direction
+ switch (fileObj.getSyncOperation()) //evaluate comparison result and sync direction
{
case SO_CREATE_NEW_LEFT:
++createLeft;
@@ -145,7 +147,7 @@ void SyncStatistics::getFileNumbers(const FileMapping& fileObj)
inline
void SyncStatistics::getDirNumbers(const DirMapping& dirObj)
{
- switch (FreeFileSync::getSyncOperation(dirObj)) //evaluate comparison result and sync direction
+ switch (dirObj.getSyncOperation()) //evaluate comparison result and sync direction
{
case SO_CREATE_NEW_LEFT:
++createLeft;
@@ -181,14 +183,16 @@ std::vector<FreeFileSync::FolderPairSyncCfg> FreeFileSync::extractSyncCfg(const
//add main pair
output.push_back(
- FolderPairSyncCfg(mainCfg.handleDeletion,
- mainCfg.customDeletionDirectory));
+ FolderPairSyncCfg(mainCfg.syncConfiguration.automatic,
+ mainCfg.handleDeletion,
+ wxToZ(mainCfg.customDeletionDirectory)));
//add additional pairs
for (std::vector<FolderPairEnh>::const_iterator i = mainCfg.additionalPairs.begin(); i != mainCfg.additionalPairs.end(); ++i)
output.push_back(
- FolderPairSyncCfg(i->altSyncConfig.get() ? i->altSyncConfig->handleDeletion : mainCfg.handleDeletion,
- i->altSyncConfig.get() ? i->altSyncConfig->customDeletionDirectory : mainCfg.customDeletionDirectory));
+ FolderPairSyncCfg(i->altSyncConfig.get() ? i->altSyncConfig->syncConfiguration.automatic : mainCfg.syncConfiguration.automatic,
+ i->altSyncConfig.get() ? i->altSyncConfig->handleDeletion : mainCfg.handleDeletion,
+ wxToZ(i->altSyncConfig.get() ? i->altSyncConfig->customDeletionDirectory : mainCfg.customDeletionDirectory)));
return output;
}
@@ -214,28 +218,44 @@ private:
//process files
for (HierarchyObject::SubFileMapping::const_iterator i = hierObj.subFiles.begin(); i != hierObj.subFiles.end(); ++i)
- if (i->selectedForSynchronization) //do not add filtered entries
+ switch (i->getSyncOperation()) //evaluate comparison result and sync direction
{
- //get data to process
- switch (i->syncDir)
- {
- case SYNC_DIR_LEFT: //copy from right to left
- if (!recyclerUsed)
- spaceNeededLeft -= globalFunctions::convertToSigned(i->getFileSize<LEFT_SIDE>());
- spaceNeededLeft += globalFunctions::convertToSigned(i->getFileSize<RIGHT_SIDE>());
- break;
-
- case SYNC_DIR_RIGHT: //copy from left to right
- if (!recyclerUsed)
- spaceNeededRight -= globalFunctions::convertToSigned(i->getFileSize<RIGHT_SIDE>());
- spaceNeededRight += globalFunctions::convertToSigned(i->getFileSize<LEFT_SIDE>());
- break;
-
- case SYNC_DIR_NONE:
- break;
- }
+ case SO_CREATE_NEW_LEFT:
+ spaceNeededLeft += globalFunctions::convertToSigned(i->getFileSize<RIGHT_SIDE>());
+ break;
+
+ case SO_CREATE_NEW_RIGHT:
+ spaceNeededRight += globalFunctions::convertToSigned(i->getFileSize<LEFT_SIDE>());
+ break;
+
+ case SO_DELETE_LEFT:
+ if (!recyclerUsed)
+ spaceNeededLeft -= globalFunctions::convertToSigned(i->getFileSize<LEFT_SIDE>());
+ break;
+
+ case SO_DELETE_RIGHT:
+ if (!recyclerUsed)
+ spaceNeededRight -= globalFunctions::convertToSigned(i->getFileSize<RIGHT_SIDE>());
+ break;
+
+ case SO_OVERWRITE_LEFT:
+ if (!recyclerUsed)
+ spaceNeededLeft -= globalFunctions::convertToSigned(i->getFileSize<LEFT_SIDE>());
+ spaceNeededLeft += globalFunctions::convertToSigned(i->getFileSize<RIGHT_SIDE>());
+ break;
+
+ case SO_OVERWRITE_RIGHT:
+ if (!recyclerUsed)
+ spaceNeededRight -= globalFunctions::convertToSigned(i->getFileSize<RIGHT_SIDE>());
+ spaceNeededRight += globalFunctions::convertToSigned(i->getFileSize<LEFT_SIDE>());
+ break;
+
+ case SO_DO_NOTHING:
+ case SO_UNRESOLVED_CONFLICT:
+ break;
}
+
//recurse into sub-dirs
std::for_each(hierObj.subDirs.begin(), hierObj.subDirs.end(), boost::bind(&DiskSpaceNeeded<recyclerUsed>::processRecursively, this, _1));
}
@@ -254,7 +274,7 @@ std::pair<wxLongLong, wxLongLong> freeDiskSpaceNeeded(const BaseDirMapping& base
case FreeFileSync::MOVE_TO_RECYCLE_BIN:
return DiskSpaceNeeded<true>(baseDirObj).getSpaceTotal();
case FreeFileSync::MOVE_TO_CUSTOM_DIRECTORY:
- //warning: this is not necessarily correct! it needs to be checked if user-def recycle bin dir and sync-dir are on same drive
+ //warning: this is not necessarily correct! it needs to be checked if user-def recycle bin dir and sync-dir are on same drive
return DiskSpaceNeeded<true>(baseDirObj).getSpaceTotal();
}
@@ -302,106 +322,32 @@ bool significantDifferenceDetected(const SyncStatistics& folderPairStat)
}
-FreeFileSync::SyncOperation FreeFileSync::getSyncOperation( //evaluate comparison result and sync direction
- const CompareFilesResult cmpResult,
- const bool selectedForSynchronization,
- const SyncDirection syncDir)
-{
- if (!selectedForSynchronization) return SO_DO_NOTHING;
-
- switch (cmpResult)
- {
- case FILE_LEFT_SIDE_ONLY:
- switch (syncDir)
- {
- case SYNC_DIR_LEFT:
- return SO_DELETE_LEFT; //delete files on left
- case SYNC_DIR_RIGHT:
- return SO_CREATE_NEW_RIGHT; //copy files to right
- case SYNC_DIR_NONE:
- return SO_DO_NOTHING;
- }
- break;
-
- case FILE_RIGHT_SIDE_ONLY:
- switch (syncDir)
- {
- case SYNC_DIR_LEFT:
- return SO_CREATE_NEW_LEFT; //copy files to left
- case SYNC_DIR_RIGHT:
- return SO_DELETE_RIGHT; //delete files on right
- case SYNC_DIR_NONE:
- return SO_DO_NOTHING;
- }
- break;
-
- case FILE_LEFT_NEWER:
- case FILE_RIGHT_NEWER:
- case FILE_DIFFERENT:
- switch (syncDir)
- {
- case SYNC_DIR_LEFT:
- return SO_OVERWRITE_LEFT; //copy from right to left
- case SYNC_DIR_RIGHT:
- return SO_OVERWRITE_RIGHT; //copy from left to right
- case SYNC_DIR_NONE:
- return SO_DO_NOTHING;
- }
- break;
-
- case FILE_CONFLICT:
- switch (syncDir)
- {
- case SYNC_DIR_LEFT:
- return SO_OVERWRITE_LEFT; //copy from right to left
- case SYNC_DIR_RIGHT:
- return SO_OVERWRITE_RIGHT; //copy from left to right
- case SYNC_DIR_NONE:
- return SO_UNRESOLVED_CONFLICT;
- }
- break;
-
- case FILE_EQUAL:
- assert(syncDir == SYNC_DIR_NONE);
- return SO_DO_NOTHING;
- }
-
- return SO_DO_NOTHING; //dummy
-}
-
-
-SyncOperation FreeFileSync::getSyncOperation(const FileSystemObject& fsObj) //convenience function
-{
- return getSyncOperation(fsObj.getCategory(), fsObj.selectedForSynchronization, fsObj.syncDir);
-}
-
-
/*add some postfix to alternate deletion directory: customDir\2009-06-30 12-59-12\ */
-wxString getSessionDeletionDir(const wxString& customDeletionDirectory)
+Zstring getSessionDeletionDir(const Zstring& customDeletionDirectory)
{
wxString timeNow = wxDateTime::Now().FormatISOTime();
timeNow.Replace(wxT(":"), wxT("-"));
const wxString sessionDir = wxDateTime::Now().FormatISODate() + wxChar(' ') + timeNow;
- wxString formattedDirectory = FreeFileSync::getFormattedDirectoryName(customDeletionDirectory.c_str()).c_str();
+ Zstring formattedDirectory = FreeFileSync::getFormattedDirectoryName(customDeletionDirectory);
if (formattedDirectory.empty())
- return wxEmptyString; //no valid directory for deletion specified (checked later)
+ return Zstring(); //no valid directory for deletion specified (checked later)
- if (!formattedDirectory.EndsWith(wxString(globalFunctions::FILE_NAME_SEPARATOR)))
+ if (!formattedDirectory.EndsWith(globalFunctions::FILE_NAME_SEPARATOR))
formattedDirectory += globalFunctions::FILE_NAME_SEPARATOR;
- formattedDirectory += sessionDir;
+ formattedDirectory += wxToZ(sessionDir);
//ensure that session directory does not yet exist (must be unique)
if (FreeFileSync::dirExists(formattedDirectory))
{
//if it's not unique, add a postfix number
int postfix = 1;
- while (FreeFileSync::dirExists(formattedDirectory + wxT("_") + globalFunctions::numberToWxString(postfix)))
+ while (FreeFileSync::dirExists(formattedDirectory + DefaultStr("_") + numberToZstring(postfix)))
++postfix;
- formattedDirectory += wxT("_") + globalFunctions::numberToWxString(postfix);
+ formattedDirectory += Zstring(DefaultStr("_")) + numberToZstring(postfix);
}
formattedDirectory += globalFunctions::FILE_NAME_SEPARATOR;
@@ -414,30 +360,30 @@ SyncProcess::SyncProcess(const bool copyFileSymLinks,
xmlAccess::OptionalDialogs& warnings,
const bool verifyCopiedFiles,
StatusHandler* handler) :
- m_copyFileSymLinks(copyFileSymLinks),
- m_traverseDirSymLinks(traverseDirSymLinks),
- m_verifyCopiedFiles(verifyCopiedFiles),
- m_warnings(warnings),
+ m_copyFileSymLinks(copyFileSymLinks),
+ m_traverseDirSymLinks(traverseDirSymLinks),
+ m_verifyCopiedFiles(verifyCopiedFiles),
+ m_warnings(warnings),
#ifdef FFS_WIN
- shadowCopyHandler(new ShadowCopy),
+ shadowCopyHandler(new ShadowCopy),
#endif
- statusUpdater(handler),
- txtCopyingFile(Zstring(_("Copying file %x to %y")).Replace(wxT("%x"), wxT("\"%x\""), false).Replace(wxT("%y"), wxT("\n\"%y\""), false)),
- txtOverwritingFile(Zstring(_("Copying file %x to %y overwriting target")).Replace(wxT("%x"), wxT("\"%x\""), false).Replace(wxT("%y"), wxT("\n\"%y\""), false)),
- txtCreatingFolder(Zstring(_("Creating folder %x")).Replace(wxT("%x"), wxT("\n\"%x\""), false)),
- txtDeletingFile(Zstring(_("Deleting file %x")).Replace(wxT("%x"), wxT("\n\"%x\""), false)),
- txtDeletingFolder(Zstring(_("Deleting folder %x")).Replace( wxT("%x"), wxT("\n\"%x\""), false)),
- txtMoveToRecycler(Zstring(_("Moving %x to Recycle Bin")).Replace(wxT("%x"), wxT("\"%x\""), false)),
- txtVerifying(Zstring(_("Verifying file %x")).Replace(wxT("%x"), wxT("\n\"%x\""), false))
+ statusUpdater(handler),
+ txtCopyingFile(wxToZ(_("Copying file %x to %y")).Replace(DefaultStr("%x"), DefaultStr("\"%x\""), false).Replace(DefaultStr("%y"), DefaultStr("\n\"%y\""), false)),
+ txtOverwritingFile(wxToZ(_("Copying file %x to %y overwriting target")).Replace(DefaultStr("%x"), DefaultStr("\"%x\""), false).Replace(DefaultStr("%y"), DefaultStr("\n\"%y\""), false)),
+ txtCreatingFolder(wxToZ(_("Creating folder %x")).Replace(DefaultStr("%x"), DefaultStr("\n\"%x\""), false)),
+ txtDeletingFile(wxToZ(_("Deleting file %x")).Replace(DefaultStr("%x"), DefaultStr("\n\"%x\""), false)),
+ txtDeletingFolder(wxToZ(_("Deleting folder %x")).Replace( DefaultStr("%x"), DefaultStr("\n\"%x\""), false)),
+ txtMoveToRecycler(wxToZ(_("Moving %x to Recycle Bin")).Replace(DefaultStr("%x"), DefaultStr("\"%x\""), false)),
+ txtVerifying(wxToZ(_("Verifying file %x")).Replace(DefaultStr("%x"), DefaultStr("\n\"%x\""), false))
{}
SyncProcess::DeletionHandling::DeletionHandling(const DeletionPolicy handleDel,
- const wxString& custDelFolder) :
- handleDeletion(handleDel),
- currentDelFolder(getSessionDeletionDir(custDelFolder).c_str()), //ends with path separator
- txtMoveFileUserDefined( Zstring(_("Moving file %x to user-defined directory %y")). Replace(wxT("%x"), wxT("\"%x\"\n"), false).Replace(wxT("%y"), Zstring(wxT("\"")) + custDelFolder.c_str() + wxT("\""), false)),
- txtMoveFolderUserDefined(Zstring(_("Moving folder %x to user-defined directory %y")).Replace(wxT("%x"), wxT("\"%x\"\n"), false).Replace(wxT("%y"), Zstring(wxT("\"")) + custDelFolder.c_str() + wxT("\""), false))
+ const Zstring& custDelFolder) :
+ handleDeletion(handleDel),
+ currentDelFolder(getSessionDeletionDir(custDelFolder)), //ends with path separator
+ txtMoveFileUserDefined( wxToZ(_("Moving file %x to user-defined directory %y")). Replace(DefaultStr("%x"), DefaultStr("\"%x\"\n"), false).Replace(DefaultStr("%y"), Zstring(DefaultStr("\"")) + custDelFolder + DefaultStr("\""), false)),
+ txtMoveFolderUserDefined(wxToZ(_("Moving folder %x to user-defined directory %y")).Replace(DefaultStr("%x"), DefaultStr("\"%x\"\n"), false).Replace(DefaultStr("%y"), Zstring(DefaultStr("\"")) + custDelFolder + DefaultStr("\""), false))
{}
@@ -476,7 +422,7 @@ void SyncProcess::removeFile(const FileMapping& fileObj, const DeletionHandling&
if (showStatusUpdate) //status information
{
statusText = txtDeletingFile;
- statusText.Replace(wxT("%x"), fileObj.getFullName<side>(), false);
+ statusText.Replace(DefaultStr("%x"), fileObj.getFullName<side>(), false);
statusUpdater->updateStatusText(statusText);
statusUpdater->requestUiRefresh(); //trigger display refresh
}
@@ -486,7 +432,7 @@ void SyncProcess::removeFile(const FileMapping& fileObj, const DeletionHandling&
if (showStatusUpdate) //status information
{
statusText = txtMoveToRecycler;
- statusText.Replace(wxT("%x"), fileObj.getFullName<side>(), false);
+ statusText.Replace(DefaultStr("%x"), fileObj.getFullName<side>(), false);
statusUpdater->updateStatusText(statusText);
statusUpdater->requestUiRefresh(); //trigger display refresh
}
@@ -498,7 +444,7 @@ void SyncProcess::removeFile(const FileMapping& fileObj, const DeletionHandling&
if (showStatusUpdate) //status information
{
statusText = delHandling.txtMoveFileUserDefined;
- statusText.Replace(wxT("%x"), fileObj.getFullName<side>(), false);
+ statusText.Replace(DefaultStr("%x"), fileObj.getFullName<side>(), false);
statusUpdater->updateStatusText(statusText);
statusUpdater->requestUiRefresh(); //trigger display refresh
}
@@ -530,14 +476,14 @@ void SyncProcess::synchronizeFile(FileMapping& fileObj, const DeletionHandling&
Zstring statusText;
Zstring target;
- switch (getSyncOperation(fileObj)) //evaluate comparison result and sync direction
+ switch (fileObj.getSyncOperation()) //evaluate comparison result and sync direction
{
case SO_CREATE_NEW_LEFT:
target = fileObj.getBaseDirPf<LEFT_SIDE>() + fileObj.getRelativeName<RIGHT_SIDE>();
statusText = txtCopyingFile;
- statusText.Replace(wxT("%x"), fileObj.getShortName<RIGHT_SIDE>(), false);
- statusText.Replace(wxT("%y"), target.BeforeLast(globalFunctions::FILE_NAME_SEPARATOR), false);
+ statusText.Replace(DefaultStr("%x"), fileObj.getShortName<RIGHT_SIDE>(), false);
+ statusText.Replace(DefaultStr("%y"), target.BeforeLast(globalFunctions::FILE_NAME_SEPARATOR), false);
statusUpdater->updateStatusText(statusText);
statusUpdater->requestUiRefresh(); //trigger display refresh
@@ -548,8 +494,8 @@ void SyncProcess::synchronizeFile(FileMapping& fileObj, const DeletionHandling&
target = fileObj.getBaseDirPf<RIGHT_SIDE>() + fileObj.getRelativeName<LEFT_SIDE>();
statusText = txtCopyingFile;
- statusText.Replace(wxT("%x"), fileObj.getShortName<LEFT_SIDE>(), false);
- statusText.Replace(wxT("%y"), target.BeforeLast(globalFunctions::FILE_NAME_SEPARATOR), false);
+ statusText.Replace(DefaultStr("%x"), fileObj.getShortName<LEFT_SIDE>(), false);
+ statusText.Replace(DefaultStr("%y"), target.BeforeLast(globalFunctions::FILE_NAME_SEPARATOR), false);
statusUpdater->updateStatusText(statusText);
statusUpdater->requestUiRefresh(); //trigger display refresh
@@ -566,8 +512,8 @@ void SyncProcess::synchronizeFile(FileMapping& fileObj, const DeletionHandling&
case SO_OVERWRITE_RIGHT:
statusText = txtOverwritingFile;
- statusText.Replace(wxT("%x"), fileObj.getShortName<LEFT_SIDE>(), false);
- statusText.Replace(wxT("%y"), fileObj.getFullName<RIGHT_SIDE>().BeforeLast(globalFunctions::FILE_NAME_SEPARATOR), false);
+ statusText.Replace(DefaultStr("%x"), fileObj.getShortName<LEFT_SIDE>(), false);
+ statusText.Replace(DefaultStr("%y"), fileObj.getFullName<RIGHT_SIDE>().BeforeLast(globalFunctions::FILE_NAME_SEPARATOR), false);
statusUpdater->updateStatusText(statusText);
statusUpdater->requestUiRefresh(); //trigger display refresh
@@ -577,8 +523,8 @@ void SyncProcess::synchronizeFile(FileMapping& fileObj, const DeletionHandling&
case SO_OVERWRITE_LEFT:
statusText = txtOverwritingFile;
- statusText.Replace(wxT("%x"), fileObj.getShortName<RIGHT_SIDE>(), false);
- statusText.Replace(wxT("%y"), fileObj.getFullName<LEFT_SIDE>().BeforeLast(globalFunctions::FILE_NAME_SEPARATOR), false);
+ statusText.Replace(DefaultStr("%x"), fileObj.getShortName<RIGHT_SIDE>(), false);
+ statusText.Replace(DefaultStr("%y"), fileObj.getFullName<LEFT_SIDE>().BeforeLast(globalFunctions::FILE_NAME_SEPARATOR), false);
statusUpdater->updateStatusText(statusText);
statusUpdater->requestUiRefresh(); //trigger display refresh
@@ -591,23 +537,12 @@ void SyncProcess::synchronizeFile(FileMapping& fileObj, const DeletionHandling&
return; //no update on processed data!
}
+ //update FileMapping
+ fileObj.synchronizeSides();
+
//progress indicator update
//indicator is updated only if file is sync'ed correctly (and if some sync was done)!
statusUpdater->updateProcessedData(1, 0); //processed data is communicated in subfunctions!
-
- //update FileMapping
- switch (fileObj.syncDir)
- {
- case SYNC_DIR_LEFT:
- fileObj.copyTo<LEFT_SIDE>();
- break;
- case SYNC_DIR_RIGHT:
- fileObj.copyTo<RIGHT_SIDE>();
- break;
- case SYNC_DIR_NONE:
- assert(!"if nothing's todo then why arrive here?");
- break;
- }
}
@@ -622,7 +557,7 @@ void SyncProcess::removeFolder(const DirMapping& dirObj, const DeletionHandling&
case FreeFileSync::DELETE_PERMANENTLY:
//status information
statusText = txtDeletingFolder;
- statusText.Replace(wxT("%x"), dirObj.getFullName<side>(), false);
+ statusText.Replace(DefaultStr("%x"), dirObj.getFullName<side>(), false);
statusUpdater->updateStatusText(statusText);
statusUpdater->requestUiRefresh(); //trigger display refresh
@@ -631,7 +566,7 @@ void SyncProcess::removeFolder(const DirMapping& dirObj, const DeletionHandling&
case FreeFileSync::MOVE_TO_RECYCLE_BIN:
//status information
statusText = txtMoveToRecycler;
- statusText.Replace(wxT("%x"), dirObj.getFullName<side>(), false);
+ statusText.Replace(DefaultStr("%x"), dirObj.getFullName<side>(), false);
statusUpdater->updateStatusText(statusText);
statusUpdater->requestUiRefresh(); //trigger display refresh
@@ -642,7 +577,7 @@ void SyncProcess::removeFolder(const DirMapping& dirObj, const DeletionHandling&
{
//status information
statusText = delHandling.txtMoveFolderUserDefined;
- statusText.Replace(wxT("%x"), dirObj.getFullName<side>(), false);
+ statusText.Replace(DefaultStr("%x"), dirObj.getFullName<side>(), false);
statusUpdater->updateStatusText(statusText);
statusUpdater->requestUiRefresh(); //trigger display refresh
@@ -675,19 +610,19 @@ void SyncProcess::synchronizeFolder(DirMapping& dirObj, const DeletionHandling&
Zstring target;
//synchronize folders:
- switch (getSyncOperation(dirObj)) //evaluate comparison result and sync direction
+ switch (dirObj.getSyncOperation()) //evaluate comparison result and sync direction
{
case SO_CREATE_NEW_LEFT:
target = dirObj.getBaseDirPf<LEFT_SIDE>() + dirObj.getRelativeName<RIGHT_SIDE>();
statusText = txtCreatingFolder;
- statusText.Replace(wxT("%x"), target, false);
+ statusText.Replace(DefaultStr("%x"), target, false);
statusUpdater->updateStatusText(statusText);
statusUpdater->requestUiRefresh(); //trigger display refresh
//some check to catch the error that directory on source has been deleted externally after "compare"...
if (!FreeFileSync::dirExists(dirObj.getFullName<RIGHT_SIDE>()))
- throw FileError(wxString(_("Error: Source directory does not exist anymore:")) + wxT("\n\"") + dirObj.getFullName<RIGHT_SIDE>() + wxT("\""));
+ throw FileError(wxString(_("Source directory does not exist anymore:")) + wxT("\n\"") + zToWx(dirObj.getFullName<RIGHT_SIDE>()) + wxT("\""));
createDirectory(target, dirObj.getFullName<RIGHT_SIDE>(), !m_traverseDirSymLinks); //traverse symlinks <=> !copy symlinks
break;
@@ -695,22 +630,38 @@ void SyncProcess::synchronizeFolder(DirMapping& dirObj, const DeletionHandling&
target = dirObj.getBaseDirPf<RIGHT_SIDE>() + dirObj.getRelativeName<LEFT_SIDE>();
statusText = txtCreatingFolder;
- statusText.Replace(wxT("%x"), target, false);
+ statusText.Replace(DefaultStr("%x"), target, false);
statusUpdater->updateStatusText(statusText);
statusUpdater->requestUiRefresh(); //trigger display refresh
//some check to catch the error that directory on source has been deleted externally after "compare"...
if (!FreeFileSync::dirExists(dirObj.getFullName<LEFT_SIDE>()))
- throw FileError(wxString(_("Error: Source directory does not exist anymore:")) + wxT("\n\"") + dirObj.getFullName<LEFT_SIDE>() + wxT("\""));
+ throw FileError(wxString(_("Source directory does not exist anymore:")) + wxT("\n\"") + zToWx(dirObj.getFullName<LEFT_SIDE>()) + wxT("\""));
createDirectory(target, dirObj.getFullName<LEFT_SIDE>(), !m_traverseDirSymLinks); //traverse symlinks <=> !copy symlinks
break;
case SO_DELETE_LEFT:
removeFolder<LEFT_SIDE>(dirObj, delHandling);
+ {
+ //progress indicator update: DON'T forget to notify about implicitly deleted objects!
+ const SyncStatistics subObjects(dirObj);
+ //...then remove everything
+ dirObj.subFiles.clear();
+ dirObj.subDirs.clear();
+ statusUpdater->updateProcessedData(subObjects.getCreate() + subObjects.getOverwrite() + subObjects.getDelete(), subObjects.getDataToProcess().ToDouble());
+ }
break;
case SO_DELETE_RIGHT:
removeFolder<RIGHT_SIDE>(dirObj, delHandling);
+ {
+ //progress indicator update: DON'T forget to notify about implicitly deleted objects!
+ const SyncStatistics subObjects(dirObj);
+ //...then remove everything
+ dirObj.subFiles.clear();
+ dirObj.subDirs.clear();
+ statusUpdater->updateProcessedData(subObjects.getCreate() + subObjects.getOverwrite() + subObjects.getDelete(), subObjects.getDataToProcess().ToDouble());
+ }
break;
case SO_OVERWRITE_RIGHT:
@@ -721,23 +672,12 @@ void SyncProcess::synchronizeFolder(DirMapping& dirObj, const DeletionHandling&
return; //no update on processed data!
}
+ //update DirMapping
+ dirObj.synchronizeSides();
+
//progress indicator update
//indicator is updated only if directory is sync'ed correctly (and if some work was done)!
statusUpdater->updateProcessedData(1, 0); //each call represents one processed file
-
- //update DirMapping
- switch (dirObj.syncDir)
- {
- case SYNC_DIR_LEFT:
- dirObj.copyTo<LEFT_SIDE>();
- break;
- case SYNC_DIR_RIGHT:
- dirObj.copyTo<RIGHT_SIDE>();
- break;
- case SYNC_DIR_NONE:
- assert(!"if nothing's todo then why arrive here?");
- break;
- }
}
@@ -745,7 +685,7 @@ inline
bool deletionImminent(const FileSystemObject& fsObj)
{
//test if current sync-line will result in deletion of files -> used to avoid disc space bottlenecks
- const SyncOperation op = FreeFileSync::getSyncOperation(fsObj);
+ const SyncOperation op = fsObj.getSyncOperation();
return op == FreeFileSync::SO_DELETE_LEFT || op == FreeFileSync::SO_DELETE_RIGHT;
}
@@ -754,7 +694,7 @@ class RemoveInvalid
{
public:
RemoveInvalid(HierarchyObject& hierObj) :
- hierObj_(hierObj) {}
+ hierObj_(hierObj) {}
~RemoveInvalid()
{
@@ -771,24 +711,25 @@ class SyncProcess::SyncRecursively
{
public:
SyncRecursively(const SyncProcess* const syncProc, const SyncProcess::DeletionHandling& delHandling) :
- syncProc_(syncProc),
- delHandling_(delHandling) {}
+ syncProc_(syncProc),
+ delHandling_(delHandling) {}
void execute(HierarchyObject& hierObj)
{
//enforce removal of invalid entries (where both sides are empty)
RemoveInvalid dummy(hierObj); //non-recursive
- //synchronize folders:
- for (HierarchyObject::SubDirMapping::iterator i = hierObj.subDirs.begin(); i != hierObj.subDirs.end(); ++i)
+ //synchronize files:
+ for (HierarchyObject::SubFileMapping::iterator i = hierObj.subFiles.begin(); i != hierObj.subFiles.end(); ++i)
{
- if (deleteOnly) //no need, to process folders more than once!
+ if ( ( deleteOnly && deletionImminent(*i)) ||
+ (!deleteOnly && !deletionImminent(*i)))
{
while (true)
{
try
{
- syncProc_->synchronizeFolder(*i, delHandling_);
+ syncProc_->synchronizeFile(*i, delHandling_);
break;
}
catch (FileError& error)
@@ -799,33 +740,27 @@ public:
syncProc_->statusUpdater->requestUiRefresh(true);
ErrorHandler::Response rv = syncProc_->statusUpdater->reportError(error.show());
- if (rv == ErrorHandler::IGNORE_ERROR)
+ if ( rv == ErrorHandler::IGNORE_ERROR)
break;
else if (rv == ErrorHandler::RETRY)
- ; //continue with loop
+ ; //continue with loop
else
- assert (false);
+ throw std::logic_error("Programming Error: Unknown return value!");
}
}
}
-
- //recursive synchronization: don't recurse into already deleted subdirectories
- if (!i->isEmpty())
- execute(*i);
}
-
- //synchronize files:
- for (HierarchyObject::SubFileMapping::iterator i = hierObj.subFiles.begin(); i != hierObj.subFiles.end(); ++i)
+ //synchronize folders:
+ for (HierarchyObject::SubDirMapping::iterator i = hierObj.subDirs.begin(); i != hierObj.subDirs.end(); ++i)
{
- if ( ( deleteOnly && deletionImminent(*i)) ||
- (!deleteOnly && !deletionImminent(*i)))
+ if (deleteOnly) //no need, to process folders more than once!
{
while (true)
{
try
{
- syncProc_->synchronizeFile(*i, delHandling_);
+ syncProc_->synchronizeFolder(*i, delHandling_);
break;
}
catch (FileError& error)
@@ -836,15 +771,19 @@ public:
syncProc_->statusUpdater->requestUiRefresh(true);
ErrorHandler::Response rv = syncProc_->statusUpdater->reportError(error.show());
- if ( rv == ErrorHandler::IGNORE_ERROR)
+ if (rv == ErrorHandler::IGNORE_ERROR)
break;
else if (rv == ErrorHandler::RETRY)
- ; //continue with loop
+ ; //continue with loop
else
- assert (false);
+ throw std::logic_error("Programming Error: Unknown return value!");
}
}
}
+
+ //recursive synchronization:
+ //if (!i->isEmpty()) -> not necessary, deleted folders have no sub-objects at this point
+ execute(*i);
}
}
@@ -854,12 +793,73 @@ private:
};
+template <typename Function>
+inline
+void tryReportingError(StatusHandler& handler, Function cmd)
+{
+ while (true)
+ {
+ try
+ {
+ cmd();
+ break;
+ }
+ catch (FileError& error)
+ {
+ handler.requestUiRefresh(); //may throw!
+
+ ErrorHandler::Response rv = handler.reportError(error.show()); //may throw!
+ if ( rv == ErrorHandler::IGNORE_ERROR)
+ break;
+ else if (rv == ErrorHandler::RETRY)
+ ; //continue with loop
+ else
+ throw std::logic_error("Programming Error: Unknown return value!");
+ }
+ }
+}
+
+
+class UpdateDatabase
+{
+public:
+ UpdateDatabase(const BaseDirMapping& baseMap, StatusHandler& statusHandler) :
+ baseMap_(baseMap),
+ statusHandler_(statusHandler) {}
+
+ //update sync database after synchronization is finished
+ void updateNow()
+ {
+ //these calls may throw!
+ tryReportingError(statusHandler_, boost::bind(saveToDisk, boost::cref(baseMap_), LEFT_SIDE, baseMap_.getDBFilename<LEFT_SIDE>()));
+ tryReportingError(statusHandler_, boost::bind(saveToDisk, boost::cref(baseMap_), RIGHT_SIDE, baseMap_.getDBFilename<RIGHT_SIDE>()));
+ };
+ //_("You can ignore the error to skip current folder pair."));
+
+private:
+ const BaseDirMapping& baseMap_;
+ StatusHandler& statusHandler_;
+};
+
+
+//avoid data loss when source directory doesn't (temporarily?) exist anymore AND user chose to ignore errors (else we wouldn't arrive here)
+bool dataLossPossible(const Zstring& dirName, const SyncStatistics& folderPairStat)
+{
+ return folderPairStat.getCreate() + folderPairStat.getOverwrite() + folderPairStat.getConflict() == 0 &&
+ folderPairStat.getDelete() > 0 && //deletions only... (respect filtered items!)
+ !dirName.empty() && !FreeFileSync::dirExists(dirName);
+}
+
+
void SyncProcess::startSynchronizationProcess(const std::vector<FolderPairSyncCfg>& syncConfig, FolderComparison& folderCmp)
{
#ifndef __WXDEBUG__
wxLogNull noWxLogs; //prevent wxWidgets logging
#endif
+ //PERF_START;
+
+
//inform about the total amount of data that will be processed from now on
const SyncStatistics statisticsTotal(folderCmp);
@@ -898,12 +898,24 @@ 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 (dataLossPossible(j->getBaseDir<LEFT_SIDE>(), statisticsFolderPair))
+ {
+ statusUpdater->reportFatalError(wxString(_("Source directory does not exist anymore:")) + wxT("\n\"") + zToWx(j->getBaseDir<LEFT_SIDE>()) + wxT("\""));
+ return; //should be obsolete!
+ }
+ if (dataLossPossible(j->getBaseDir<RIGHT_SIDE>(), statisticsFolderPair))
+ {
+ statusUpdater->reportFatalError(wxString(_("Source directory does not exist anymore:")) + wxT("\n\"") + zToWx(j->getBaseDir<RIGHT_SIDE>()) + wxT("\"") );
+ return; //should be obsolete!
+ }
+
//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") +
- j->getBaseDir<LEFT_SIDE>() + wxT(" <-> ") + wxT("\n") +
- j->getBaseDir<RIGHT_SIDE>() + wxT("\n\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);
}
@@ -912,11 +924,11 @@ void SyncProcess::startSynchronizationProcess(const std::vector<FolderPairSyncCf
const std::pair<wxLongLong, wxLongLong> spaceNeeded = freeDiskSpaceNeeded(*j, folderPairCfg.handleDeletion);
wxLongLong freeDiskSpaceLeft;
- if (wxGetDiskSpace(j->getBaseDir<LEFT_SIDE>().c_str(), NULL, &freeDiskSpaceLeft))
+ if (wxGetDiskSpace(zToWx(j->getBaseDir<LEFT_SIDE>()), NULL, &freeDiskSpaceLeft))
{
if (freeDiskSpaceLeft < spaceNeeded.first)
statusUpdater->reportWarning(wxString(_("Not enough free disk space available in:")) + wxT("\n") +
- wxT("\"") + j->getBaseDir<LEFT_SIDE>() + wxT("\"\n\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);
@@ -924,11 +936,11 @@ void SyncProcess::startSynchronizationProcess(const std::vector<FolderPairSyncCf
//check for sufficient free diskspace in right directory
wxLongLong freeDiskSpaceRight;
- if (wxGetDiskSpace(j->getBaseDir<RIGHT_SIDE>().c_str(), NULL, &freeDiskSpaceRight))
+ if (wxGetDiskSpace(zToWx(j->getBaseDir<RIGHT_SIDE>()), NULL, &freeDiskSpaceRight))
{
if (freeDiskSpaceRight < spaceNeeded.second)
statusUpdater->reportWarning(wxString(_("Not enough free disk space available in:")) + wxT("\n") +
- wxT("\"") + j->getBaseDir<RIGHT_SIDE>() + wxT("\"\n\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);
@@ -954,16 +966,27 @@ void SyncProcess::startSynchronizationProcess(const std::vector<FolderPairSyncCf
//generate name of alternate deletion directory (unique for session AND folder pair)
const DeletionHandling currentDelHandling(folderPairCfg.handleDeletion, folderPairCfg.custDelFolder);
+//------------------------------------------------------------------------------------------
//execute synchronization recursively
//loop through all files twice; reason: first delete, then copy
SyncRecursively<true>( this, currentDelHandling).execute(*j);
SyncRecursively<false>(this, currentDelHandling).execute(*j);
+//------------------------------------------------------------------------------------------
+
+ //update synchronization database (automatic sync only)
+ if (folderPairCfg.updateSyncDB)
+ {
+ UpdateDatabase syncDB(*j, *statusUpdater);
+ statusUpdater->updateStatusText(wxToZ(_("Generating database...")));
+ statusUpdater->forceUiRefresh();
+ syncDB.updateNow();
+ }
}
}
catch (const std::exception& e)
{
- statusUpdater->reportFatalError(wxString::From8BitData(e.what()));
+ statusUpdater->reportFatalError(wxString::FromAscii(e.what()));
return; //should be obsolete!
}
}
@@ -977,8 +1000,8 @@ class WhileCopying : public FreeFileSync::CopyFileCallback //callback functional
public:
WhileCopying(wxLongLong& bytesTransferredLast, StatusHandler* statusHandler) :
- m_bytesTransferredLast(bytesTransferredLast),
- m_statusHandler(statusHandler) {}
+ m_bytesTransferredLast(bytesTransferredLast),
+ m_statusHandler(statusHandler) {}
virtual Response updateCopyStatus(const wxULongLong& totalBytesTransferred)
{
@@ -1049,22 +1072,6 @@ void SyncProcess::copyFileUpdating(const Zstring& source, const Zstring& target,
//--------------------- data verification -------------------------
-struct MemoryAllocator
-{
- MemoryAllocator()
- {
- buffer = new unsigned char[bufferSize];
- }
-
- ~MemoryAllocator()
- {
- delete [] buffer;
- }
-
- static const unsigned int bufferSize = 512 * 1024; //512 kb seems to be the perfect buffer size
- unsigned char* buffer;
-};
-
//callback functionality for status updates while verifying
class VerifyCallback
@@ -1077,29 +1084,38 @@ public:
void verifyFiles(const Zstring& source, const Zstring& target, VerifyCallback* callback) // throw (FileError)
{
- static MemoryAllocator memory1;
- static MemoryAllocator memory2;
+ const unsigned int BUFFER_SIZE = 512 * 1024; //512 kb seems to be the perfect buffer size
+ static boost::scoped_array<unsigned char> memory1(new unsigned char[BUFFER_SIZE]);
+ static boost::scoped_array<unsigned char> memory2(new unsigned char[BUFFER_SIZE]);
+#ifdef FFS_WIN
wxFile file1(source.c_str(), wxFile::read); //don't use buffered file input for verification!
+#elif defined FFS_LINUX
+ wxFile file1(::open(source.c_str(), O_RDONLY)); //utilize UTF-8 filename
+#endif
if (!file1.IsOpened())
- throw FileError(wxString(_("Error opening file:")) + wxT(" \"") + source.c_str() + wxT("\""));
+ throw FileError(wxString(_("Error opening file:")) + wxT(" \"") + zToWx(source) + wxT("\""));
- wxFile file2(target.c_str(), wxFile::read);
+#ifdef FFS_WIN
+ wxFile file2(target.c_str(), wxFile::read); //don't use buffered file input for verification!
+#elif defined FFS_LINUX
+ wxFile file2(::open(target.c_str(), O_RDONLY)); //utilize UTF-8 filename
+#endif
if (!file2.IsOpened()) //NO cleanup necessary for (wxFile) file1
- throw FileError(wxString(_("Error opening file:")) + wxT(" \"") + target.c_str() + wxT("\""));
+ throw FileError(wxString(_("Error opening file:")) + wxT(" \"") + zToWx(target) + wxT("\""));
do
{
- const size_t length1 = file1.Read(memory1.buffer, MemoryAllocator::bufferSize);
- if (file1.Error()) throw FileError(wxString(_("Error reading file:")) + wxT(" \"") + source.c_str() + wxT("\""));
+ const size_t length1 = file1.Read(memory1.get(), BUFFER_SIZE);
+ if (file1.Error()) throw FileError(wxString(_("Error reading file:")) + wxT(" \"") + zToWx(source) + wxT("\""));
- const size_t length2 = file2.Read(memory2.buffer, MemoryAllocator::bufferSize);
- if (file2.Error()) throw FileError(wxString(_("Error reading file:")) + wxT(" \"") + target.c_str() + wxT("\""));
+ const size_t length2 = file2.Read(memory2.get(), BUFFER_SIZE);
+ if (file2.Error()) throw FileError(wxString(_("Error reading file:")) + wxT(" \"") + zToWx(target) + wxT("\""));
- if (length1 != length2 || ::memcmp(memory1.buffer, memory2.buffer, length1) != 0)
+ if (length1 != length2 || ::memcmp(memory1.get(), memory2.get(), length1) != 0)
{
const wxString errorMsg = wxString(_("Data verification error: Source and target file have different content!")) + wxT("\n");
- throw FileError(errorMsg + wxT("\"") + source + wxT("\" -> \n\"") + target + wxT("\""));
+ throw FileError(errorMsg + wxT("\"") + zToWx(source) + wxT("\" -> \n\"") + zToWx(target) + wxT("\""));
}
//send progress updates
@@ -1110,7 +1126,7 @@ void verifyFiles(const Zstring& source, const Zstring& target, VerifyCallback* c
if (!file2.Eof())
{
const wxString errorMsg = wxString(_("Data verification error: Source and target file have different content!")) + wxT("\n");
- throw FileError(errorMsg + wxT("\"") + source + wxT("\" -> \n\"") + target + wxT("\""));
+ throw FileError(errorMsg + wxT("\"") + zToWx(source) + wxT("\" -> \n\"") + zToWx(target) + wxT("\""));
}
}
@@ -1133,7 +1149,7 @@ private:
void SyncProcess::verifyFileCopy(const Zstring& source, const Zstring& target) const
{
Zstring statusText = txtVerifying;
- statusText.Replace(wxT("%x"), target, false);
+ statusText.Replace(DefaultStr("%x"), target, false);
statusUpdater->updateStatusText(statusText);
statusUpdater->requestUiRefresh(); //trigger display refresh
@@ -1154,3 +1170,9 @@ void SyncProcess::verifyFileCopy(const Zstring& source, const Zstring& target) c
}
}
}
+
+
+
+
+
+
bgstack15