summaryrefslogtreecommitdiff
path: root/synchronization.cpp
diff options
context:
space:
mode:
authorDaniel Wilhelm <daniel@wili.li>2014-04-18 17:07:43 +0200
committerDaniel Wilhelm <daniel@wili.li>2014-04-18 17:07:43 +0200
commit4226e548662339ea1ca37b45385a7cf9b237ff1e (patch)
tree9a3fa54b85d97f05164e41bdb96b82f748a37342 /synchronization.cpp
parent3.7 (diff)
downloadFreeFileSync-4226e548662339ea1ca37b45385a7cf9b237ff1e.tar.gz
FreeFileSync-4226e548662339ea1ca37b45385a7cf9b237ff1e.tar.bz2
FreeFileSync-4226e548662339ea1ca37b45385a7cf9b237ff1e.zip
3.8
Diffstat (limited to 'synchronization.cpp')
-rw-r--r--synchronization.cpp410
1 files changed, 267 insertions, 143 deletions
diff --git a/synchronization.cpp b/synchronization.cpp
index dfc68fe7..a071489d 100644
--- a/synchronization.cpp
+++ b/synchronization.cpp
@@ -111,8 +111,13 @@ void SyncStatistics::getNumbersRecursively(const HierarchyObject& hierObj)
std::for_each(hierObj.useSubFiles().begin(), hierObj.useSubFiles().end(),
boost::bind(&SyncStatistics::getFileNumbers, this, _1));
- rowsTotal += hierObj.useSubDirs().size();
+ //process symlinks
+ std::for_each(hierObj.useSubLinks().begin(), hierObj.useSubLinks().end(),
+ boost::bind(&SyncStatistics::getLinkNumbers, this, _1));
+
+ rowsTotal += hierObj.useSubDirs(). size();
rowsTotal += hierObj.useSubFiles().size();
+ rowsTotal += hierObj.useSubLinks().size();
}
@@ -149,14 +154,56 @@ void SyncStatistics::getFileNumbers(const FileMapping& fileObj)
dataToProcess += fileObj.getFileSize<LEFT_SIDE>();
break;
+ case SO_UNRESOLVED_CONFLICT:
+ ++conflict;
+ if (firstConflicts.size() < 3) //save the first 3 conflict texts
+ firstConflicts.push_back(std::make_pair(fileObj.getObjRelativeName(), fileObj.getSyncOpConflict()));
+ break;
+
case SO_DO_NOTHING:
case SO_EQUAL:
break;
+ }
+}
+
+
+inline
+void SyncStatistics::getLinkNumbers(const SymLinkMapping& linkObj)
+{
+ switch (linkObj.getSyncOperation()) //evaluate comparison result and sync direction
+ {
+ case SO_CREATE_NEW_LEFT:
+ ++createLeft;
+ break;
+
+ case SO_CREATE_NEW_RIGHT:
+ ++createRight;
+ break;
+
+ case SO_DELETE_LEFT:
+ ++deleteLeft;
+ break;
+
+ case SO_DELETE_RIGHT:
+ ++deleteRight;
+ break;
+
+ case SO_OVERWRITE_LEFT:
+ ++overwriteLeft;
+ break;
+
+ case SO_OVERWRITE_RIGHT:
+ ++overwriteRight;
+ break;
case SO_UNRESOLVED_CONFLICT:
++conflict;
if (firstConflicts.size() < 3) //save the first 3 conflict texts
- firstConflicts.push_back(std::make_pair(fileObj.getObjRelativeName(), fileObj.getSyncOpConflict()));
+ firstConflicts.push_back(std::make_pair(linkObj.getObjRelativeName(), linkObj.getSyncOpConflict()));
+ break;
+
+ case SO_DO_NOTHING:
+ case SO_EQUAL:
break;
}
}
@@ -189,6 +236,11 @@ void SyncStatistics::getDirNumbers(const DirMapping& dirObj)
break;
case SO_UNRESOLVED_CONFLICT:
+ ++conflict;
+ if (firstConflicts.size() < 3) //save the first 3 conflict texts
+ firstConflicts.push_back(std::make_pair(dirObj.getObjRelativeName(), dirObj.getSyncOpConflict()));
+ break;
+
case SO_DO_NOTHING:
case SO_EQUAL:
break;
@@ -289,6 +341,8 @@ private:
break;
}
+ //symbolic links
+ //[...]
//recurse into sub-dirs
std::for_each(hierObj.useSubDirs().begin(), hierObj.useSubDirs().end(), boost::bind(&DiskSpaceNeeded::processRecursively, this, _1));
@@ -342,7 +396,8 @@ std::pair<wxLongLong, wxLongLong> freeDiskSpaceNeeded(
}
//------------------------------------------------------------------------------------------------------------
-
+namespace
+{
bool synchronizationNeeded(const SyncStatistics& statisticsTotal)
{
return statisticsTotal.getCreate() +
@@ -351,6 +406,7 @@ bool synchronizationNeeded(const SyncStatistics& statisticsTotal)
//conflicts (unless excluded) justify a sync! Also note: if this method returns false, no warning about unresolved conflicts were shown!
statisticsTotal.getConflict() != 0;
}
+}
bool FreeFileSync::synchronizationNeeded(const FolderComparison& folderCmp)
@@ -453,14 +509,10 @@ Zstring getSessionDeletionDir(const Zstring& deletionDirectory, const Zstring& p
}
-SyncProcess::SyncProcess(bool copyFileSymLinks,
- bool traverseDirSymLinks,
- xmlAccess::OptionalDialogs& warnings,
+SyncProcess::SyncProcess(xmlAccess::OptionalDialogs& warnings,
bool verifyCopiedFiles,
bool copyLockedFiles,
StatusHandler& handler) :
- m_copyFileSymLinks(copyFileSymLinks),
- m_traverseDirSymLinks(traverseDirSymLinks),
m_verifyCopiedFiles(verifyCopiedFiles),
copyLockedFiles_(copyLockedFiles),
m_warnings(warnings),
@@ -468,6 +520,23 @@ SyncProcess::SyncProcess(bool copyFileSymLinks,
//--------------------------------------------------------------------------------------------------------------
+namespace
+{
+void ensureExists(const Zstring& dirname, const Zstring& templateDir = Zstring()) //throw (FileError)
+{
+ if (!dirname.empty()) //kind of pathological ?
+ if (!FreeFileSync::dirExists(dirname))
+ //lazy creation of alternate deletion directory (including super-directories of targetFile)
+ FreeFileSync::createDirectory(dirname, templateDir, false);
+ /*symbolic link handling:
+ if "not traversing symlinks": fullName == c:\syncdir<symlinks>\some\dirs\leaf<symlink>
+ => setting irrelevant
+ if "traversing symlinks": fullName == c:\syncdir<symlinks>\some\dirs<symlinks>\leaf<symlink>
+ => setting NEEDS to be false: We want to move leaf, therefore symlinks in "some\dirs" must not interfere */
+}
+}
+
+
class DeletionHandling
{
public:
@@ -479,23 +548,24 @@ public:
~DeletionHandling(); //always (try to) clean up, even if synchronization is aborted!
//clean-up temporary directory (recycler bin optimization)
- void tryCleanup() const; //throw FileError() -> call this in non-exceptional coding, i.e. after Sync somewhere!
+ void tryCleanup() const; //throw (FileError) -> call this in non-exceptional coding, i.e. after Sync somewhere!
template <FreeFileSync::SelectedSide side>
- void removeFile(const FileMapping& fileObj) const; //throw FileError()
+ void removeFile(const FileSystemObject& fileObj) const; //throw (FileError)
template <FreeFileSync::SelectedSide side>
- void removeFolder(const DirMapping& dirObj) const; //throw FileError()
+ void removeFolder(const FileSystemObject& dirObj) const; //throw (FileError)
const Zstring& getTxtRemovingFile() const; //status text templates
+ const Zstring& getTxtRemovingSymLink() const;
const Zstring& getTxtRemovingDir() const; //status text templates
private:
template <SelectedSide side>
const Zstring& getSessionDir() const;
- void tryCleanupLeft() const; //throw FileError()
- void tryCleanupRight() const; //throw FileError()
+ void tryCleanupLeft() const; //throw (FileError)
+ void tryCleanupRight() const; //throw (FileError)
const DeletionPolicy deletionType;
StatusHandler& statusUpdater_;
@@ -505,6 +575,7 @@ private:
//preloaded status texts:
Zstring txtRemovingFile;
+ Zstring txtRemovingSymlink;
Zstring txtRemovingDirectory;
};
@@ -521,6 +592,7 @@ DeletionHandling::DeletionHandling(const DeletionPolicy handleDel,
{
case DELETE_PERMANENTLY:
txtRemovingFile = wxToZ(_("Deleting file %x")).Replace(DefaultStr("%x"), DefaultStr("\n\"%x\""), false);
+ txtRemovingSymlink = wxToZ(_("Deleting Symbolic Link %x")).Replace(DefaultStr("%x"), DefaultStr("\n\"%x\""), false);
txtRemovingDirectory = wxToZ(_("Deleting folder %x")).Replace( DefaultStr("%x"), DefaultStr("\n\"%x\""), false);
break;
@@ -528,14 +600,15 @@ DeletionHandling::DeletionHandling(const DeletionPolicy handleDel,
sessionDelDirLeft = getSessionDeletionDir(baseDirLeft, DefaultStr("FFS "));
sessionDelDirRight = getSessionDeletionDir(baseDirRight, DefaultStr("FFS "));
- txtRemovingFile = txtRemovingDirectory = wxToZ(_("Moving %x to Recycle Bin")).Replace(DefaultStr("%x"), DefaultStr("\"%x\""), false);
+ txtRemovingFile = txtRemovingSymlink = txtRemovingDirectory = wxToZ(_("Moving %x to Recycle Bin")).Replace(DefaultStr("%x"), DefaultStr("\"%x\""), false);
break;
case MOVE_TO_CUSTOM_DIRECTORY:
sessionDelDirLeft = sessionDelDirRight = getSessionDeletionDir(custDelFolder);
- txtRemovingFile = wxToZ(_("Moving file %x to user-defined directory %y")). Replace(DefaultStr("%x"), DefaultStr("\"%x\"\n"), false).Replace(DefaultStr("%y"), Zstring(DefaultStr("\"")) + custDelFolder + DefaultStr("\""), false);
- txtRemovingDirectory = wxToZ(_("Moving folder %x to user-defined directory %y")).Replace(DefaultStr("%x"), DefaultStr("\"%x\"\n"), false).Replace(DefaultStr("%y"), Zstring(DefaultStr("\"")) + custDelFolder + DefaultStr("\""), false);
+ txtRemovingFile = wxToZ(_("Moving file %x to user-defined directory %y")). Replace(DefaultStr("%x"), DefaultStr("\"%x\"\n"), false).Replace(DefaultStr("%y"), Zstring(DefaultStr("\"")) + custDelFolder + DefaultStr("\""), false);
+ txtRemovingDirectory = wxToZ(_("Moving folder %x to user-defined directory %y")). Replace(DefaultStr("%x"), DefaultStr("\"%x\"\n"), false).Replace(DefaultStr("%y"), Zstring(DefaultStr("\"")) + custDelFolder + DefaultStr("\""), false);
+ txtRemovingSymlink = wxToZ(_("Moving Symbolic Link %x to user-defined directory %y")).Replace(DefaultStr("%x"), DefaultStr("\"%x\"\n"), false).Replace(DefaultStr("%y"), Zstring(DefaultStr("\"")) + custDelFolder + DefaultStr("\""), false);
break;
}
}
@@ -564,14 +637,14 @@ void DeletionHandling::tryCleanup() const //throw(AbortThisProcess)
}
-void DeletionHandling::tryCleanupLeft() const //throw FileError()
+void DeletionHandling::tryCleanupLeft() const //throw (FileError)
{
if (deletionType == MOVE_TO_RECYCLE_BIN) //clean-up temporary directory (recycle bin)
FreeFileSync::moveToRecycleBin(sessionDelDirLeft.BeforeLast(globalFunctions::FILE_NAME_SEPARATOR)); //throw (FileError)
}
-void DeletionHandling::tryCleanupRight() const //throw FileError()
+void DeletionHandling::tryCleanupRight() const //throw (FileError)
{
if (deletionType == MOVE_TO_RECYCLE_BIN) //clean-up temporary directory (recycle bin)
FreeFileSync::moveToRecycleBin(sessionDelDirRight.BeforeLast(globalFunctions::FILE_NAME_SEPARATOR)); //throw (FileError)
@@ -592,6 +665,13 @@ const Zstring& DeletionHandling::getTxtRemovingDir() const
}
+inline
+const Zstring& DeletionHandling::getTxtRemovingSymLink() const
+{
+ return txtRemovingSymlink;
+}
+
+
template <>
inline
const Zstring& DeletionHandling::getSessionDir<LEFT_SIDE>() const
@@ -630,7 +710,7 @@ private:
template <FreeFileSync::SelectedSide side>
-void DeletionHandling::removeFile(const FileMapping& fileObj) const
+void DeletionHandling::removeFile(const FileSystemObject& fileObj) const
{
switch (deletionType)
{
@@ -644,12 +724,7 @@ void DeletionHandling::removeFile(const FileMapping& fileObj) const
const Zstring targetFile = getSessionDir<side>() + fileObj.getRelativeName<side>(); //altDeletionDir ends with path separator
const Zstring targetDir = targetFile.BeforeLast(globalFunctions::FILE_NAME_SEPARATOR);
- if (!FreeFileSync::dirExists(targetDir))
- {
- if (!targetDir.empty()) //kind of pathological ?
- //lazy creation of alternate deletion directory (including super-directories of targetFile)
- FreeFileSync::createDirectory(targetDir, Zstring(), false);
- }
+ ensureExists(targetDir); //throw (FileError)
try //rename file: no copying!!!
{
@@ -671,17 +746,7 @@ void DeletionHandling::removeFile(const FileMapping& fileObj) const
const Zstring targetFile = getSessionDir<side>() + fileObj.getRelativeName<side>(); //altDeletionDir ends with path separator
const Zstring targetDir = targetFile.BeforeLast(globalFunctions::FILE_NAME_SEPARATOR);
- if (!FreeFileSync::dirExists(targetDir))
- {
- if (!targetDir.empty()) //kind of pathological ?
- //lazy creation of alternate deletion directory (including super-directories of targetFile)
- FreeFileSync::createDirectory(targetDir, Zstring(), false);
- /*symbolic link handling:
- if "not traversing symlinks": fullName == c:\syncdir<symlinks>\some\dirs\leaf<symlink>
- => setting irrelevant
- if "traversing symlinks": fullName == c:\syncdir<symlinks>\some\dirs<symlinks>\leaf<symlink>
- => setting NEEDS to be false: We want to move leaf, therefore symlinks in "some\dirs" must not interfere */
- }
+ ensureExists(targetDir); //throw (FileError)
MoveFileCallbackImpl callBack(statusUpdater_); //if file needs to be copied we need callback functionality to update screen and offer abort
FreeFileSync::moveFile(fileObj.getFullName<side>(), targetFile, &callBack);
@@ -692,7 +757,7 @@ void DeletionHandling::removeFile(const FileMapping& fileObj) const
template <FreeFileSync::SelectedSide side>
-void DeletionHandling::removeFolder(const DirMapping& dirObj) const
+void DeletionHandling::removeFolder(const FileSystemObject& dirObj) const
{
switch (deletionType)
{
@@ -706,12 +771,7 @@ void DeletionHandling::removeFolder(const DirMapping& dirObj) const
const Zstring targetDir = getSessionDir<side>() + dirObj.getRelativeName<side>();
const Zstring targetSuperDir = targetDir.BeforeLast(globalFunctions::FILE_NAME_SEPARATOR);
- if (!FreeFileSync::dirExists(targetSuperDir))
- {
- if (!targetSuperDir.empty()) //kind of pathological ?
- //lazy creation of alternate deletion directory (including super-directories of targetFile)
- FreeFileSync::createDirectory(targetSuperDir, Zstring(), false);
- }
+ ensureExists(targetSuperDir); //throw (FileError)
try //rename directory: no copying!!!
{
@@ -734,17 +794,7 @@ void DeletionHandling::removeFolder(const DirMapping& dirObj) const
const Zstring targetDir = getSessionDir<side>() + dirObj.getRelativeName<side>();
const Zstring targetSuperDir = targetDir.BeforeLast(globalFunctions::FILE_NAME_SEPARATOR);
- if (!FreeFileSync::dirExists(targetSuperDir))
- {
- if (!targetSuperDir.empty()) //kind of pathological ?
- //lazy creation of alternate deletion directory (including super-directories of targetFile)
- FreeFileSync::createDirectory(targetSuperDir, Zstring(), false);
- /*symbolic link handling:
- if "not traversing symlinks": fullName == c:\syncdir<symlinks>\some\dirs\leaf<symlink>
- => setting irrelevant
- if "traversing symlinks": fullName == c:\syncdir<symlinks>\some\dirs<symlinks>\leaf<symlink>
- => setting NEEDS to be false: We want to move leaf, therefore symlinks in "some\dirs" must not interfere */
- }
+ ensureExists(targetSuperDir); //throw (FileError)
MoveFileCallbackImpl callBack(statusUpdater_); //if files need to be copied, we need callback functionality to update screen and offer abort
FreeFileSync::moveDirectory(dirObj.getFullName<side>(), targetDir, true, &callBack);
@@ -818,13 +868,13 @@ public:
shadowCopyHandler_(shadowCopyHandler),
#endif
delHandling_(delHandling),
- copyFileSymLinks_(syncProc.m_copyFileSymLinks),
- traverseDirSymLinks_(syncProc.m_traverseDirSymLinks),
verifyCopiedFiles_(syncProc.m_verifyCopiedFiles),
- 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)),
- txtVerifying(wxToZ(_("Verifying file %x")).Replace(DefaultStr("%x"), DefaultStr("\n\"%x\""), false)) {}
+ txtCopyingFile (wxToZ(_("Copying file %x to %y")). Replace(DefaultStr("%x"), DefaultStr("\"%x\""), false).Replace(DefaultStr("%y"), DefaultStr("\n\"%y\""), false)),
+ txtCopyingLink (wxToZ(_("Copying Symbolic Link %x to %y")).Replace(DefaultStr("%x"), DefaultStr("\"%x\""), false).Replace(DefaultStr("%y"), DefaultStr("\n\"%y\""), false)),
+ txtOverwritingFile(wxToZ(_("Copying file %x overwriting %y")). Replace(DefaultStr("%x"), DefaultStr("\"%x\""), false).Replace(DefaultStr("%y"), DefaultStr("\n\"%y\""), false)),
+ txtOverwritingLink(wxToZ(_("Copying Symbolic Link %x overwriting %y")).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)),
+ txtVerifying (wxToZ(_("Verifying file %x")). Replace(DefaultStr("%x"), DefaultStr("\n\"%x\""), false)) {}
template <bool reduceDiskSpace> //"true" if files deletion shall happen only
@@ -838,26 +888,29 @@ private:
void execute(HierarchyObject& hierObj);
void synchronizeFile(FileMapping& fileObj) const;
+ void synchronizeLink(SymLinkMapping& linkObj) const;
void synchronizeFolder(DirMapping& dirObj) const;
+ //more low level helper
+ template <FreeFileSync::SelectedSide side>
+ void deleteSymlink(const SymLinkMapping& linkObj) const;
+ void copySymlink(const Zstring& source, const Zstring& target, LinkDescriptor::LinkType type) const;
void copyFileUpdating(const Zstring& source, const Zstring& target, const wxULongLong& sourceFileSize) const;
void verifyFileCopy(const Zstring& source, const Zstring& target) const;
-
-
StatusHandler& statusUpdater_;
#ifdef FFS_WIN
ShadowCopy* shadowCopyHandler_; //optional!
#endif
const DeletionHandling& delHandling_;
- const bool copyFileSymLinks_;
- const bool traverseDirSymLinks_;
const bool verifyCopiedFiles_;
//preload status texts
const Zstring txtCopyingFile;
+ const Zstring txtCopyingLink;
const Zstring txtOverwritingFile;
+ const Zstring txtOverwritingLink;
const Zstring txtCreatingFolder;
const Zstring txtVerifying;
};
@@ -874,6 +927,11 @@ void SynchronizeFolderPair::execute(HierarchyObject& hierObj)
tryReportingError(statusUpdater_, boost::bind(&SynchronizeFolderPair::synchronizeFile, this, boost::ref(*i)));
}
+ //synchronize symbolic links: (process in second step only)
+ if (!reduceDiskSpace)
+ for (HierarchyObject::SubLinkMapping::iterator i = hierObj.useSubLinks().begin(); i != hierObj.useSubLinks().end(); ++i)
+ tryReportingError(statusUpdater_, boost::bind(&SynchronizeFolderPair::synchronizeLink, this, boost::ref(*i)));
+
//synchronize folders:
for (HierarchyObject::SubDirMapping::iterator i = hierObj.useSubDirs().begin(); i != hierObj.useSubDirs().end(); ++i)
{
@@ -890,10 +948,10 @@ void SynchronizeFolderPair::execute(HierarchyObject& hierObj)
switch (syncOp)
{
case SO_CREATE_NEW_LEFT:
- copyFileTimes(i->getFullName<RIGHT_SIDE>(), i->getFullName<LEFT_SIDE>()); //throw()
+ copyFileTimes(i->getFullName<RIGHT_SIDE>(), i->getFullName<LEFT_SIDE>(), true); //throw()
break;
case SO_CREATE_NEW_RIGHT:
- copyFileTimes(i->getFullName<LEFT_SIDE>(), i->getFullName<RIGHT_SIDE>()); //throw()
+ copyFileTimes(i->getFullName<LEFT_SIDE>(), i->getFullName<RIGHT_SIDE>(), true); //throw()
break;
case SO_OVERWRITE_RIGHT:
case SO_OVERWRITE_LEFT:
@@ -1003,70 +1061,98 @@ void SynchronizeFolderPair::synchronizeFile(FileMapping& fileObj) const
}
-//class DetectRenamedFiles
-//{
-//public:
-// static void execute(BaseDirMapping& baseMap, StatusHandler& statusUpdater)
-// {
-// DetectRenamedFiles(baseMap, statusUpdater);
-// }
-//
-//private:
-// DetectRenamedFiles(BaseDirMapping& baseMap, StatusHandler& statusUpdater);
-//
-// template <SelectedSide renameOnSide>
-// void renameFile(FileMapping& fileObjCreate, FileMapping& fileObjDelete) const;
-//
-// const Zstring txtRenamingFile;
-// StatusHandler& statusUpdater_;
-//};
-
-
-//DetectRenamedFiles::DetectRenamedFiles(BaseDirMapping& baseMap, StatusHandler& statusUpdater) :
-// txtRenamingFile(wxToZ(_("Renaming file %x to %y")).Replace(DefaultStr("%x"), DefaultStr("\"%x\""), false).Replace(DefaultStr("%y"), DefaultStr("\n\"%y\""), false)),
-// statusUpdater_(statusUpdater)
-//{
-// typedef std::vector<std::pair<CreateOnLeft, DeleteOnLeft> > RenameList;
-// RenameList renameOnLeft;
-// RenameList renameOnRight;
-// FreeFileSync::getRenameCandidates(baseMap, renameOnLeft, renameOnRight); //throw()!
-//
-// for (RenameList::const_iterator i = renameOnLeft.begin(); i != renameOnLeft.end(); ++i)
-// tryReportingError(statusUpdater_, boost::bind(&DetectRenamedFiles::renameFile<LEFT_SIDE>, this, boost::ref(*i->first), boost::ref(*i->second)));
-//
-// for (RenameList::const_iterator i = renameOnRight.begin(); i != renameOnRight.end(); ++i)
-// tryReportingError(statusUpdater_, boost::bind(&DetectRenamedFiles::renameFile<RIGHT_SIDE>, this, boost::ref(*i->first), boost::ref(*i->second)));
-//}
+void SynchronizeFolderPair::synchronizeLink(SymLinkMapping& linkObj) const
+{
+ Zstring statusText;
+ Zstring target;
+ switch (linkObj.getSyncOperation()) //evaluate comparison result and sync direction
+ {
+ case SO_CREATE_NEW_LEFT:
+ target = linkObj.getBaseDirPf<LEFT_SIDE>() + linkObj.getRelativeName<RIGHT_SIDE>();
-//template <SelectedSide renameOnSide>
-//void DetectRenamedFiles::renameFile(FileMapping& fileObjCreate, FileMapping& fileObjDelete) const
-//{
-// const SelectedSide sourceSide = renameOnSide == LEFT_SIDE ? RIGHT_SIDE : LEFT_SIDE;
-//
-// Zstring statusText = txtRenamingFile;
-// statusText.Replace(DefaultStr("%x"), fileObjDelete.getFullName<renameOnSide>(), false);
-// statusText.Replace(DefaultStr("%y"), fileObjCreate.getRelativeName<sourceSide>(), false);
-// statusUpdater_.updateStatusText(statusText);
-// statusUpdater_.requestUiRefresh(); //trigger display refresh
-//
-// FreeFileSync::renameFile(fileObjDelete.getFullName<renameOnSide>(),
-// fileObjDelete.getBaseDirPf<renameOnSide>() + fileObjCreate.getRelativeName<sourceSide>()); //throw (FileError);
-//
-// //update FileMapping
-// fileObjCreate.synchronizeSides();
-// fileObjDelete.synchronizeSides();
-//
-//#ifndef _MSC_VER
-//#warning set FileID!
-//#warning Test: zweimaliger rename sollte dann klappen
-//
-//#warning allgemein: FileID nach jedem kopieren neu bestimmen?
-//#endif
-// //progress indicator update
-// //indicator is updated only if file is sync'ed correctly (and if some sync was done)!
-// statusUpdater_.updateProcessedData(2, globalFunctions::convertToSigned(fileObjCreate.getFileSize<sourceSide>()));
-//}
+ statusText = txtCopyingLink;
+ statusText.Replace(DefaultStr("%x"), linkObj.getShortName<RIGHT_SIDE>(), false);
+ statusText.Replace(DefaultStr("%y"), target.BeforeLast(globalFunctions::FILE_NAME_SEPARATOR), false);
+ statusUpdater_.updateStatusText(statusText);
+ statusUpdater_.requestUiRefresh(); //trigger display refresh
+
+ copySymlink(linkObj.getFullName<RIGHT_SIDE>(), target, linkObj.getLinkType<RIGHT_SIDE>());
+ break;
+
+ case SO_CREATE_NEW_RIGHT:
+ target = linkObj.getBaseDirPf<RIGHT_SIDE>() + linkObj.getRelativeName<LEFT_SIDE>();
+
+ statusText = txtCopyingLink;
+ statusText.Replace(DefaultStr("%x"), linkObj.getShortName<LEFT_SIDE>(), false);
+ statusText.Replace(DefaultStr("%y"), target.BeforeLast(globalFunctions::FILE_NAME_SEPARATOR), false);
+ statusUpdater_.updateStatusText(statusText);
+ statusUpdater_.requestUiRefresh(); //trigger display refresh
+
+ copySymlink(linkObj.getFullName<LEFT_SIDE>(), target, linkObj.getLinkType<LEFT_SIDE>());
+ break;
+
+ case SO_DELETE_LEFT:
+ statusText = delHandling_.getTxtRemovingSymLink();
+ statusText.Replace(DefaultStr("%x"), linkObj.getFullName<LEFT_SIDE>(), false);
+ statusUpdater_.updateStatusText(statusText);
+ statusUpdater_.requestUiRefresh(); //trigger display refresh
+
+ deleteSymlink<LEFT_SIDE>(linkObj); //throw FileError()
+ break;
+
+ case SO_DELETE_RIGHT:
+ statusText = delHandling_.getTxtRemovingSymLink();
+ statusText.Replace(DefaultStr("%x"), linkObj.getFullName<RIGHT_SIDE>(), false);
+ statusUpdater_.updateStatusText(statusText);
+ statusUpdater_.requestUiRefresh(); //trigger display refresh
+
+ deleteSymlink<RIGHT_SIDE>(linkObj); //throw FileError()
+ break;
+
+ case SO_OVERWRITE_RIGHT:
+ target = linkObj.getBaseDirPf<RIGHT_SIDE>() + linkObj.getRelativeName<LEFT_SIDE>();
+
+ statusText = txtOverwritingLink;
+ statusText.Replace(DefaultStr("%x"), linkObj.getShortName<LEFT_SIDE>(), false);
+ statusText.Replace(DefaultStr("%y"), linkObj.getFullName<RIGHT_SIDE>().BeforeLast(globalFunctions::FILE_NAME_SEPARATOR), false);
+ statusUpdater_.updateStatusText(statusText);
+ statusUpdater_.requestUiRefresh(); //trigger display refresh
+
+ deleteSymlink<RIGHT_SIDE>(linkObj); //throw FileError()
+ linkObj.removeObject<RIGHT_SIDE>(); //remove file from FileMapping, to keep in sync (if subsequent copying fails!!)
+
+ copySymlink(linkObj.getFullName<LEFT_SIDE>(), target, linkObj.getLinkType<LEFT_SIDE>());
+ break;
+
+ case SO_OVERWRITE_LEFT:
+ target = linkObj.getBaseDirPf<LEFT_SIDE>() + linkObj.getRelativeName<RIGHT_SIDE>();
+
+ statusText = txtOverwritingLink;
+ statusText.Replace(DefaultStr("%x"), linkObj.getShortName<RIGHT_SIDE>(), false);
+ statusText.Replace(DefaultStr("%y"), linkObj.getFullName<LEFT_SIDE>().BeforeLast(globalFunctions::FILE_NAME_SEPARATOR), false);
+ statusUpdater_.updateStatusText(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_DO_NOTHING:
+ case SO_EQUAL:
+ case SO_UNRESOLVED_CONFLICT:
+ return; //no update on processed data!
+ }
+
+ //update FileMapping
+ linkObj.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!
+}
void SynchronizeFolderPair::synchronizeFolder(DirMapping& dirObj) const
@@ -1088,7 +1174,7 @@ void SynchronizeFolderPair::synchronizeFolder(DirMapping& dirObj) const
//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(_("Source directory does not exist anymore:")) + wxT("\n\"") + zToWx(dirObj.getFullName<RIGHT_SIDE>()) + wxT("\""));
- createDirectory(target, dirObj.getFullName<RIGHT_SIDE>(), !traverseDirSymLinks_); //traverse symlinks <=> !copy symlinks
+ createDirectory(target, dirObj.getFullName<RIGHT_SIDE>(), false); //no symlink copying!
break;
case SO_CREATE_NEW_RIGHT:
@@ -1102,7 +1188,7 @@ void SynchronizeFolderPair::synchronizeFolder(DirMapping& dirObj) const
//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(_("Source directory does not exist anymore:")) + wxT("\n\"") + zToWx(dirObj.getFullName<LEFT_SIDE>()) + wxT("\""));
- createDirectory(target, dirObj.getFullName<LEFT_SIDE>(), !traverseDirSymLinks_); //traverse symlinks <=> !copy symlinks
+ createDirectory(target, dirObj.getFullName<LEFT_SIDE>(), false); //no symlink copying!
break;
case SO_DELETE_LEFT:
@@ -1118,6 +1204,7 @@ void SynchronizeFolderPair::synchronizeFolder(DirMapping& dirObj) const
const SyncStatistics subObjects(dirObj);
//...then remove everything
dirObj.useSubFiles().clear();
+ dirObj.useSubLinks().clear();
dirObj.useSubDirs().clear();
statusUpdater_.updateProcessedData(subObjects.getCreate() + subObjects.getOverwrite() + subObjects.getDelete(), subObjects.getDataToProcess().ToDouble());
}
@@ -1136,6 +1223,7 @@ void SynchronizeFolderPair::synchronizeFolder(DirMapping& dirObj) const
const SyncStatistics subObjects(dirObj);
//...then remove everything
dirObj.useSubFiles().clear();
+ dirObj.useSubLinks().clear();
dirObj.useSubDirs().clear();
statusUpdater_.updateProcessedData(subObjects.getCreate() + subObjects.getOverwrite() + subObjects.getDelete(), subObjects.getDataToProcess().ToDouble());
}
@@ -1167,6 +1255,7 @@ bool dataLossPossible(const Zstring& dirName, const SyncStatistics& folderPairSt
!dirName.empty() && !FreeFileSync::dirExists(dirName);
}
+
namespace
{
void makeSameLength(wxString& first, wxString& second)
@@ -1281,7 +1370,7 @@ void SyncProcess::startSynchronizationProcess(const std::vector<FolderPairSyncCf
{
//show the first few conflicts in warning message also:
wxString warningMessage = wxString(_("Unresolved conflicts existing!")) +
- wxT(" (") + numberToWxString(statisticsTotal.getConflict(), true) + wxT(")\n\n");
+ wxT(" (") + numberToStringSep(statisticsTotal.getConflict()) + wxT(")\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)
@@ -1428,16 +1517,10 @@ void SynchronizeFolderPair::copyFileUpdating(const Zstring& source, const Zstrin
{
//create folders first (see http://sourceforge.net/tracker/index.php?func=detail&aid=2628943&group_id=234430&atid=1093080)
const Zstring targetDir = target.BeforeLast(globalFunctions::FILE_NAME_SEPARATOR);
- if (!FreeFileSync::dirExists(targetDir))
- {
- if (!targetDir.empty()) //kind of pathological, but empty target might happen
- {
- const Zstring templateDir = source.BeforeLast(globalFunctions::FILE_NAME_SEPARATOR);
- FreeFileSync::createDirectory(targetDir, templateDir, false);
- //symbolic link setting: If traversing into links => don't create
- //if not traversing into links => copy dir symlink of leaf-dir, not relevant here => actually: setting doesn't matter
- }
- }
+ const Zstring templateDir = source.BeforeLast(globalFunctions::FILE_NAME_SEPARATOR);
+
+ ensureExists(targetDir, templateDir); //throw (FileError)
+
//start of (possibly) long-running copy process: ensure status updates are performed regularly
wxLongLong totalBytesTransferred;
@@ -1447,7 +1530,7 @@ void SynchronizeFolderPair::copyFileUpdating(const Zstring& source, const Zstrin
{
FreeFileSync::copyFile(source,
target,
- copyFileSymLinks_,
+ false, //type File implicitly means symlinks need to be dereferenced!
#ifdef FFS_WIN
shadowCopyHandler_,
#endif
@@ -1468,6 +1551,48 @@ void SynchronizeFolderPair::copyFileUpdating(const Zstring& source, const Zstrin
}
+void SynchronizeFolderPair::copySymlink(const Zstring& source, const Zstring& target, LinkDescriptor::LinkType type) const
+{
+ //create folders first (see http://sourceforge.net/tracker/index.php?func=detail&aid=2628943&group_id=234430&atid=1093080)
+
+ const Zstring targetDir = target.BeforeLast(globalFunctions::FILE_NAME_SEPARATOR);
+ const Zstring templateDir = source.BeforeLast(globalFunctions::FILE_NAME_SEPARATOR);
+
+ ensureExists(targetDir, templateDir); //throw (FileError)
+
+ switch (type)
+ {
+ case LinkDescriptor::TYPE_DIR:
+ FreeFileSync::createDirectory(target, source, true); //copy symlink
+ break;
+
+ case LinkDescriptor::TYPE_FILE: //Windows: true file symlink; Linux: file-link or broken link
+ FreeFileSync::copyFile(source, target, true, //copy symlink
+#ifdef FFS_WIN
+ shadowCopyHandler_,
+#endif
+ NULL);
+ break;
+ }
+}
+
+
+template <FreeFileSync::SelectedSide side>
+void SynchronizeFolderPair::deleteSymlink(const SymLinkMapping& linkObj) const
+{
+ switch (linkObj.getLinkType<side>())
+ {
+ case LinkDescriptor::TYPE_DIR:
+ delHandling_.removeFolder<side>(linkObj); //throw (FileError)
+ break;
+
+ case LinkDescriptor::TYPE_FILE: //Windows: true file symlink; Linux: file-link or broken link
+ delHandling_.removeFile<side>(linkObj); //throw (FileError)
+ break;
+ }
+}
+
+
//--------------------- data verification -------------------------
//callback functionality for status updates while verifying
@@ -1566,4 +1691,3 @@ void SynchronizeFolderPair::verifyFileCopy(const Zstring& source, const Zstring&
}
}
}
-
bgstack15