diff options
Diffstat (limited to 'comparison.cpp')
-rw-r--r-- | comparison.cpp | 609 |
1 files changed, 326 insertions, 283 deletions
diff --git a/comparison.cpp b/comparison.cpp index 0ad2e1fb..f90b47de 100644 --- a/comparison.cpp +++ b/comparison.cpp @@ -15,160 +15,25 @@ using namespace FreeFileSync; -CompareProcess::CompareProcess(bool lineBreakOnMessages, bool handleDstOnFat32Drives, StatusHandler* handler) : - includeLineBreak(lineBreakOnMessages), - handleDstOnFat32(handleDstOnFat32Drives), - statusUpdater(handler), - txtComparingContentOfFiles(_("Comparing content of files %x")) -{ - if (includeLineBreak) - txtComparingContentOfFiles.Replace(wxT("%x"), wxT("\n\"%x\""), false); - else - txtComparingContentOfFiles.Replace(wxT("%x"), wxT("\"%x\""), false); -} - - -struct MemoryAllocator -{ - MemoryAllocator() - { - buffer1 = new unsigned char[bufferSize]; - buffer2 = new unsigned char[bufferSize]; - } - - ~MemoryAllocator() - { - delete [] buffer1; - delete [] buffer2; - } - - static const unsigned int bufferSize = 1024 * 512; //512 kb seems to be the perfect buffer size - unsigned char* buffer1; - unsigned char* buffer2; -}; - - -bool filesHaveSameContent(const Zstring& filename1, const Zstring& filename2) -{ - static MemoryAllocator memory; - - wxFFile file1(filename1.c_str(), wxT("rb")); - if (!file1.IsOpened()) - throw FileError(Zstring(_("Error reading file:")) + wxT(" \"") + filename1 + wxT("\"")); - - wxFFile file2(filename2.c_str(), wxT("rb")); - if (!file2.IsOpened()) //NO cleanup necessary for (wxFFile) file1 - throw FileError(Zstring(_("Error reading file:")) + wxT(" \"") + filename2 + wxT("\"")); - - do - { - size_t length1 = file1.Read(memory.buffer1, memory.bufferSize); - if (file1.Error()) throw FileError(Zstring(_("Error reading file:")) + wxT(" \"") + filename1 + wxT("\"")); - - size_t length2 = file2.Read(memory.buffer2, memory.bufferSize); - if (file2.Error()) throw FileError(Zstring(_("Error reading file:")) + wxT(" \"") + filename2 + wxT("\"")); - - if (length1 != length2 || memcmp(memory.buffer1, memory.buffer2, length1) != 0) - return false; - } - while (!file1.Eof()); - - if (!file2.Eof()) - return false; - - return true; -} - - -//handle execution of a method while updating the UI -class UpdateWhileComparing : public UpdateWhileExecuting -{ -public: - UpdateWhileComparing() {} - ~UpdateWhileComparing() {} - - Zstring file1; - Zstring file2; - bool success; - Zstring errorMessage; - bool result; - -private: - void longRunner() //virtual method implementation - { - try - { - result = filesHaveSameContent(file1, file2); - success = true; - } - catch (FileError& error) - { - success = false; - errorMessage = error.show(); - } - } -}; - - -bool filesHaveSameContentMultithreaded(const Zstring& filename1, const Zstring& filename2, StatusHandler* updateClass) -{ - static UpdateWhileComparing cmpAndUpdate; //single instantiation: thread enters wait phase after each execution - - cmpAndUpdate.waitUntilReady(); - - //longRunner is called from thread, but no mutex needed here, since thread is in waiting state! - cmpAndUpdate.file1 = filename1; - cmpAndUpdate.file2 = filename2; - - cmpAndUpdate.execute(updateClass); - - //no mutex needed here since longRunner is finished - if (!cmpAndUpdate.success) - throw FileError(cmpAndUpdate.errorMessage); - - return cmpAndUpdate.result; -} - - -void calcTotalDataForCompare(int& objectsTotal, double& dataTotal, const FileCompareResult& grid, const std::set<int>& rowsToCompare) -{ - dataTotal = 0; - - for (std::set<int>::iterator i = rowsToCompare.begin(); i != rowsToCompare.end(); ++i) - { - const FileCompareLine& gridline = grid[*i]; - - dataTotal+= gridline.fileDescrLeft.fileSize.ToDouble(); - dataTotal+= gridline.fileDescrRight.fileSize.ToDouble(); - } - - objectsTotal = rowsToCompare.size() * 2; -} - - -inline -void writeText(const wxChar* text, const int length, wxChar*& currentPos) -{ - memcpy(currentPos, text, length * sizeof(wxChar)); - currentPos+=length; -} - class GetAllFilesFull : public FullDetailFileTraverser { public: - GetAllFilesFull(DirectoryDescrType& output, Zstring dirThatIsSearched, const bool includeLineBreak, StatusHandler* updateClass) : + GetAllFilesFull(DirectoryDescrType& output, Zstring dirThatIsSearched, StatusHandler* handler) : m_output(output), directory(dirThatIsSearched), - statusUpdater(updateClass) + statusHandler(handler) { - assert(updateClass); prefixLength = directory.length(); + textScanning = Zstring(_("Scanning:")) + wxT(" \n"); //performance optimization + } - if (includeLineBreak) - textScanning = Zstring(_("Scanning:")) + wxT("\n"); //performance optimization - else - textScanning = Zstring(_("Scanning:")) + wxT(" "); //performance optimization + + inline + void writeText(const wxChar* text, const int length, wxChar*& currentPos) + { + memcpy(currentPos, text, length * sizeof(wxChar)); + currentPos+=length; } @@ -197,11 +62,11 @@ public: *position = 0; //update UI/commandline status information - statusUpdater->updateStatusText(statusText); + statusHandler->updateStatusText(statusText); //add 1 element to the progress indicator - statusUpdater->updateProcessedData(1, 0); //NO performance issue at all + statusHandler->updateProcessedData(1, 0); //NO performance issue at all //trigger display refresh - statusUpdater->requestUiRefresh(); + statusHandler->requestUiRefresh(); return wxDIR_CONTINUE; } @@ -238,11 +103,11 @@ public: *position = 0; //update UI/commandline status information - statusUpdater->updateStatusText(statusText); + statusHandler->updateStatusText(statusText); //add 1 element to the progress indicator - statusUpdater->updateProcessedData(1, 0); //NO performance issue at all + statusHandler->updateProcessedData(1, 0); //NO performance issue at all //trigger display refresh - statusUpdater->requestUiRefresh(); + statusHandler->requestUiRefresh(); return wxDIR_CONTINUE; } @@ -250,7 +115,20 @@ public: wxDirTraverseResult GetAllFilesFull::OnError(const Zstring& errorText) //virtual impl. { - wxMessageBox(errorText.c_str(), _("Error")); + while (true) + { + ErrorHandler::Response rv = statusHandler->reportError(errorText); + if (rv == ErrorHandler::IGNORE_ERROR) + return wxDIR_CONTINUE; + else if (rv == ErrorHandler::RETRY) + ; //I have to admit "retry" is a bit of a fake here... at least the user has opportunity to abort! + else + { + assert (false); + return wxDIR_CONTINUE; + } + } + return wxDIR_CONTINUE; } @@ -259,25 +137,10 @@ private: Zstring directory; int prefixLength; Zstring textScanning; - StatusHandler* statusUpdater; + StatusHandler* statusHandler; }; -void generateFileAndFolderDescriptions(DirectoryDescrType& output, const Zstring& directory, const bool includeLineBreak, StatusHandler* updateClass) -{ - assert (updateClass); - - output.clear(); - - //get all files and folders from directory (and subdirectories) + information - const Zstring directoryFormatted = FreeFileSync::getFormattedDirectoryName(directory); - - GetAllFilesFull traverser(output, directoryFormatted, includeLineBreak, updateClass); - - traverseInDetail(directoryFormatted, &traverser); -} - - struct DescrBufferLine { Zstring directoryName; @@ -294,9 +157,13 @@ struct DescrBufferLine }; -class DirectoryDescrBuffer //buffer multiple scans of the same directories +class FreeFileSync::DirectoryDescrBuffer //buffer multiple scans of the same directories { public: + DirectoryDescrBuffer(const bool traverseSymbolicLinks, StatusHandler* statusUpdater) : + m_traverseSymbolicLinks(traverseSymbolicLinks), + m_statusUpdater(statusUpdater) {} + ~DirectoryDescrBuffer() { //clean up @@ -304,13 +171,13 @@ public: delete i->directoryDesc; } - DirectoryDescrType* getDirectoryDescription(const Zstring& directory, const bool includeLineBreak, StatusHandler* statusUpdater) + DirectoryDescrType* getDirectoryDescription(const Zstring& directoryFormatted) { DescrBufferLine bufferEntry; - bufferEntry.directoryName = directory; + bufferEntry.directoryName = directoryFormatted; - std::set<DescrBufferLine>::iterator entryFound; - if ((entryFound = buffer.find(bufferEntry)) != buffer.end()) + std::set<DescrBufferLine>::iterator entryFound = buffer.find(bufferEntry); + if (entryFound != buffer.end()) { //entry found in buffer; return return entryFound->directoryDesc; @@ -321,18 +188,234 @@ public: bufferEntry.directoryDesc = new DirectoryDescrType; buffer.insert(bufferEntry); //exception safety: insert into buffer right after creation! - bufferEntry.directoryDesc->reserve(400000); //reserve space for up to 400000 files to avoid vector reallocations + bufferEntry.directoryDesc->reserve(400000); //reserve space for up to 400000 files to avoid too many vector reallocations + + //get all files and folders from directoryFormatted (and subdirectories) + GetAllFilesFull traverser(*bufferEntry.directoryDesc, directoryFormatted, m_statusUpdater); //exceptions may be thrown! + traverseInDetail(directoryFormatted, m_traverseSymbolicLinks, &traverser); - generateFileAndFolderDescriptions(*bufferEntry.directoryDesc, directory, includeLineBreak, statusUpdater); //exceptions may be thrown! return bufferEntry.directoryDesc; } } private: std::set<DescrBufferLine> buffer; + + const bool m_traverseSymbolicLinks; + StatusHandler* m_statusUpdater; }; +bool foldersAreValidForComparison(const std::vector<FolderPair>& folderPairs, wxString& errorMessage) +{ + errorMessage.Clear(); + + for (std::vector<FolderPair>::const_iterator i = folderPairs.begin(); i != folderPairs.end(); ++i) + { + const Zstring leftFolderName = getFormattedDirectoryName(i->leftDirectory); + const Zstring rightFolderName = getFormattedDirectoryName(i->rightDirectory); + + //check if folder name is empty + if (leftFolderName.empty() || rightFolderName.empty()) + { + errorMessage = _("Please fill all empty directory fields."); + return false; + } + + //check if folder exists + if (!wxDirExists(leftFolderName)) + { + errorMessage = wxString(_("Directory does not exist:")) + wxT(" \"") + leftFolderName + wxT("\""); + return false; + } + if (!wxDirExists(rightFolderName)) + { + errorMessage = wxString(_("Directory does not exist:")) + wxT(" \"") + rightFolderName + wxT("\""); + return false; + } + } + return true; +} + + +bool dependencyExists(const std::vector<Zstring>& folders, const Zstring& newFolder, wxString& warningMessage) +{ + warningMessage.Clear(); + + for (std::vector<Zstring>::const_iterator i = folders.begin(); i != folders.end(); ++i) + if (newFolder.StartsWith(*i) || i->StartsWith(newFolder)) + { + warningMessage = wxString(_("Directories are dependent! Be careful when setting up synchronization rules:\n")) + + wxT("\"") + *i + wxT("\",\n") + + wxT("\"") + newFolder + wxT("\""); + return true; + } + return false; +} + + +bool foldersHaveDependencies(const std::vector<FolderPair>& folderPairs, wxString& warningMessage) +{ + warningMessage.Clear(); + + std::vector<Zstring> folders; + for (std::vector<FolderPair>::const_iterator i = folderPairs.begin(); i != folderPairs.end(); ++i) + { + const Zstring leftFolderName = getFormattedDirectoryName(i->leftDirectory); + const Zstring rightFolderName = getFormattedDirectoryName(i->rightDirectory); + + if (dependencyExists(folders, leftFolderName, warningMessage)) + return true; + folders.push_back(leftFolderName); + + if (dependencyExists(folders, rightFolderName, warningMessage)) + return true; + folders.push_back(rightFolderName); + } + + return false; +} + + +CompareProcess::CompareProcess(const bool traverseSymLinks, + const bool handleDstOnFat32Drives, + bool& warningDependentFolders, + StatusHandler* handler) : + traverseSymbolicLinks(traverseSymLinks), + handleDstOnFat32(handleDstOnFat32Drives), + m_warningDependentFolders(warningDependentFolders), + statusUpdater(handler), + txtComparingContentOfFiles(_("Comparing content of files %x")) +{ + descriptionBuffer = new DirectoryDescrBuffer(traverseSymLinks, handler); + txtComparingContentOfFiles.Replace(wxT("%x"), wxT("\n\"%x\""), false); +} + + +CompareProcess::~CompareProcess() +{ + delete descriptionBuffer; +} + + +struct MemoryAllocator +{ + MemoryAllocator() + { + buffer1 = new unsigned char[bufferSize]; + buffer2 = new unsigned char[bufferSize]; + } + + ~MemoryAllocator() + { + delete [] buffer1; + delete [] buffer2; + } + + static const unsigned int bufferSize = 1024 * 512; //512 kb seems to be the perfect buffer size + unsigned char* buffer1; + unsigned char* buffer2; +}; + + +bool filesHaveSameContent(const Zstring& filename1, const Zstring& filename2) +{ + static MemoryAllocator memory; + + wxFFile file1(filename1.c_str(), wxT("rb")); + if (!file1.IsOpened()) + throw FileError(Zstring(_("Error reading file:")) + wxT(" \"") + filename1 + wxT("\"")); + + wxFFile file2(filename2.c_str(), wxT("rb")); + if (!file2.IsOpened()) //NO cleanup necessary for (wxFFile) file1 + throw FileError(Zstring(_("Error reading file:")) + wxT(" \"") + filename2 + wxT("\"")); + + do + { + size_t length1 = file1.Read(memory.buffer1, memory.bufferSize); + if (file1.Error()) throw FileError(Zstring(_("Error reading file:")) + wxT(" \"") + filename1 + wxT("\"")); + + size_t length2 = file2.Read(memory.buffer2, memory.bufferSize); + if (file2.Error()) throw FileError(Zstring(_("Error reading file:")) + wxT(" \"") + filename2 + wxT("\"")); + + if (length1 != length2 || memcmp(memory.buffer1, memory.buffer2, length1) != 0) + return false; + } + while (!file1.Eof()); + + if (!file2.Eof()) + return false; + + return true; +} + + +//handle execution of a method while updating the UI +class UpdateWhileComparing : public UpdateWhileExecuting +{ +public: + UpdateWhileComparing() {} + ~UpdateWhileComparing() {} + + Zstring file1; + Zstring file2; + bool success; + Zstring errorMessage; + bool sameContent; + +private: + void longRunner() //virtual method implementation + { + try + { + sameContent = filesHaveSameContent(file1, file2); + success = true; + } + catch (FileError& error) + { + success = false; + errorMessage = error.show(); + } + } +}; + + +bool filesHaveSameContentMultithreaded(const Zstring& filename1, const Zstring& filename2, StatusHandler* updateClass) +{ + static UpdateWhileComparing cmpAndUpdate; //single instantiation: thread enters wait phase after each execution + + cmpAndUpdate.waitUntilReady(); + + //longRunner is called from thread, but no mutex needed here, since thread is in waiting state! + cmpAndUpdate.file1 = filename1; + cmpAndUpdate.file2 = filename2; + + cmpAndUpdate.execute(updateClass); + + //no mutex needed here since longRunner is finished + if (!cmpAndUpdate.success) + throw FileError(cmpAndUpdate.errorMessage); + + return cmpAndUpdate.sameContent; +} + + +void calcTotalDataForCompare(int& objectsTotal, double& dataTotal, const FileCompareResult& grid, const std::set<int>& rowsToCompare) +{ + dataTotal = 0; + + for (std::set<int>::iterator i = rowsToCompare.begin(); i != rowsToCompare.end(); ++i) + { + const FileCompareLine& gridline = grid[*i]; + + dataTotal+= gridline.fileDescrLeft.fileSize.ToDouble(); + dataTotal+= gridline.fileDescrRight.fileSize.ToDouble(); + } + + objectsTotal = rowsToCompare.size() * 2; +} + + inline bool sameFileTime(const time_t a, const time_t b, const time_t tolerance) { @@ -343,39 +426,70 @@ bool sameFileTime(const time_t a, const time_t b, const time_t tolerance) } -void CompareProcess::startCompareProcess(const std::vector<FolderPair>& directoryPairsFormatted, +void CompareProcess::startCompareProcess(const std::vector<FolderPair>& directoryPairs, const CompareVariant cmpVar, FileCompareResult& output) throw(AbortThisProcess) { #ifndef __WXDEBUG__ wxLogNull noWxLogs; //hide wxWidgets log messages in release build #endif - assert (statusUpdater); - FileCompareResult output_tmp; //write to output not before END of process! + + //format directory pairs + std::vector<FolderPair> directoryPairsFormatted; + + for (std::vector<FolderPair>::const_iterator i = directoryPairs.begin(); i != directoryPairs.end(); ++i) + { + FolderPair newEntry; + newEntry.leftDirectory = FreeFileSync::getFormattedDirectoryName(i->leftDirectory); + newEntry.rightDirectory = FreeFileSync::getFormattedDirectoryName(i->rightDirectory); + directoryPairsFormatted.push_back(newEntry); + } + + //some basic checks: + + //check if folders are valid + wxString errorMessage; + if (!foldersAreValidForComparison(directoryPairsFormatted, errorMessage)) + { + statusUpdater->reportFatalError(errorMessage.c_str()); + return; //should be obsolete! + } + + //check if folders have dependencies + if (m_warningDependentFolders) //test if check should be executed + { + wxString warningMessage; + if (foldersHaveDependencies(directoryPairsFormatted, warningMessage)) + { + bool dontShowAgain = false; + statusUpdater->reportWarning(warningMessage.c_str(), + dontShowAgain); + m_warningDependentFolders = !dontShowAgain; + } + } try { + FileCompareResult output_tmp; //write to output not before END of process! if (cmpVar == CMP_BY_TIME_SIZE) compareByTimeSize(directoryPairsFormatted, output_tmp); else if (cmpVar == CMP_BY_CONTENT) compareByContent(directoryPairsFormatted, output_tmp); else assert(false); + + //only if everything was processed correctly output is written to! output mustn't change to be in sync with GUI grid view!!! + output_tmp.swap(output); } catch (const RuntimeException& theException) { - wxMessageBox(theException.show(), _("An exception occured!"), wxOK | wxICON_ERROR); - statusUpdater->requestAbortion(); - return; + statusUpdater->reportFatalError(theException.show().c_str()); + return; //should be obsolete! } catch (std::bad_alloc& e) { - wxMessageBox(wxString(_("System out of memory!")) + wxT(" ") + wxString::From8BitData(e.what()), _("An exception occured!"), wxOK | wxICON_ERROR); - statusUpdater->requestAbortion(); - return; + statusUpdater->reportFatalError((wxString(_("System out of memory!")) + wxT(" ") + wxString::From8BitData(e.what())).c_str()); + return; //should be obsolete! } - - //only if everything was processed correctly output is written to! - output_tmp.swap(output); } @@ -384,20 +498,17 @@ void CompareProcess::compareByTimeSize(const std::vector<FolderPair>& directoryP //inform about the total amount of data that will be processed from now on statusUpdater->initNewProcess(-1, 0, StatusHandler::PROCESS_SCANNING); //it's not known how many files will be scanned => -1 objects - //buffer accesses to the same directories; useful when multiple folder pairs are used - DirectoryDescrBuffer descriptionBuffer; - //process one folder pair after each other unsigned tableSizeOld = 0; for (std::vector<FolderPair>::const_iterator pair = directoryPairsFormatted.begin(); pair != directoryPairsFormatted.end(); ++pair) { //do basis scan: only result lines of type FILE_UNDEFINED (files that exist on both sides) need to be determined after this call - this->performBaseComparison(*pair, descriptionBuffer, output); + this->performBaseComparison(*pair, output); //add some tolerance if one of the folders is FAT/FAT32 time_t tolerance = 0; #ifdef FFS_WIN - if (handleDstOnFat32 && (isFatDrive(pair->leftDirectory) || isFatDrive(pair->leftDirectory))) + if (handleDstOnFat32 && (isFatDrive(pair->leftDirectory) || isFatDrive(pair->rightDirectory))) tolerance = FILE_TIME_PRECISION + 3600; //tolerate filetime diff <= 1 h to handle daylight saving time issues else tolerance = FILE_TIME_PRECISION; @@ -437,14 +548,11 @@ void CompareProcess::compareByContent(const std::vector<FolderPair>& directoryPa //inform about the total amount of data that will be processed from now on statusUpdater->initNewProcess(-1, 0, StatusHandler::PROCESS_SCANNING); //it's not known how many files will be scanned => -1 objects - //buffer accesses to the same directories; useful when multiple folder pairs are used - DirectoryDescrBuffer descriptionBuffer; - //process one folder pair after each other for (std::vector<FolderPair>::const_iterator pair = directoryPairsFormatted.begin(); pair != directoryPairsFormatted.end(); ++pair) { //do basis scan: only result lines of type FILE_UNDEFINED (files that exist on both sides) need to be determined after this call - this->performBaseComparison(*pair, descriptionBuffer, output); + this->performBaseComparison(*pair, output); } @@ -526,7 +634,7 @@ public: m_directory(directory) { if (Create() != wxTHREAD_NO_ERROR) - throw RuntimeException(wxString(wxT("Error starting thread for sorting!"))); + throw RuntimeException(wxString(wxT("Error creating thread for sorting!"))); } ~ThreadSorting() {} @@ -543,12 +651,12 @@ private: }; -void CompareProcess::performBaseComparison(const FolderPair& pair, DirectoryDescrBuffer& descriptionBuffer, FileCompareResult& output) +void CompareProcess::performBaseComparison(const FolderPair& pair, FileCompareResult& output) { //PERF_START; //retrieve sets of files (with description data) - DirectoryDescrType* directoryLeft = descriptionBuffer.getDirectoryDescription(pair.leftDirectory, includeLineBreak, statusUpdater); - DirectoryDescrType* directoryRight = descriptionBuffer.getDirectoryDescription(pair.rightDirectory, includeLineBreak, statusUpdater); + DirectoryDescrType* directoryLeft = descriptionBuffer->getDirectoryDescription(pair.leftDirectory); + DirectoryDescrType* directoryRight = descriptionBuffer->getDirectoryDescription(pair.rightDirectory); statusUpdater->updateStatusText(_("Generating file list...")); statusUpdater->forceUiRefresh(); //keep total number of scanned files up to date @@ -559,16 +667,23 @@ void CompareProcess::performBaseComparison(const FolderPair& pair, DirectoryDesc { //no synchronization (multithreading) needed here: directoryLeft and directoryRight are disjunct //reference counting Zstring also shouldn't be an issue, as no strings are deleted during std::sort() - ThreadSorting sortLeft(directoryLeft); - ThreadSorting sortRight(directoryRight); + std::auto_ptr<ThreadSorting> sortLeft(new ThreadSorting(directoryLeft)); + std::auto_ptr<ThreadSorting> sortRight(new ThreadSorting(directoryRight)); + + if (sortLeft->Run() != wxTHREAD_NO_ERROR) + throw RuntimeException(wxString(wxT("Error starting thread for sorting!"))); - sortLeft.Run(); if (directoryLeft != directoryRight) //attention: might point to the same vector because of buffer! { - sortRight.Run(); - sortRight.Wait(); + if (sortRight->Run() != wxTHREAD_NO_ERROR) + throw RuntimeException(wxString(wxT("Error starting thread for sorting!"))); + + if (sortRight->Wait() != 0) + throw RuntimeException(wxString(wxT("Error waiting for thread (sorting)!"))); } - sortLeft.Wait(); + + if (sortLeft->Wait() != 0) + throw RuntimeException(wxString(wxT("Error waiting for thread (sorting)!"))); } else //single threaded { @@ -579,14 +694,14 @@ void CompareProcess::performBaseComparison(const FolderPair& pair, DirectoryDesc } //PERF_STOP; - //reserve some space to avoid vector reallocations + //reserve some space to avoid too many vector reallocations output.reserve(output.size() + unsigned(std::max(directoryLeft->size(), directoryRight->size()) * 1.2)); //begin base comparison FileCompareLine newline; DirectoryDescrType::iterator j; - for (DirectoryDescrType::iterator i = directoryLeft->begin(); i != directoryLeft->end(); ++i) - { //find files/folders that exist in left file model but not in right model + for (DirectoryDescrType::const_iterator i = directoryLeft->begin(); i != directoryLeft->end(); ++i) + { //find files/folders that exist in left file tree but not in right one if ((j = custom_binary_search(directoryRight->begin(), directoryRight->end(), *i)) == directoryRight->end()) { newline.fileDescrLeft = *i; @@ -595,7 +710,7 @@ void CompareProcess::performBaseComparison(const FolderPair& pair, DirectoryDesc newline.cmpResult = FILE_LEFT_SIDE_ONLY; output.push_back(newline); } - //find files/folders that exist in left and right file model + //find files/folders that exist on left and right side else { const FileDescrLine::ObjectType typeLeft = i->objType; @@ -638,7 +753,7 @@ void CompareProcess::performBaseComparison(const FolderPair& pair, DirectoryDesc } - for (DirectoryDescrType::iterator j = directoryRight->begin(); j != directoryRight->end(); ++j) + for (DirectoryDescrType::const_iterator j = directoryRight->begin(); j != directoryRight->end(); ++j) { //find files/folders that exist in right file model but not in left model if (custom_binary_search(directoryLeft->begin(), directoryLeft->end(), *j) == directoryLeft->end()) @@ -653,75 +768,3 @@ void CompareProcess::performBaseComparison(const FolderPair& pair, DirectoryDesc //PERF_STOP } - - -bool FreeFileSync::foldersAreValidForComparison(const std::vector<FolderPair>& folderPairs, wxString& errorMessage) -{ - errorMessage.Clear(); - - for (std::vector<FolderPair>::const_iterator i = folderPairs.begin(); i != folderPairs.end(); ++i) - { - const Zstring leftFolderName = getFormattedDirectoryName(i->leftDirectory); - const Zstring rightFolderName = getFormattedDirectoryName(i->rightDirectory); - - //check if folder name is empty - if (leftFolderName.empty() || rightFolderName.empty()) - { - errorMessage = _("Please fill all empty directory fields."); - return false; - } - - //check if folder exists - if (!wxDirExists(leftFolderName)) - { - errorMessage = wxString(_("Directory does not exist:")) + wxT(" \"") + leftFolderName + wxT("\""); - return false; - } - if (!wxDirExists(rightFolderName)) - { - errorMessage = wxString(_("Directory does not exist:")) + wxT(" \"") + rightFolderName + wxT("\""); - return false; - } - } - return true; -} - - -bool dependencyExists(const std::vector<Zstring>& folders, const Zstring& newFolder, wxString& warningMessage) -{ - warningMessage.Clear(); - - for (std::vector<Zstring>::const_iterator i = folders.begin(); i != folders.end(); ++i) - if (newFolder.StartsWith(*i) || i->StartsWith(newFolder)) - { - warningMessage = wxString(_("Directories are dependent:")) + - wxT(" \n\"") + *i + wxT("\"") + wxT(", \n") + wxT("\"") + newFolder + wxT("\""); - return true; - } - - return false; -} - - -bool FreeFileSync::foldersHaveDependencies(const std::vector<FolderPair>& folderPairs, wxString& warningMessage) -{ - warningMessage.Clear(); - - std::vector<Zstring> folders; - for (std::vector<FolderPair>::const_iterator i = folderPairs.begin(); i != folderPairs.end(); ++i) - { - const Zstring leftFolderName = getFormattedDirectoryName(i->leftDirectory); - const Zstring rightFolderName = getFormattedDirectoryName(i->rightDirectory); - - if (dependencyExists(folders, leftFolderName, warningMessage)) - return true; - folders.push_back(leftFolderName); - - if (dependencyExists(folders, rightFolderName, warningMessage)) - return true; - folders.push_back(rightFolderName); - } - - return false; -} - |