summaryrefslogtreecommitdiff
path: root/comparison.cpp
diff options
context:
space:
mode:
authorDaniel Wilhelm <daniel@wili.li>2014-04-18 17:04:59 +0200
committerDaniel Wilhelm <daniel@wili.li>2014-04-18 17:04:59 +0200
commitf570e2f2685aa43aa518c2f8578391c1847cddbe (patch)
treeb9376b3a7e807c5e0c4cf3d5615c14034d9675d6 /comparison.cpp
parent3.2 (diff)
downloadFreeFileSync-f570e2f2685aa43aa518c2f8578391c1847cddbe.tar.gz
FreeFileSync-f570e2f2685aa43aa518c2f8578391c1847cddbe.tar.bz2
FreeFileSync-f570e2f2685aa43aa518c2f8578391c1847cddbe.zip
3.3
Diffstat (limited to 'comparison.cpp')
-rw-r--r--comparison.cpp106
1 files changed, 71 insertions, 35 deletions
diff --git a/comparison.cpp b/comparison.cpp
index 79105801..120a96c3 100644
--- a/comparison.cpp
+++ b/comparison.cpp
@@ -21,6 +21,10 @@
#include <boost/bind.hpp>
#include <boost/scoped_array.hpp>
+#ifdef FFS_WIN
+#include "shared/longPathPrefix.h"
+#endif
+
using namespace FreeFileSync;
@@ -33,7 +37,7 @@ std::vector<FreeFileSync::FolderPairCfg> FreeFileSync::extractCompareCfg(const M
mainCfg.additionalPairs.begin(), //add additional pairs
mainCfg.additionalPairs.end());
- const FilterProcess::FilterRef globalFilter(new NameFilter(mainCfg.includeFilter, mainCfg.excludeFilter));
+ const BaseFilter::FilterRef globalFilter(new NameFilter(mainCfg.includeFilter, mainCfg.excludeFilter));
std::vector<FolderPairCfg> output;
for (std::vector<FolderPairEnh>::const_iterator i = allPairs.begin(); i != allPairs.end(); ++i)
@@ -43,11 +47,11 @@ std::vector<FreeFileSync::FolderPairCfg> FreeFileSync::extractCompareCfg(const M
mainCfg.filterIsActive ?
combineFilters(globalFilter,
- FilterProcess::FilterRef(
+ BaseFilter::FilterRef(
new NameFilter(
i->localFilter.includeFilter,
i->localFilter.excludeFilter))) :
- FilterProcess::FilterRef(new NullFilter),
+ BaseFilter::FilterRef(new NullFilter),
i->altSyncConfig.get() ? i->altSyncConfig->syncConfiguration : mainCfg.syncConfiguration));
@@ -89,9 +93,13 @@ class BaseDirCallback : public DirCallback
{
friend class DirCallback;
public:
- BaseDirCallback(DirContainer& output, const FilterProcess::FilterRef& filter, StatusHandler* handler) :
+ BaseDirCallback(DirContainer& output,
+ const BaseFilter::FilterRef& filter,
+ unsigned int detectRenameThreshold,
+ StatusHandler* handler) :
DirCallback(this, Zstring(), output, handler),
textScanning(wxToZ(wxString(_("Scanning:")) + wxT(" \n"))),
+ detectRenameThreshold_(detectRenameThreshold),
filterInstance(filter) {}
virtual TraverseCallback::ReturnValue onFile(const DefaultChar* shortName, const Zstring& fullName, const TraverseCallback::FileInfo& details);
@@ -102,7 +110,8 @@ private:
const Zstring textScanning;
std::vector<CallbackPointer> callBackBox; //collection of callback pointers to handle ownership
- const FilterProcess::FilterRef filterInstance; //always bound!
+ const unsigned int detectRenameThreshold_;
+ const BaseFilter::FilterRef filterInstance; //always bound!
};
@@ -126,6 +135,16 @@ TraverseCallback::ReturnValue DirCallback::onFile(const DefaultChar* shortName,
return TRAVERSING_CONTINUE;
}
+ //warning: for windows retrieveFileID is slow as hell! approximately 3 * 10^-4 s per file!
+ //therefore only large files (that take advantage of detection of renaming when synchronizing) should be evaluated!
+ //testcase: scanning only files larger than 1 MB results in performance loss of 6%
+
+//#warning this call is NOT acceptable for Linux!
+// //Linux: retrieveFileID takes about 50% longer in VM! (avoidable because of redundant stat() call!)
+// const Utility::FileID fileIdentifier = details.fileSize >= baseCallback_->detectRenameThreshold_ ?
+// Utility::retrieveFileID(fullName) :
+// Utility::FileID();
+
output_.addSubFile(shortName, FileDescriptor(details.lastWriteTimeRaw, details.fileSize));
//add 1 element to the progress indicator
@@ -212,7 +231,7 @@ TraverseCallback::ReturnValue BaseDirCallback::onFile(
const Zstring& fullName,
const TraverseCallback::FileInfo& details)
{
- //do not scan the database file
+ //do not list the database file sync.ffs_db
#ifdef FFS_WIN
if (getSyncDBFilename().CmpNoCase(shortName) == 0)
#elif defined FFS_LINUX
@@ -228,14 +247,14 @@ TraverseCallback::ReturnValue BaseDirCallback::onFile(
struct DirBufferKey
{
DirBufferKey(const Zstring& dirname,
- const FilterProcess::FilterRef& filterIn) : //filter interface: always bound by design!
+ const BaseFilter::FilterRef& filterIn) : //filter interface: always bound by design!
directoryName(dirname),
filter(filterIn->isNull() ? //some optimization of "Null" filter
- FilterProcess::FilterRef(new NullFilter) :
+ BaseFilter::FilterRef(new NullFilter) :
filterIn) {}
const Zstring directoryName;
- const FilterProcess::FilterRef filter; //buffering has to consider filtering!
+ const BaseFilter::FilterRef filter; //buffering has to consider filtering!
bool operator < (const DirBufferKey& b) const
{
@@ -256,11 +275,14 @@ struct DirBufferKey
class CompareProcess::DirectoryBuffer //buffer multiple scans of the same directories
{
public:
- DirectoryBuffer(const bool traverseDirectorySymlinks, StatusHandler* statusUpdater) :
+ DirectoryBuffer(const bool traverseDirectorySymlinks,
+ const unsigned int detectRenameThreshold,
+ StatusHandler* statusUpdater) :
m_traverseDirectorySymlinks(traverseDirectorySymlinks),
+ detectRenameThreshold_(detectRenameThreshold),
m_statusUpdater(statusUpdater) {}
- const DirContainer& getDirectoryDescription(const Zstring& directoryPostfixed, const FilterProcess::FilterRef& filter);
+ const DirContainer& getDirectoryDescription(const Zstring& directoryPostfixed, const BaseFilter::FilterRef& filter);
private:
typedef boost::shared_ptr<DirContainer> DirBufferValue; //exception safety: avoid memory leak
@@ -271,6 +293,7 @@ private:
BufferType buffer;
const bool m_traverseDirectorySymlinks;
+ const unsigned int detectRenameThreshold_;
StatusHandler* m_statusUpdater;
};
//------------------------------------------------------------------------------------------
@@ -282,10 +305,15 @@ DirContainer& CompareProcess::DirectoryBuffer::insertIntoBuffer(const DirBufferK
if (FreeFileSync::dirExists(newKey.directoryName.c_str())) //folder existence already checked in startCompareProcess(): do not treat as error when arriving here!
{
- std::auto_ptr<TraverseCallback> traverser(new BaseDirCallback(*baseContainer, newKey.filter, m_statusUpdater));
+ std::auto_ptr<TraverseCallback> traverser(new BaseDirCallback(*baseContainer,
+ newKey.filter,
+ detectRenameThreshold_,
+ m_statusUpdater));
//get all files and folders from directoryPostfixed (and subdirectories)
- traverseFolder(newKey.directoryName, m_traverseDirectorySymlinks, traverser.get()); //exceptions may be thrown!
+ traverseFolder(newKey.directoryName,
+ m_traverseDirectorySymlinks,
+ traverser.get()); //exceptions may be thrown!
}
return *baseContainer.get();
}
@@ -293,7 +321,7 @@ DirContainer& CompareProcess::DirectoryBuffer::insertIntoBuffer(const DirBufferK
const DirContainer& CompareProcess::DirectoryBuffer::getDirectoryDescription(
const Zstring& directoryPostfixed,
- const FilterProcess::FilterRef& filter)
+ const BaseFilter::FilterRef& filter)
{
const DirBufferKey searchKey(directoryPostfixed, filter);
@@ -321,14 +349,14 @@ void foldersAreValidForComparison(const std::vector<FolderPairCfg>& folderPairsF
checkEmptyDirnameActive = false;
while (true)
{
- const ErrorHandler::Response rv = statusUpdater->reportError(wxString(_("Please fill all empty directory fields.")) + wxT(" \n\n") +
+ const ErrorHandler::Response rv = statusUpdater->reportError(wxString(_("At least one directory input field is empty.")) + wxT(" \n\n") +
+ wxT("(") + additionalInfo + wxT(")"));
if (rv == ErrorHandler::IGNORE_ERROR)
break;
else if (rv == ErrorHandler::RETRY)
; //continue with loop
else
- throw std::logic_error("Programming Error: Unknown return value!");
+ throw std::logic_error("Programming Error: Unknown return value! (1)");
}
}
}
@@ -339,13 +367,13 @@ void foldersAreValidForComparison(const std::vector<FolderPairCfg>& folderPairsF
{
ErrorHandler::Response rv = statusUpdater->reportError(wxString(_("Directory does not exist:")) + wxT(" \n") +
wxT("\"") + zToWx(i->leftDirectory) + wxT("\"") + wxT("\n\n") +
- FreeFileSync::getLastErrorFormatted() + wxT(" ") + additionalInfo);
+ additionalInfo + wxT(" ") + FreeFileSync::getLastErrorFormatted());
if (rv == ErrorHandler::IGNORE_ERROR)
break;
else if (rv == ErrorHandler::RETRY)
; //continue with loop
else
- throw std::logic_error("Programming Error: Unknown return value!");
+ throw std::logic_error("Programming Error: Unknown return value! (2)");
}
if (!i->rightDirectory.empty())
@@ -353,13 +381,13 @@ void foldersAreValidForComparison(const std::vector<FolderPairCfg>& folderPairsF
{
ErrorHandler::Response rv = statusUpdater->reportError(wxString(_("Directory does not exist:")) + wxT("\n") +
wxT("\"") + zToWx(i->rightDirectory) + wxT("\"") + wxT("\n\n") +
- FreeFileSync::getLastErrorFormatted() + wxT(" ") + additionalInfo);
+ additionalInfo + wxT(" ") + FreeFileSync::getLastErrorFormatted());
if (rv == ErrorHandler::IGNORE_ERROR)
break;
else if (rv == ErrorHandler::RETRY)
; //continue with loop
else
- throw std::logic_error("Programming Error: Unknown return value!");
+ throw std::logic_error("Programming Error: Unknown return value! (3)");
}
}
}
@@ -372,8 +400,8 @@ bool dependencyExists(const std::set<Zstring>& folders, const Zstring& newFolder
Zstring newFolderFmt = newFolder;
Zstring refFolderFmt = *i;
#ifdef FFS_WIN //Windows does NOT distinguish between upper/lower-case
- newFolderFmt.MakeLower();
- refFolderFmt.MakeLower();
+ newFolderFmt.MakeUpper();
+ refFolderFmt.MakeUpper();
#elif defined FFS_LINUX //Linux DOES distinguish between upper/lower-case
//nothing to do here
#endif
@@ -419,6 +447,7 @@ bool foldersHaveDependencies(const std::vector<FolderPairCfg>& folderPairsFrom,
CompareProcess::CompareProcess(const bool traverseSymLinks,
const unsigned int fileTimeTol,
const bool ignoreOneHourDiff,
+ const unsigned int detectRenameThreshold,
xmlAccess::OptionalDialogs& warnings,
StatusHandler* handler) :
fileTimeTolerance(fileTimeTol),
@@ -427,7 +456,7 @@ CompareProcess::CompareProcess(const bool traverseSymLinks,
statusUpdater(handler),
txtComparingContentOfFiles(wxToZ(_("Comparing content of files %x")).Replace(DefaultStr("%x"), DefaultStr("\n\"%x\""), false))
{
- directoryBuffer.reset(new DirectoryBuffer(traverseSymLinks, handler));
+ directoryBuffer.reset(new DirectoryBuffer(traverseSymLinks, detectRenameThreshold, handler));
}
@@ -447,7 +476,7 @@ bool filesHaveSameContent(const Zstring& filename1, const Zstring& filename2, Co
static boost::scoped_array<unsigned char> memory2(new unsigned char[BUFFER_SIZE]);
#ifdef FFS_WIN
- wxFFile file1(filename1.c_str(), DefaultStr("rb"));
+ wxFFile file1(FreeFileSync::applyLongPathPrefix(filename1).c_str(), DefaultStr("rb"));
#elif defined FFS_LINUX
wxFFile file1(::fopen(filename1.c_str(), DefaultStr("rb"))); //utilize UTF-8 filename
#endif
@@ -455,7 +484,7 @@ bool filesHaveSameContent(const Zstring& filename1, const Zstring& filename2, Co
throw FileError(wxString(_("Error opening file:")) + wxT(" \"") + zToWx(filename1) + wxT("\""));
#ifdef FFS_WIN
- wxFFile file2(filename2.c_str(), DefaultStr("rb"));
+ wxFFile file2(FreeFileSync::applyLongPathPrefix(filename2).c_str(), DefaultStr("rb"));
#elif defined FFS_LINUX
wxFFile file2(::fopen(filename2.c_str(), DefaultStr("rb"))); //utilize UTF-8 filename
#endif
@@ -551,7 +580,7 @@ struct ToBeRemoved
class RemoveFilteredDirs
{
public:
- RemoveFilteredDirs(const FilterProcess& filterProc) :
+ RemoveFilteredDirs(const BaseFilter& filterProc) :
filterProc_(filterProc) {}
void execute(HierarchyObject& hierObj)
@@ -573,7 +602,7 @@ private:
execute(dirObj);
}
- const FilterProcess& filterProc_;
+ const BaseFilter& filterProc_;
};
@@ -695,15 +724,25 @@ wxString getConflictInvalidDate(const Zstring& fileNameFull, const wxLongLong& u
}
+namespace
+{
+inline
+void makeSameLength(wxString& first, wxString& second)
+{
+ const size_t maxPref = std::max(first.length(), second.length());
+ first.Pad(maxPref - first.length(), wxT(' '), true);
+ second.Pad(maxPref - second.length(), wxT(' '), true);
+}
+}
+
+
//check for changed files with same modification date
wxString getConflictSameDateDiffSize(const FileMapping& fileObj)
{
//some beautification...
wxString left = wxString(_("Left")) + wxT(": ");
wxString right = wxString(_("Right")) + wxT(": ");
- const size_t maxPref = std::max(left.length(), right.length());
- left.Pad(maxPref - left.length(), wxT(' '), true);
- right.Pad(maxPref - right.length(), wxT(' '), true);
+ makeSameLength(left, right);
wxString msg = _("Files %x have the same date but a different size!");
msg.Replace(wxT("%x"), wxString(wxT("\"")) + zToWx(fileObj.getRelativeName<LEFT_SIDE>()) + wxT("\""));
@@ -722,9 +761,7 @@ wxString getConflictChangeWithinHour(const FileMapping& fileObj)
//some beautification...
wxString left = wxString(_("Left")) + wxT(": ");
wxString right = wxString(_("Right")) + wxT(": ");
- const size_t maxPref = std::max(left.length(), right.length());
- left.Pad(maxPref - left.length(), wxT(' '), true);
- right.Pad(maxPref - right.length(), wxT(' '), true);
+ makeSameLength(left, right);
wxString msg = _("Files %x have a file time difference of less than 1 hour!\n\nIt's not safe to decide which one is newer due to Daylight Saving Time issues.");
msg += wxString(wxT("\n")) + _("(Note that only FAT/FAT32 drives are affected by this problem!\nIn all other cases you can disable the setting \"ignore 1-hour difference\".)");
@@ -880,7 +917,7 @@ void CompareProcess::compareByContent(const std::vector<FolderPairCfg>& director
- const size_t objectsTotal = filesToCompareBytewise.size() * 2;
+ const size_t objectsTotal = filesToCompareBytewise.size() * 2;
const wxULongLong bytesTotal = getBytesToCompare(filesToCompareBytewise);
statusUpdater->initNewProcess(objectsTotal,
@@ -1060,4 +1097,3 @@ void CompareProcess::performBaseComparison(BaseDirMapping& output, std::vector<F
MergeSides(appendUndefined).execute(directoryLeft, directoryRight, output);
}
-
bgstack15