diff options
author | Daniel Wilhelm <daniel@wili.li> | 2014-04-18 17:19:14 +0200 |
---|---|---|
committer | Daniel Wilhelm <daniel@wili.li> | 2014-04-18 17:19:14 +0200 |
commit | 01eb8253196672c969a39587e90b49321a182428 (patch) | |
tree | 4a3b71d7913de519744466c9227fda6461c4f0b5 /synchronization.cpp | |
parent | 5.0 (diff) | |
download | FreeFileSync-01eb8253196672c969a39587e90b49321a182428.tar.gz FreeFileSync-01eb8253196672c969a39587e90b49321a182428.tar.bz2 FreeFileSync-01eb8253196672c969a39587e90b49321a182428.zip |
5.1
Diffstat (limited to 'synchronization.cpp')
-rw-r--r-- | synchronization.cpp | 113 |
1 files changed, 47 insertions, 66 deletions
diff --git a/synchronization.cpp b/synchronization.cpp index 10ec2f5a..1528ac27 100644 --- a/synchronization.cpp +++ b/synchronization.cpp @@ -14,7 +14,6 @@ #include <wx+/string_conv.h> #include <wx+/format_unit.h> #include <zen/scope_guard.h> -#include "lib/status_handler.h" #include <zen/file_handling.h> #include "lib/resolve_path.h" #include "lib/recycler.h" @@ -23,6 +22,7 @@ #include "lib/cmp_filetime.h" #include <zen/file_io.h> #include <zen/time.h> +#include "lib/status_handler_impl.h" #ifdef FFS_WIN #include <zen/long_path_prefix.h> @@ -338,31 +338,6 @@ FolderPairSyncCfg::FolderPairSyncCfg(bool automaticMode, custDelFolder(zen::getFormattedDirectoryName(custDelDir)) {} //----------------------------------------------------------------------------------------------------------- - -template <typename Function> inline -bool tryReportingError(ProcessCallback& handler, Function cmd) //return "true" on success, "false" if error was ignored -{ - while (true) - { - try - { - cmd(); //throw FileError - return true; - } - catch (FileError& error) - { - ProcessCallback::Response rv = handler.reportError(error.toString()); //may throw! - if (rv == ProcessCallback::IGNORE_ERROR) - return false; - else if (rv == ProcessCallback::RETRY) - ; //continue with loop - else - throw std::logic_error("Programming Error: Unknown return value!"); - } - } -} - - /* add some postfix to alternate deletion directory: deletionDirectory\<prefix>2010-06-30 12-59-12\ */ @@ -383,7 +358,7 @@ Zstring getSessionDeletionDir(const Zstring& deletionDirectory, const Zstring& p //ensure uniqueness for (int i = 1; zen::somethingExists(output); ++i) - output = formattedDir + Zchar('_') + toString<Zstring>(i); + output = formattedDir + Zchar('_') + numberTo<Zstring>(i); output += FILE_NAME_SEPARATOR; return output; @@ -422,7 +397,7 @@ public: void tryCleanup(); //throw FileError -> call this in non-exceptional coding, i.e. somewhere after sync! void removeFile (const Zstring& relativeName) const; //throw FileError - void removeFolder(const Zstring& relativeName) const { removeFolderInt(relativeName, NULL, NULL); }; //throw FileError + void removeFolder(const Zstring& relativeName) const { removeFolderInt(relativeName, nullptr, nullptr); }; //throw FileError void removeFolderUpdateStatistics(const Zstring& relativeName, int objectsExpected, Int64 dataExpected) const { removeFolderInt(relativeName, &objectsExpected, &dataExpected); }; //throw FileError //in contrast to "removeFolder()" this function will update statistics! @@ -636,7 +611,7 @@ void DeletionHandling::removeFile(const Zstring& relativeName) const case MOVE_TO_CUSTOM_DIRECTORY: { - CallbackMoveFileImpl callBack(*procCallback_, *this, NULL); //we do *not* report statistics in this method + CallbackMoveFileImpl callBack(*procCallback_, *this, nullptr); //we do *not* report statistics in this method const Zstring targetFile = sessionDelDir + relativeName; //ends with path separator try //... to get away cheaply! @@ -673,7 +648,7 @@ void DeletionHandling::removeFolderInt(const Zstring& relativeName, const int* o { case DELETE_PERMANENTLY: { - CallbackRemoveDirImpl remDirCallback(*procCallback_, *this, objectsExpected ? &objectsReported : NULL); + CallbackRemoveDirImpl remDirCallback(*procCallback_, *this, objectsExpected ? &objectsReported : nullptr); removeDirectory(fullName, &remDirCallback); } break; @@ -716,7 +691,7 @@ void DeletionHandling::removeFolderInt(const Zstring& relativeName, const int* o case MOVE_TO_CUSTOM_DIRECTORY: { - CallbackMoveFileImpl callBack(*procCallback_, *this, objectsExpected ? &objectsReported : NULL); + CallbackMoveFileImpl callBack(*procCallback_, *this, objectsExpected ? &objectsReported : nullptr); const Zstring targetDir = sessionDelDir + relativeName; try //... to get away cheaply! @@ -1009,8 +984,8 @@ namespace template <class Mapping> inline bool haveNameClash(const Zstring& shortname, Mapping& m) { - return std::find_if(m.begin(), m.end(), - [&](const typename Mapping::value_type& obj) { return EqualFilename()(obj.getObjShortName(), shortname); }) != m.end(); + return std::any_of(m.begin(), m.end(), + [&](const typename Mapping::value_type& obj) { return EqualFilename()(obj.getObjShortName(), shortname); }); } @@ -1020,7 +995,7 @@ Zstring findUniqueTempName(const Zstring& filename) //ensure uniqueness for (int i = 1; somethingExists(output); ++i) - output = filename + Zchar('_') + toString<Zstring>(i) + zen::TEMP_FILE_ENDING; + output = filename + Zchar('_') + numberTo<Zstring>(i) + zen::TEMP_FILE_ENDING; return output; } @@ -1158,7 +1133,13 @@ void SynchronizeFolderPair::runZeroPass(HierarchyObject& hierObj) FileMapping* sourceObj = &fileObj; if (FileMapping* targetObj = dynamic_cast<FileMapping*>(FileSystemObject::retrieve(fileObj.getMoveRef()))) { - if (!tryReportingError(procCallback_, [&] { return syncOp == SO_MOVE_LEFT_SOURCE ? this->manageFileMove<LEFT_SIDE>(*sourceObj, *targetObj) : this->manageFileMove<RIGHT_SIDE>(*sourceObj, *targetObj); })) + if (!tryReportingError([&] + { + if (syncOp == SO_MOVE_LEFT_SOURCE) + this->manageFileMove<LEFT_SIDE>(*sourceObj, *targetObj); + else + this->manageFileMove<RIGHT_SIDE>(*sourceObj, *targetObj); + }, procCallback_)) { //move operation has failed! We cannot allow to continue and have move source's parent directory deleted, messing up statistics! // => revert to ordinary "copy + delete" @@ -1173,8 +1154,8 @@ void SynchronizeFolderPair::runZeroPass(HierarchyObject& hierObj) }; const auto statBefore = getStat(); - sourceObj->setMoveRef(NULL); - targetObj->setMoveRef(NULL); + sourceObj->setMoveRef(nullptr); + targetObj->setMoveRef(nullptr); const auto statAfter = getStat(); //fix statistics to total to match "copy + delete" procCallback_.updateTotalData(statAfter.first - statBefore.first, statAfter.second - statBefore.second); @@ -1313,7 +1294,7 @@ void SynchronizeFolderPair::runPass(HierarchyObject& hierObj) [&](FileMapping& fileObj) { if (pass == getPass(fileObj)) - tryReportingError(procCallback_, [&] { synchronizeFile(fileObj); }); + tryReportingError([&] { synchronizeFile(fileObj); }, procCallback_); }); //synchronize symbolic links: @@ -1321,7 +1302,7 @@ void SynchronizeFolderPair::runPass(HierarchyObject& hierObj) [&](SymLinkMapping& linkObj) { if (pass == getPass(linkObj)) - tryReportingError(procCallback_, [&] { synchronizeLink(linkObj); }); + tryReportingError([&] { synchronizeLink(linkObj); }, procCallback_); }); //synchronize folders: @@ -1329,7 +1310,7 @@ void SynchronizeFolderPair::runPass(HierarchyObject& hierObj) [&](DirMapping& dirObj) { if (pass == getPass(dirObj)) - tryReportingError(procCallback_, [&] { synchronizeFolder(dirObj); }); + tryReportingError([&] { synchronizeFolder(dirObj); }, procCallback_); this->runPass<pass>(dirObj); //recurse }); @@ -1963,7 +1944,7 @@ void SyncProcess::startSynchronizationProcess(const std::vector<FolderPairSyncCf auto checkSpace = [&](const Zstring& baseDirPf, const Int64& spaceRequired) { wxLongLong freeDiskSpace; - if (wxGetDiskSpace(toWx(baseDirPf), NULL, &freeDiskSpace)) + if (wxGetDiskSpace(toWx(baseDirPf), nullptr, &freeDiskSpace)) { if (0 < freeDiskSpace && //zero disk space is either an error or not: in both cases this warning message is obsolete (WebDav seems to report 0) freeDiskSpace.GetValue() < spaceRequired) @@ -2068,9 +2049,9 @@ void SyncProcess::startSynchronizationProcess(const std::vector<FolderPairSyncCf std::vector<Zstring> conflictDirs; for (auto iter = dirReadWriteCount.cbegin(); iter != dirReadWriteCount.cend(); ++iter) { - const auto& countRef = iter->second; - if (countRef.second >= 2 || //multiple write accesses - (countRef.second == 1 && countRef.first >= 1)) //read/write access + const std::pair<size_t, size_t>& countRef = iter->second; //# read/write accesses + + if (countRef.first + countRef.second >= 2 && countRef.second >= 1) //race condition := multiple accesses of which at least one is a write conflictDirs.push_back(iter->first); } @@ -2087,7 +2068,7 @@ void SyncProcess::startSynchronizationProcess(const std::vector<FolderPairSyncCf #ifdef FFS_WIN //shadow copy buffer: per sync-instance, not folder pair - boost::scoped_ptr<shadow::ShadowCopy> shadowCopyHandler(copyLockedFiles_ ? new shadow::ShadowCopy : NULL); + std::unique_ptr<shadow::ShadowCopy> shadowCopyHandler(copyLockedFiles_ ? new shadow::ShadowCopy : nullptr); #endif try @@ -2114,7 +2095,7 @@ void SyncProcess::startSynchronizationProcess(const std::vector<FolderPairSyncCf makeSameLength(left, right); const std::wstring statusTxt = _("Processing folder pair:") + L" \n" + - L" " + left + L"\"" + j->getBaseDirPf<LEFT_SIDE>() + L"\"" + L" \n" + + L" " + left + L"\"" + j->getBaseDirPf<LEFT_SIDE >() + L"\"" + L" \n" + L" " + right + L"\"" + j->getBaseDirPf<RIGHT_SIDE>() + L"\""; procCallback.reportInfo(statusTxt); @@ -2124,14 +2105,14 @@ void SyncProcess::startSynchronizationProcess(const std::vector<FolderPairSyncCf const Zstring dirnameLeft = beforeLast(j->getBaseDirPf<LEFT_SIDE>(), FILE_NAME_SEPARATOR); if (!dirnameLeft.empty() && !dirExistsUpdating(dirnameLeft, false, procCallback)) { - if (!tryReportingError(procCallback, [&]() { createDirectory(dirnameLeft); })) //may throw in error-callback! - continue; //skip this folder pair + if (!tryReportingError([&] { createDirectory(dirnameLeft); }, procCallback)) //may throw in error-callback! + continue; //skip this folder pair } const Zstring dirnameRight = beforeLast(j->getBaseDirPf<RIGHT_SIDE>(), FILE_NAME_SEPARATOR); if (!dirnameRight.empty() && !dirExistsUpdating(dirnameRight, false, procCallback)) { - if (!tryReportingError(procCallback, [&]() { createDirectory(dirnameRight); })) //may throw in error-callback! - continue; //skip this folder pair + if (!tryReportingError([&] { createDirectory(dirnameRight); }, procCallback)) //may throw in error-callback! + continue; //skip this folder pair } //------------------------------------------------------------------------------------------ //execute synchronization recursively @@ -2140,19 +2121,20 @@ void SyncProcess::startSynchronizationProcess(const std::vector<FolderPairSyncCf zen::ScopeGuard guardUpdateDb = zen::makeGuard([&] { if (folderPairCfg.inAutomaticMode) - zen::saveToDisk(*j); //throw FileError + try { zen::saveToDisk(*j); } + catch (...) {} //throw FileError }); //guarantee removal of invalid entries (where element on both sides is empty) - ZEN_ON_BLOCK_EXIT(BaseDirMapping::removeEmpty(*j);); + ZEN_ON_SCOPE_EXIT(BaseDirMapping::removeEmpty(*j);); bool copyPermissionsFp = false; - tryReportingError(procCallback, [&] + tryReportingError([&] { copyPermissionsFp = copyFilePermissions_ && //copy permissions only if asked for and supported by *both* sides! supportsPermissions(beforeLast(j->getBaseDirPf<LEFT_SIDE >(), FILE_NAME_SEPARATOR)) && //throw FileError supportsPermissions(beforeLast(j->getBaseDirPf<RIGHT_SIDE>(), FILE_NAME_SEPARATOR)); - }); //show error dialog if necessary + }, procCallback); //show error dialog if necessary SynchronizeFolderPair syncFP(procCallback, verifyCopiedFiles_, copyPermissionsFp, transactionalFileCopy_, #ifdef FFS_WIN @@ -2163,8 +2145,8 @@ void SyncProcess::startSynchronizationProcess(const std::vector<FolderPairSyncCf syncFP.startSync(*j); //(try to gracefully) cleanup temporary folders (Recycle bin optimization) -> will be done in ~DeletionHandling anyway... - tryReportingError(procCallback, [&] { delHandlerFp.first .tryCleanup(); }); //show error dialog if necessary - tryReportingError(procCallback, [&] { delHandlerFp.second.tryCleanup(); }); // + tryReportingError([&] { delHandlerFp.first .tryCleanup(); }, procCallback); //show error dialog if necessary + tryReportingError([&] { delHandlerFp.second.tryCleanup(); }, procCallback); // //(try to gracefully) write database file (will be done in ~EnforceUpdateDatabase anyway...) if (folderPairCfg.inAutomaticMode) @@ -2172,13 +2154,13 @@ void SyncProcess::startSynchronizationProcess(const std::vector<FolderPairSyncCf procCallback.reportStatus(_("Generating database...")); procCallback.forceUiRefresh(); - tryReportingError(procCallback, [&]() { zen::saveToDisk(*j); }); //throw FileError + tryReportingError([&] { zen::saveToDisk(*j); }, procCallback); //throw FileError guardUpdateDb.dismiss(); } } if (!synchronizationNeeded(statisticsTotal)) - procCallback.reportInfo(_("Nothing to synchronize according to configuration!")); //inform about this special case + procCallback.reportInfo(_("Nothing to synchronize!")); //inform about this special case } catch (const std::exception& e) { @@ -2266,7 +2248,7 @@ void SynchronizeFolderPair::copyFileUpdatingTo(const FileMapping& fileObj, const catch (ErrorFileLocked&) { //if file is locked (try to) use Windows Volume Shadow Copy Service - if (shadowCopyHandler_ == NULL) + if (!shadowCopyHandler_) throw; try { @@ -2275,8 +2257,7 @@ void SynchronizeFolderPair::copyFileUpdatingTo(const FileMapping& fileObj, const } catch (const FileError& e) { - const std::wstring errorMsg = replaceCpy(_("Error copying locked file %x!"), L"%x", std::wstring(L"\"") + source + L"\""); - throw FileError(errorMsg + L"\n\n" + e.toString()); + throw FileError(replaceCpy(_("Unable to copy locked file %x!"), L"%x", std::wstring(L"\"") + source + L"\"") + L"\n\n" + e.toString()); } //now try again @@ -2326,7 +2307,7 @@ void verifyFiles(const Zstring& source, const Zstring& target, VerifyCallback& c wxFile file1(::open(source.c_str(), O_RDONLY)); //utilize UTF-8 filename #endif if (!file1.IsOpened()) - throw FileError(_("Error opening file:") + L" \"" + source + L"\""); + throw FileError(_("Error reading file:") + L" \"" + source + L"\""); #ifdef FFS_WIN wxFile file2(applyLongPathPrefix(target).c_str(), wxFile::read); //don't use buffered file input for verification! @@ -2334,18 +2315,18 @@ void verifyFiles(const Zstring& source, const Zstring& target, VerifyCallback& c wxFile file2(::open(target.c_str(), O_RDONLY)); //utilize UTF-8 filename #endif if (!file2.IsOpened()) //NO cleanup necessary for (wxFile) file1 - throw FileError(_("Error opening file:") + L" \"" + target + L"\""); + throw FileError(_("Error reading file:") + L" \"" + target + L"\""); do { const size_t length1 = file1.Read(&memory1[0], memory1.size()); if (file1.Error()) - throw FileError(_("Error reading file:") + L" \"" + source + L"\""); + throw FileError(_("Error reading file:") + L" \"" + source + L"\"" + L" (r)"); callback.updateStatus(); //send progress updates const size_t length2 = file2.Read(&memory2[0], memory2.size()); if (file2.Error()) - throw FileError(_("Error reading file:") + L" \"" + target + L"\""); + throw FileError(_("Error reading file:") + L" \"" + target + L"\"" + L" (r)"); callback.updateStatus(); //send progress updates if (length1 != length2 || ::memcmp(&memory1[0], &memory2[0], length1) != 0) @@ -2376,5 +2357,5 @@ void SynchronizeFolderPair::verifyFileCopy(const Zstring& source, const Zstring& VerifyStatusUpdater callback(procCallback_); - tryReportingError(procCallback_, [&]() { ::verifyFiles(source, target, callback);}); + tryReportingError([&] { ::verifyFiles(source, target, callback); }, procCallback_); } |