summaryrefslogtreecommitdiff
path: root/library
diff options
context:
space:
mode:
authorDaniel Wilhelm <daniel@wili.li>2014-04-18 17:13:35 +0200
committerDaniel Wilhelm <daniel@wili.li>2014-04-18 17:13:35 +0200
commit801e8b43b13f1cb67d9e9ba4aae5acb274ccdfbc (patch)
tree473f4a9ea5016f146fb2ff6085807bc91a84c84e /library
parent3.20 (diff)
downloadFreeFileSync-801e8b43b13f1cb67d9e9ba4aae5acb274ccdfbc.tar.gz
FreeFileSync-801e8b43b13f1cb67d9e9ba4aae5acb274ccdfbc.tar.bz2
FreeFileSync-801e8b43b13f1cb67d9e9ba4aae5acb274ccdfbc.zip
3.21
Diffstat (limited to 'library')
-rw-r--r--library/db_file.cpp6
-rw-r--r--library/dir_exist_async.h4
-rw-r--r--library/dir_lock.cpp22
-rw-r--r--library/icon_buffer.cpp7
-rw-r--r--library/lock_holder.h10
-rw-r--r--library/parallel_scan.cpp66
-rw-r--r--library/parallel_scan.h2
-rw-r--r--library/process_xml.cpp24
-rw-r--r--library/process_xml.h4
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;
bgstack15