diff options
author | Daniel Wilhelm <daniel@wili.li> | 2014-04-18 17:13:35 +0200 |
---|---|---|
committer | Daniel Wilhelm <daniel@wili.li> | 2014-04-18 17:13:35 +0200 |
commit | 801e8b43b13f1cb67d9e9ba4aae5acb274ccdfbc (patch) | |
tree | 473f4a9ea5016f146fb2ff6085807bc91a84c84e /library | |
parent | 3.20 (diff) | |
download | FreeFileSync-801e8b43b13f1cb67d9e9ba4aae5acb274ccdfbc.tar.gz FreeFileSync-801e8b43b13f1cb67d9e9ba4aae5acb274ccdfbc.tar.bz2 FreeFileSync-801e8b43b13f1cb67d9e9ba4aae5acb274ccdfbc.zip |
3.21
Diffstat (limited to 'library')
-rw-r--r-- | library/db_file.cpp | 6 | ||||
-rw-r--r-- | library/dir_exist_async.h | 4 | ||||
-rw-r--r-- | library/dir_lock.cpp | 22 | ||||
-rw-r--r-- | library/icon_buffer.cpp | 7 | ||||
-rw-r--r-- | library/lock_holder.h | 10 | ||||
-rw-r--r-- | library/parallel_scan.cpp | 66 | ||||
-rw-r--r-- | library/parallel_scan.h | 2 | ||||
-rw-r--r-- | library/process_xml.cpp | 24 | ||||
-rw-r--r-- | library/process_xml.h | 4 |
9 files changed, 98 insertions, 47 deletions
diff --git a/library/db_file.cpp b/library/db_file.cpp index 9429dd1e..994e8579 100644 --- a/library/db_file.cpp +++ b/library/db_file.cpp @@ -334,11 +334,11 @@ public: private: void execute(const HierarchyObject& hierObj, const DirContainer* oldDirInfo) { - std::for_each(hierObj.useSubFiles().begin(), hierObj.useSubFiles().end(), boost::bind(&SaveDirInfo::processFile, this, _1, oldDirInfo)); + std::for_each(hierObj.refSubFiles().begin(), hierObj.refSubFiles().end(), boost::bind(&SaveDirInfo::processFile, this, _1, oldDirInfo)); writeNumberC<bool>(false); //mark last entry - std::for_each(hierObj.useSubLinks().begin(), hierObj.useSubLinks().end(), boost::bind(&SaveDirInfo::processLink, this, _1, oldDirInfo)); + std::for_each(hierObj.refSubLinks().begin(), hierObj.refSubLinks().end(), boost::bind(&SaveDirInfo::processLink, this, _1, oldDirInfo)); writeNumberC<bool>(false); //mark last entry - std::for_each(hierObj.useSubDirs ().begin(), hierObj.useSubDirs ().end(), boost::bind(&SaveDirInfo::processDir, this, _1, oldDirInfo)); + std::for_each(hierObj.refSubDirs ().begin(), hierObj.refSubDirs ().end(), boost::bind(&SaveDirInfo::processDir, this, _1, oldDirInfo)); writeNumberC<bool>(false); //mark last entry } diff --git a/library/dir_exist_async.h b/library/dir_exist_async.h index 661c70d6..60fa4582 100644 --- a/library/dir_exist_async.h +++ b/library/dir_exist_async.h @@ -21,9 +21,7 @@ bool dirExistsUpdating(const Zstring& dirname, ProcessCallback& procCallback) { using namespace util; - std::wstring statusText = _("Searching for directory %x..."); - replace(statusText, L"%x", std::wstring(L"\"") + dirname + L"\"", false); - procCallback.reportInfo(statusText); + //do NOT include info messages here! this method is used by synchronization also, so avoid flooding! auto ft = dirExistsAsync(dirname); while (!ft.timed_wait(boost::posix_time::milliseconds(UI_UPDATE_INTERVAL))) diff --git a/library/dir_lock.cpp b/library/dir_lock.cpp index 6123449b..f653fa7c 100644 --- a/library/dir_lock.cpp +++ b/library/dir_lock.cpp @@ -473,7 +473,7 @@ bool tryLock(const Zstring& lockfilename) //throw (FileError) Loki::ScopeGuard guardLockFile = Loki::MakeGuard(::releaseLock, lockfilename); - //write UUID at the beginning of the file: this ID is a universal identifier for this lock (no matter what the path is, considering symlinks ,etc.) + //write UUID at the beginning of the file: this ID is a universal identifier for this lock (no matter what the path is, considering symlinks, etc.) writeLockInfo(lockfilename); //throw (FileError) guardLockFile.Dismiss(); //lockfile created successfully @@ -491,7 +491,7 @@ public: while (!::tryLock(lockfilename)) //throw (FileError) ::waitOnDirLock(lockfilename, callback); // - threadObj = std::move(boost::thread(LifeSigns(lockfilename))); + threadObj = boost::thread(LifeSigns(lockfilename)); } ~SharedDirLock() @@ -579,5 +579,19 @@ private: }; -DirLock::DirLock(const Zstring& lockfilename, DirLockCallback* callback) : //throw (FileError) - sharedLock(LockAdmin::instance().retrieve(lockfilename, callback)) {} +DirLock::DirLock(const Zstring& lockfilename, DirLockCallback* callback) //throw (FileError) +{ +#ifdef FFS_WIN + std::vector<wchar_t> volName(std::max(lockfilename.size(), static_cast<size_t>(10000))); + if (::GetVolumePathName(lockfilename.c_str(), //__in LPCTSTR lpszFileName, + &volName[0], //__out LPTSTR lpszVolumePathName, + static_cast<DWORD>(volName.size()))) //__in DWORD cchBufferLength + { + DWORD dt = ::GetDriveType(&volName[0]); + if (dt == DRIVE_CDROM) + return; //we don't need a lock for a CD ROM + } +#endif + + sharedLock = LockAdmin::instance().retrieve(lockfilename, callback); +} diff --git a/library/icon_buffer.cpp b/library/icon_buffer.cpp index 5d4dd19b..2c17f6da 100644 --- a/library/icon_buffer.cpp +++ b/library/icon_buffer.cpp @@ -297,9 +297,10 @@ public: void setWorkload(const std::vector<Zstring>& newLoad) //context of main thread { - boost::unique_lock<boost::mutex> dummy(lockFiles); - filesToLoad = newLoad; - + { + boost::unique_lock<boost::mutex> dummy(lockFiles); + filesToLoad = newLoad; + } conditionNewFiles.notify_one(); //condition handling, see: http://www.boost.org/doc/libs/1_43_0/doc/html/thread/synchronization.html#thread.synchronization.condvar_ref } diff --git a/library/lock_holder.h b/library/lock_holder.h index 172209dc..65471d5f 100644 --- a/library/lock_holder.h +++ b/library/lock_holder.h @@ -17,8 +17,14 @@ class LockHolder public: void addDir(const Zstring& dirnameFmt, ProcessCallback& procCallback) //resolved dirname ending with path separator { - if (dirnameFmt.empty() || - !dirExistsUpdating(dirnameFmt, procCallback)) + if (dirnameFmt.empty()) + return; + + std::wstring statusText = _("Searching for directory %x..."); + replace(statusText, L"%x", std::wstring(L"\"") + dirnameFmt + L"\"", false); + procCallback.reportInfo(statusText); + + if (!dirExistsUpdating(dirnameFmt, procCallback)) return; if (lockHolder.find(dirnameFmt) != lockHolder.end()) return; diff --git a/library/parallel_scan.cpp b/library/parallel_scan.cpp index 2f91763a..5ccb05fe 100644 --- a/library/parallel_scan.cpp +++ b/library/parallel_scan.cpp @@ -303,10 +303,10 @@ private: class DirCallback; -struct TraverserConfig +struct TraverserShared { public: - TraverserConfig(int threadID, + TraverserShared(int threadID, SymLinkHandling handleSymlinks, const HardFilter::FilterRef& filter, std::set<Zstring>& failedReads, @@ -322,7 +322,9 @@ public: const SymLinkHandling handleSymlinks_; const HardFilter::FilterRef filterInstance; //always bound! + std::set<Zstring>& failedReads_; //relative postfixed names of directories that could not be read (empty for root) + std::set<DirContainer*> excludedDirs; AsyncCallback& acb_; int threadID_; @@ -332,7 +334,7 @@ public: class DirCallback : public zen::TraverseCallback { public: - DirCallback(TraverserConfig& config, + DirCallback(TraverserShared& config, const Zstring& relNameParentPf, //postfixed with FILE_NAME_SEPARATOR! DirContainer& output) : cfg(config), @@ -345,7 +347,7 @@ public: virtual HandleError onError (const std::wstring& errorText); private: - TraverserConfig& cfg; + TraverserShared& cfg; const Zstring relNameParentPf_; DirContainer& output_; }; @@ -424,20 +426,20 @@ TraverseCallback::ReturnValDir DirCallback::onDir(const Zchar* shortName, const //apply filter before processing (use relative name!) bool subObjMightMatch = true; - if (!cfg.filterInstance->passDirFilter(relName, &subObjMightMatch)) - { - if (!subObjMightMatch) + const bool passFilter = cfg.filterInstance->passDirFilter(relName, &subObjMightMatch); + if (!passFilter && !subObjMightMatch) return Loki::Int2Type<ReturnValDir::TRAVERSING_DIR_IGNORE>(); //do NOT traverse subdirs - } - else - cfg.acb_.incItemsScanned(); //add 1 element to the progress indicator + //else: attention! ensure directory filtering is applied later to exclude actually filtered directories DirContainer& subDir = output_.addSubDir(shortName); + if (passFilter) + cfg.acb_.incItemsScanned(); //add 1 element to the progress indicator + else + cfg.excludedDirs.insert(&subDir); - TraverserConfig::CallbackPointer subDirCallback = std::make_shared<DirCallback>(cfg, relName + FILE_NAME_SEPARATOR, subDir); + TraverserShared::CallbackPointer subDirCallback = std::make_shared<DirCallback>(cfg, relName + FILE_NAME_SEPARATOR, subDir); cfg.callBackBox.push_back(subDirCallback); //handle lifetime - //attention: ensure directory filtering is applied later to exclude actually filtered directories - return ReturnValDir(Loki::Int2Type<ReturnValDir::TRAVERSING_DIR_CONTINUE>(), *subDirCallback.get()); + return ReturnValDir(Loki::Int2Type<ReturnValDir::TRAVERSING_DIR_CONTINUE>(), *subDirCallback); } @@ -482,6 +484,38 @@ private: #endif //------------------------------------------------------------------------------------------ +template <class M, class Predicate> inline +void map_remove_if(M& map, Predicate p) +{ + for (auto iter = map.begin(); iter != map.end();) + if (p(*iter)) + map.erase(iter++); + else + ++iter; +} + +void removeFilteredDirs(DirContainer& dirCont, const std::set<DirContainer*>& excludedDirs) +{ + //process subdirs recursively + std::for_each(dirCont.dirs.begin(), dirCont.dirs.end(), + [&](std::pair<const Zstring, DirContainer>& item) + { + removeFilteredDirs(item.second, excludedDirs); + }); + + //remove superfluous directories + map_remove_if(dirCont.dirs, + [&](std::pair<const Zstring, DirContainer>& item) -> bool + { + DirContainer& subDir = item.second; + return + subDir.dirs .empty() && + subDir.files.empty() && + subDir.links.empty() && + excludedDirs.find(&subDir) != excludedDirs.end(); + }); +} + class WorkerThread { @@ -512,7 +546,7 @@ public: //folder existence already checked in startCompareProcess(): do not treat as error when arriving here! //perf note: missing network drives should not delay here, as Windows buffers result of last existence check for a short time { - TraverserConfig travCfg(threadID_, + TraverserShared travCfg(threadID_, item.first.handleSymlinks_, //shared by all(!) instances of DirCallback while traversing a folder hierarchy item.first.filter_, dirVal.failedReads, @@ -544,6 +578,10 @@ public: //get all files and folders from directoryPostfixed (and subdirectories) traverseFolder(directoryName, followSymlinks, traverser, dstCallbackPtr); //exceptions may be thrown! + + //attention: some filtered directories are still in the comparison result! (see include filter handling!) + if (!travCfg.excludedDirs.empty()) + removeFilteredDirs(dirVal.dirCont, travCfg.excludedDirs); //remove all excluded directories (but keeps those serving as parent folders for not excl. elements) } }); } diff --git a/library/parallel_scan.h b/library/parallel_scan.h index f36c5ec7..5eaa6bd9 100644 --- a/library/parallel_scan.h +++ b/library/parallel_scan.h @@ -63,7 +63,7 @@ public: virtual void reportStatus(const std::wstring& statusMsg, int itemTotal) = 0; // }; -//attention: ensure directory filtering is applied later to exclude filtered directories which have been erroneously kept +//attention: ensure directory filtering is applied later to exclude filtered directories which have been kept as parent folders void fillBuffer(const std::set<DirectoryKey>& keysToRead, //in std::map<DirectoryKey, DirectoryValue>& buf, //out diff --git a/library/process_xml.cpp b/library/process_xml.cpp index 276bc977..aad96265 100644 --- a/library/process_xml.cpp +++ b/library/process_xml.cpp @@ -729,14 +729,10 @@ void readConfig(const XmlIn& in, XmlGlobalSettings& config) //try to read program language setting inShared["Language"](config.programLanguage); - //copy locked files using VSS - inShared["CopyLockedFiles"](config.copyLockedFiles); - - //file permissions - inShared["CopyFilePermissions"](config.copyFilePermissions); - - //verify file copying - inShared["VerifyCopiedFiles"](config.verifyFileCopy); + inShared["CopyLockedFiles" ](config.copyLockedFiles); + inShared["CopyFilePermissions" ](config.copyFilePermissions); + inShared["TransactionalFileCopy"](config.transactionalFileCopy); + inShared["VerifyCopiedFiles" ](config.verifyFileCopy); //max. allowed file time deviation inShared["FileTimeTolerance"](config.fileTimeTolerance); @@ -986,14 +982,10 @@ void writeConfig(const XmlGlobalSettings& config, XmlOut& out) //write program language setting outShared["Language"](config.programLanguage); - //copy locked files using VSS - outShared["CopyLockedFiles"](config.copyLockedFiles); - - //file permissions - outShared["CopyFilePermissions"](config.copyFilePermissions); - - //verify file copying - outShared["VerifyCopiedFiles"](config.verifyFileCopy); + outShared["CopyLockedFiles" ](config.copyLockedFiles); + outShared["CopyFilePermissions" ](config.copyFilePermissions); + outShared["TransactionalFileCopy"](config.transactionalFileCopy); + outShared["VerifyCopiedFiles" ](config.verifyFileCopy); //max. allowed file time deviation outShared["FileTimeTolerance"](config.fileTimeTolerance); diff --git a/library/process_xml.h b/library/process_xml.h index e8a11962..8815e3fd 100644 --- a/library/process_xml.h +++ b/library/process_xml.h @@ -142,7 +142,8 @@ struct XmlGlobalSettings copyLockedFiles(true), copyFilePermissions(false), fileTimeTolerance(2), //default 2s: FAT vs NTFS - verifyFileCopy(false) {} + verifyFileCopy(false), + transactionalFileCopy(true) {} int programLanguage; bool copyLockedFiles; //VSS usage @@ -150,6 +151,7 @@ struct XmlGlobalSettings size_t fileTimeTolerance; //max. allowed file time deviation bool verifyFileCopy; //verify copied files + bool transactionalFileCopy; OptionalDialogs optDialogs; |