summaryrefslogtreecommitdiff
path: root/FreeFileSync.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'FreeFileSync.cpp')
-rw-r--r--FreeFileSync.cpp540
1 files changed, 288 insertions, 252 deletions
diff --git a/FreeFileSync.cpp b/FreeFileSync.cpp
index 09e8efb8..af0da109 100644
--- a/FreeFileSync.cpp
+++ b/FreeFileSync.cpp
@@ -2,13 +2,15 @@
#include <wx/dir.h>
#include <wx/msgdlg.h>
#include "FreeFileSync.h"
-#include "library\md5.h"
-#include <stdexcept> //for std::runtime_error
#include "library/globalFunctions.h"
-#include "library/gmp/include\gmp.h"
#include <wx/filename.h>
#include <fstream>
-#include "ui\resources.h"
+#include "ui/resources.h"
+#include <sys/stat.h>
+
+#ifdef FFS_WIN
+#include <windows.h>
+#endif // FFS_WIN
using namespace globalFunctions;
@@ -40,38 +42,9 @@ wxString formatTime(unsigned int number)
}
-bool filetimeCmpEqual(const FILETIME a,const FILETIME b)
-{
- if (a.dwHighDateTime == b.dwHighDateTime && a.dwLowDateTime == b.dwLowDateTime)
- return (true);
- else
- return (false);
-}
-
void FreeFileSync::getFileInformation(FileInfo& output, const wxString& filename)
{
-//
-// wxFileName file(filename);
-//
-// wxDateTime lastWriteTime;
-// wxULongLong filesize;
-//
-//
-//
-// if (file.FileExists())
-// {
-// if (!file.GetTimes(NULL, &lastWriteTime, NULL) || ((filesize = file.GetSize()) == wxInvalidSize))
-// throw FileError(wxString(_("Could not retrieve file info for: ")) + "\"" + filename + "\"");
-// output.lastWriteTime = lastWriteTime.FormatISODate();
-//
-// output.lastWriteTimeUTC.dwHighDateTime = 0;
-// output.lastWriteTimeUTC.dwLowDateTime = 0;
-// }
-//
-// output.fileSize = filesize.ToString();
-//
-
-
+#ifdef FFS_WIN
WIN32_FIND_DATA winFileInfo;
FILETIME localFileTime;
SYSTEMTIME time;
@@ -83,15 +56,15 @@ void FreeFileSync::getFileInformation(FileInfo& output, const wxString& filename
FindClose(fileHandle);
if (FileTimeToLocalFileTime(
- &winFileInfo.ftLastWriteTime, // pointer to UTC file time to convert
- &localFileTime // pointer to converted file time
+ &winFileInfo.ftLastWriteTime, // pointer to UTC file time to convert
+ &localFileTime // pointer to converted file time
) == 0)
throw std::runtime_error(_("Error converting FILETIME to local FILETIME"));
if (FileTimeToSystemTime(
&localFileTime, // pointer to file time to convert
- &time // pointer to structure to receive system time
+ &time // pointer to structure to receive system time
) == 0)
throw std::runtime_error(_("Error converting FILETIME to SYSTEMTIME"));
@@ -102,40 +75,93 @@ void FreeFileSync::getFileInformation(FileInfo& output, const wxString& filename
formatTime(time.wMinute) + ":" +
formatTime(time.wSecond);
- //UTC times
- output.lastWriteTimeUTC = wxULongLong(winFileInfo.ftLastWriteTime.dwHighDateTime, winFileInfo.ftLastWriteTime.dwLowDateTime);
+ //UTC time
+ output.lastWriteTimeRaw = wxULongLong(winFileInfo.ftLastWriteTime.dwHighDateTime, winFileInfo.ftLastWriteTime.dwLowDateTime);
+
+ //reduce precision to 1 second (FILETIME has unit 10^-7 s)
+ output.lastWriteTimeRaw/= 10000000; // <- time is used for comparison only: unit switched to seconds
output.fileSize = wxULongLong(winFileInfo.nFileSizeHigh, winFileInfo.nFileSizeLow);
+
+#else
+ struct stat fileInfo;
+ if (stat (filename.c_str(), &fileInfo) != 0)
+ throw FileError(wxString(_("Could not retrieve file info for: ")) + "\"" + filename + "\"");
+
+ struct tm * timeinfo;
+ timeinfo = localtime(&fileInfo.st_mtime);
+ char buffer [50];
+ strftime (buffer,50,"%Y-%m-%d %H:%M:%S",timeinfo);
+
+ //local time
+ output.lastWriteTime = buffer;
+ //unit: 1 second
+ output.lastWriteTimeRaw = fileInfo.st_mtime;
+
+ output.fileSize = fileInfo.st_size;
+#endif
}
-string FreeFileSync::calculateMD5Hash(const wxString& filename)
+struct MemoryAllocator
{
- const unsigned int bufferSize = 8192;
+ MemoryAllocator()
+ {
+ buffer1 = new unsigned char[bufferSize];
+ buffer2 = new unsigned char[bufferSize];
+ }
- char md5_output[33];
- unsigned char signature[16];
- unsigned char buffer[bufferSize];
- md5_t state;
+ ~MemoryAllocator()
+ {
+ delete [] buffer1;
+ delete [] buffer2;
+ }
- md5_init(&state);
- FILE* inputFile = fopen( filename.c_str(), "rb");
- if (!inputFile)
- throw FileError(wxString(_("Could not open file: ")) + "\"" + filename + "\"");
- do
+ static const unsigned int bufferSize = 1024*256; //256 kb seems to be the perfect buffer size
+ unsigned char* buffer1;
+ unsigned char* buffer2;
+};
+
+
+bool filesHaveSameContent(const wxString& filename1, const wxString& filename2)
+{
+ static MemoryAllocator memory;
+
+ FILE* file1 = fopen(filename1.c_str(), "rb");
+ if (!file1)
+ throw FileError(wxString(_("Could not open file: ")) + "\"" + filename1 + "\"");
+
+ FILE* file2 = fopen(filename2.c_str(), "rb");
+ if (!file2)
{
- unsigned int length = fread(buffer, 1, bufferSize, inputFile);
- if (!ferror(inputFile)) md5_process(&state, buffer, length);
+ fclose(file1); //NEVER forget clean-up
+ throw FileError(wxString(_("Could not open file: ")) + "\"" + filename2 + "\"");
}
- while (!feof(inputFile));
- fclose(inputFile);
+ bool returnValue = true;
+ do
+ {
+ unsigned int length1 = fread(memory.buffer1, 1, memory.bufferSize, file1);
+ if (ferror(file1)) throw FileError(wxString(_("Error reading file: ")) + "\"" + filename1 + "\"");
+
+ unsigned int length2 = fread(memory.buffer2, 1, memory.bufferSize, file2);
+ if (ferror(file2)) throw FileError(wxString(_("Error reading file: ")) + "\"" + filename2 + "\"");
+
+ if (length1 != length2 || memcmp(memory.buffer1, memory.buffer2, length1) != 0)
+ {
+ returnValue = false;
+ break;
+ }
+ }
+ while (!feof(file1));
- md5_finish(&state, signature);
+ if (!feof(file2))
+ returnValue = false;
- for (int i=0;i<16;i++) sprintf(md5_output + i*2, "%02x", signature[i]);
+ fclose(file1);
+ fclose(file2);
- return md5_output;
+ return returnValue;
}
@@ -153,23 +179,24 @@ void FreeFileSync::generateFileAndFolderDescriptions(DirectoryDescrType& output,
//handle execution of a method while updating the UI
-class UpdateWhileCalculatingMD5 : public UpdateWhileExecuting
+class UpdateWhileComparing : public UpdateWhileExecuting
{
public:
- UpdateWhileCalculatingMD5() {}
- ~UpdateWhileCalculatingMD5() {}
+ UpdateWhileComparing() {}
+ ~UpdateWhileComparing() {}
- wxString file;
+ wxString file1;
+ wxString file2;
bool success;
wxString errorMessage;
- string result;
+ bool result;
private:
void longRunner() //virtual method implementation
{
try
{
- result = FreeFileSync::calculateMD5Hash(file);
+ result = filesHaveSameContent(file1, file2);
success = true;
}
catch (FileError& error)
@@ -181,30 +208,31 @@ private:
};
-string FreeFileSync::calculateMD5HashMultithreaded(const wxString& filename, StatusUpdater* updateClass)
+bool filesHaveSameContentMultithreaded(const wxString& filename1, const wxString& filename2, StatusUpdater* updateClass)
{
- static UpdateWhileCalculatingMD5 calcAndUpdate; //single instantiation: after each execution thread enters wait phase
+ static UpdateWhileComparing cmpAndUpdate; //single instantiation: thread enters wait phase after each execution
- calcAndUpdate.waitUntilReady();
+ cmpAndUpdate.waitUntilReady();
//longRunner is called from thread, but no mutex needed here, since thread is in waiting state!
- calcAndUpdate.file = filename;
+ cmpAndUpdate.file1 = filename1;
+ cmpAndUpdate.file2 = filename2;
- calcAndUpdate.execAndUpdate(updateClass);
+ cmpAndUpdate.execute(updateClass);
//no mutex needed here since longRunner is finished
- if (!calcAndUpdate.success)
- throw FileError(calcAndUpdate.errorMessage);
+ if (!cmpAndUpdate.success)
+ throw FileError(cmpAndUpdate.errorMessage);
- return calcAndUpdate.result;
+ return cmpAndUpdate.result;
}
-void calcTotalDataForMD5(int& objectsTotal, double& dataTotal, const FileCompareResult& grid, const set<int>& rowsForMD5)
+void calcTotalDataForCompare(int& objectsTotal, double& dataTotal, const FileCompareResult& grid, const set<int>& rowsToCompare)
{
dataTotal = 0;
- for (set<int>::iterator i = rowsForMD5.begin(); i != rowsForMD5.end(); ++i)
+ for (set<int>::iterator i = rowsToCompare.begin(); i != rowsToCompare.end(); ++i)
{
const FileCompareLine& gridline = grid[*i];
@@ -212,7 +240,7 @@ void calcTotalDataForMD5(int& objectsTotal, double& dataTotal, const FileCompare
dataTotal+= gridline.fileDescrRight.fileSize.ToDouble();
}
- objectsTotal = rowsForMD5.size() * 2;
+ objectsTotal = rowsToCompare.size() * 2;
}
@@ -232,15 +260,19 @@ void FreeFileSync::startCompareProcess(FileCompareResult& output, const wxString
//retrieve sets of files (with description data)
DirectoryDescrType directoryLeft;
DirectoryDescrType directoryRight;
+
+ //unsigned int startTime = GetTickCount();
generateFileAndFolderDescriptions(directoryLeft, dirLeft, statusUpdater);
generateFileAndFolderDescriptions(directoryRight, dirRight, statusUpdater);
+ //wxMessageBox(numberToWxString(unsigned(GetTickCount()) - startTime));
FileCompareLine newline;
- set<int> delayedMD5calculation; //md5 calculation happens AFTER compare in order to separate into two processe (needed by progress indicators)
+ set<int> delayedContentCompare; //compare of file content happens AFTER finding corresponding files
+ //in order to separate into two processe (needed by progress indicators)
//find files/folders that exist in left file model but not in right model
- for (DirectoryDescrType::iterator i = directoryLeft.begin(); i != directoryLeft.end(); i++)
+ for (DirectoryDescrType::iterator i = directoryLeft.begin(); i != directoryLeft.end(); ++i)
if (directoryRight.find(*i) == directoryRight.end())
{
newline.fileDescrLeft = *i;
@@ -250,7 +282,7 @@ void FreeFileSync::startCompareProcess(FileCompareResult& output, const wxString
output_tmp.push_back(newline);
}
- for (DirectoryDescrType::iterator j = directoryRight.begin(); j != directoryRight.end(); j++)
+ for (DirectoryDescrType::iterator j = directoryRight.begin(); j != directoryRight.end(); ++j)
{
DirectoryDescrType::iterator i;
@@ -290,15 +322,15 @@ void FreeFileSync::startCompareProcess(FileCompareResult& output, const wxString
}
else if (cmpVar == compareByTimeAndSize)
{ //check files that exist in left and right model but have different properties
- if (i->lastWriteTimeUTC != j->lastWriteTimeUTC ||
+ if (i->lastWriteTimeRaw != j->lastWriteTimeRaw ||
i->fileSize != j->fileSize)
{
newline.fileDescrLeft = *i;
newline.fileDescrRight = *j;
- if (i->lastWriteTimeUTC == j->lastWriteTimeUTC)
+ if (i->lastWriteTimeRaw == j->lastWriteTimeRaw)
newline.cmpResult = filesDifferent;
- else if (i->lastWriteTimeUTC < j->lastWriteTimeUTC)
+ else if (i->lastWriteTimeRaw < j->lastWriteTimeRaw)
newline.cmpResult = rightFileNewer;
else
newline.cmpResult = leftFileNewer;
@@ -312,7 +344,7 @@ void FreeFileSync::startCompareProcess(FileCompareResult& output, const wxString
output_tmp.push_back(newline);
}
}
- else if (cmpVar == compareByMD5)
+ else if (cmpVar == compareByContent)
{ //check files that exist in left and right model but have different content
//check filesize first!
@@ -323,8 +355,8 @@ void FreeFileSync::startCompareProcess(FileCompareResult& output, const wxString
//newline.cmpResult = ...; //not yet determined
output_tmp.push_back(newline);
- //md5 needed only if filesizes are the same
- delayedMD5calculation.insert(output_tmp.size() - 1); //save index of row, to calculate cmpResult later
+ //compare by content is only needed if filesizes are the same
+ delayedContentCompare.insert(output_tmp.size() - 1); //save index of row, to calculate cmpResult later
}
else
{
@@ -339,25 +371,27 @@ void FreeFileSync::startCompareProcess(FileCompareResult& output, const wxString
}
//################################################################################################################################################
- //calculate MD5 checksums and set value "cmpResult"
- if (cmpVar == compareByMD5)
+
+ //compare file contents and set value "cmpResult"
+
+ //unsigned int startTime3 = GetTickCount();
+ if (cmpVar == compareByContent)
{
int objectsTotal = 0;
double dataTotal = 0;
- calcTotalDataForMD5(objectsTotal, dataTotal, output_tmp, delayedMD5calculation);
+ calcTotalDataForCompare(objectsTotal, dataTotal, output_tmp, delayedContentCompare);
- statusUpdater->initNewProcess(objectsTotal, dataTotal, FreeFileSync::calcMD5Process);
+ statusUpdater->initNewProcess(objectsTotal, dataTotal, FreeFileSync::compareFileContentProcess);
set<int> rowsToDelete; //if errors occur during file access and user skips, these rows need to be deleted from result
- for (set<int>::iterator i = delayedMD5calculation.begin(); i != delayedMD5calculation.end(); ++i)
+ for (set<int>::iterator i = delayedContentCompare.begin(); i != delayedContentCompare.end(); ++i)
{
FileCompareLine& gridline = output_tmp[*i];
- //check files that exist in left and right model but have different checksums
- string leftFileHash;
- string rightFileHash;
+ statusUpdater->updateStatusText(wxString(_("Comparing content of files ")) + "\"" + gridline.fileDescrLeft.relFilename + "\"");
+ //check files that exist in left and right model but have different content
while (true)
{
//trigger display refresh
@@ -365,25 +399,12 @@ void FreeFileSync::startCompareProcess(FileCompareResult& output, const wxString
try
{
- if (leftFileHash.empty())
- {
- statusUpdater->updateStatusText(wxString(_("Reading content of ") + gridline.fileDescrLeft.filename));
- leftFileHash = calculateMD5HashMultithreaded(gridline.fileDescrLeft.filename, statusUpdater);
- statusUpdater->updateProcessedData(1, gridline.fileDescrLeft.fileSize.ToDouble());
- }
-
- if (rightFileHash.empty())
- {
- statusUpdater->updateStatusText(wxString(_("Reading content of ") + gridline.fileDescrRight.filename));
- rightFileHash = calculateMD5HashMultithreaded(gridline.fileDescrRight.filename, statusUpdater);
- statusUpdater->updateProcessedData(1, gridline.fileDescrRight.fileSize.ToDouble());
- }
-
- if (leftFileHash == rightFileHash)
+ if (filesHaveSameContentMultithreaded(gridline.fileDescrLeft.filename, gridline.fileDescrRight.filename, statusUpdater))
gridline.cmpResult = filesEqual;
else
gridline.cmpResult = filesDifferent;
+ statusUpdater->updateProcessedData(2, (gridline.fileDescrLeft.fileSize + gridline.fileDescrRight.fileSize).ToDouble());
break;
}
catch (FileError& error)
@@ -407,6 +428,7 @@ void FreeFileSync::startCompareProcess(FileCompareResult& output, const wxString
if (rowsToDelete.size() > 0)
removeRowsFromVector(output_tmp, rowsToDelete);
}
+ //wxMessageBox(numberToWxString(unsigned(GetTickCount()) - startTime3));
statusUpdater->triggerUI_Refresh();
}
@@ -479,13 +501,13 @@ wxDirTraverseResult GetAllFilesFull::OnFile(const wxString& filename)
}
fileDescr.lastWriteTime = currentFileInfo.lastWriteTime;
- fileDescr.lastWriteTimeUTC = currentFileInfo.lastWriteTimeUTC;
+ fileDescr.lastWriteTimeRaw = currentFileInfo.lastWriteTimeRaw;
fileDescr.fileSize = currentFileInfo.fileSize;
fileDescr.objType = isFile;
m_output.insert(fileDescr);
//update UI/commandline status information
- statusUpdater->updateStatusText(wxString(_("Scanning ")) + filename); // NO performance issue at all
+ statusUpdater->updateStatusText(wxString(_("Scanning ")) + "\"" + filename + "\""); // NO performance issue at all
//add 1 element to the progress indicator
statusUpdater->updateProcessedData(1, 0); // NO performance issue at all
//trigger display refresh
@@ -497,9 +519,8 @@ wxDirTraverseResult GetAllFilesFull::OnFile(const wxString& filename)
wxDirTraverseResult GetAllFilesFull::OnDir(const wxString& dirname)
{
- if (dirname.EndsWith("\\RECYCLER"))
- return wxDIR_IGNORE;
- if (dirname.EndsWith("\\System Volume Information"))
+ if (dirname.EndsWith("\\RECYCLER") ||
+ dirname.EndsWith("\\System Volume Information"))
return wxDIR_IGNORE;
fileDescr.filename = dirname;
@@ -525,13 +546,13 @@ wxDirTraverseResult GetAllFilesFull::OnDir(const wxString& dirname)
}
}
fileDescr.lastWriteTime = currentFileInfo.lastWriteTime;
- fileDescr.lastWriteTimeUTC = currentFileInfo.lastWriteTimeUTC;
+ fileDescr.lastWriteTimeRaw = currentFileInfo.lastWriteTimeRaw;
fileDescr.fileSize = wxULongLong(0); //currentFileInfo.fileSize should be "0" as well, but just to be sure... currently used by getBytesToTransfer
fileDescr.objType = isDirectory;
m_output.insert(fileDescr);
//update UI/commandline status information
- statusUpdater->updateStatusText(wxString(_("Scanning ")) + dirname); // NO performance issue at all
+ statusUpdater->updateStatusText(wxString(_("Scanning ")) + "\"" + dirname + "\""); // NO performance issue at all
//add 1 element to the progress indicator
statusUpdater->updateProcessedData(1, 0); // NO performance issue at all
//trigger display refresh
@@ -583,25 +604,82 @@ private:
};
-void FreeFileSync::moveToRecycleBin(const wxString& filename)
+#ifdef FFS_WIN
+typedef WINSHELLAPI int (*DllFileOP)(LPSHFILEOPSTRUCT lpFileOp);
+#endif // FFS_WIN
+
+
+class RecycleBin
{
- bool aborted = false;
- SHFILEOPSTRUCT fileOp;
-
- wxString filenameDoubleNull = filename + char(0);
-
- fileOp.hwnd = NULL;
- fileOp.wFunc = FO_DELETE;
- fileOp.pFrom = filenameDoubleNull.c_str();
- fileOp.pTo = NULL;
- fileOp.fFlags = FOF_ALLOWUNDO | FOF_NOCONFIRMATION | FOF_SILENT;
- fileOp.fAnyOperationsAborted = aborted;
- fileOp.hNameMappings = NULL;
- fileOp.lpszProgressTitle = NULL;
-
- if (fileOperation(&fileOp //Pointer to an SHFILEOPSTRUCT structure that contains information the function needs to carry out.
- ) != 0 || aborted) throw FileError(wxString(_("Error moving file ")) + "\"" + filename + "\"" + _(" to recycle bin!"));
-}
+public:
+ RecycleBin() :
+ recycleBinAvailable(false)
+ {
+#ifdef FFS_WIN
+ // Get a handle to the DLL module containing Recycle Bin functionality
+ hinstShell = LoadLibrary("shell32.dll");
+ if (hinstShell != NULL)
+ {
+ fileOperation = (DllFileOP)GetProcAddress(hinstShell, "SHFileOperation");
+ if (fileOperation == NULL )
+ {
+ FreeLibrary(hinstShell);
+ recycleBinAvailable = false;
+ }
+ else
+ recycleBinAvailable = true;
+ }
+#endif // FFS_WIN
+ }
+
+ ~RecycleBin()
+ {
+#ifdef FFS_WIN
+ if (recycleBinAvailable)
+ FreeLibrary(hinstShell);
+#endif // FFS_WIN
+ }
+
+ bool recycleBinExists()
+ {
+ return recycleBinAvailable;
+ }
+
+ void moveToRecycleBin(const wxString& filename)
+ {
+ if (!recycleBinAvailable) //this method should ONLY be called if recycle bin is available
+ throw std::runtime_error("Initialization of Recycle Bin failed! It cannot be used!");
+
+#ifdef FFS_WIN
+ SHFILEOPSTRUCT fileOp;
+
+ wxString filenameDoubleNull = filename + char(0);
+
+ fileOp.hwnd = NULL;
+ fileOp.wFunc = FO_DELETE;
+ fileOp.pFrom = filenameDoubleNull.c_str();
+ fileOp.pTo = NULL;
+ fileOp.fFlags = FOF_ALLOWUNDO | FOF_NOCONFIRMATION | FOF_SILENT;
+ fileOp.fAnyOperationsAborted = false;
+ fileOp.hNameMappings = NULL;
+ fileOp.lpszProgressTitle = NULL;
+
+ if (fileOperation(&fileOp //Pointer to an SHFILEOPSTRUCT structure that contains information the function needs to carry out.
+ ) != 0 || fileOp.fAnyOperationsAborted) throw FileError(wxString(_("Error moving file ")) + "\"" + filename + "\"" + _(" to recycle bin!"));
+#endif // FFS_WIN
+ }
+
+private:
+ bool recycleBinAvailable;
+
+#ifdef FFS_WIN
+ HINSTANCE hinstShell;
+ DllFileOP fileOperation;
+#endif // FFS_WIN
+};
+
+
+RecycleBin FreeFileSync::recycler;
inline
@@ -609,9 +687,9 @@ void FreeFileSync::removeFile(const wxString& filename)
{
if (!wxFileExists(filename)) return; //this is NOT an error situation: the manual deletion relies on it!
- if (recycleBinAvailable)
+ if (recycleBinShouldBeUsed)
{
- moveToRecycleBin(filename);
+ recycler.moveToRecycleBin(filename);
return;
}
@@ -631,9 +709,9 @@ void FreeFileSync::removeDirectory(const wxString& directory)
{
if (!wxDirExists(directory)) return; //this is NOT an error situation: the manual deletion relies on it!
- if (recycleBinAvailable)
+ if (recycleBinShouldBeUsed)
{
- moveToRecycleBin(directory);
+ recycler.moveToRecycleBin(directory);
return;
}
@@ -660,27 +738,6 @@ void FreeFileSync::removeDirectory(const wxString& directory)
}
-inline
-void FreeFileSync::copyfile(const wxString& source, const wxString& target)
-{
- if (!wxCopyFile(source, target, false)) //return false if file exists
- throw FileError(wxString(_("Error copying file ")) + "\"" + source + "\"" + _(" to ") + "\"" + target + "\"");
-}
-
-
-inline
-void FreeFileSync::copyOverwriting(const wxString& source, const wxString& target)
-{
- if (!SetFileAttributes(
- target.c_str(), // address of filename
- FILE_ATTRIBUTE_NORMAL // address of attributes to set
- )) throw FileError(wxString(_("Error overwriting file ")) + "\"" + target + "\"");
-
- if (!wxCopyFile(source, target, true)) //if file exists it will be overwritten
- throw FileError(wxString(_("Error copying file ")) + "\"" + source + "\"" + _(" to ") + "\"" + target + "\"");
-}
-
-
void FreeFileSync::createDirectory(const wxString& directory, int level)
{
if (wxDirExists(directory))
@@ -708,7 +765,7 @@ void FreeFileSync::createDirectory(const wxString& directory, int level)
}
}
-
+/*
void FreeFileSync::copyCreatingDirs(const wxString& source, const wxString& target)
{
wxString targetPath = wxFileName(target).GetPath();
@@ -717,7 +774,7 @@ void FreeFileSync::copyCreatingDirs(const wxString& source, const wxString& targ
if (!wxCopyFile(source, target, false)) //error if file exists
throw FileError(wxString(_("Error copying file ")) + "\"" + source + "\"" + _(" to ") + "\"" + target + "\"");
}
-
+*/
//###########################################################################################
@@ -749,7 +806,7 @@ private:
void FreeFileSync::copyfileMultithreaded(const wxString& source, const wxString& target, StatusUpdater* updateClass)
{
- static UpdateWhileCopying copyAndUpdate; //single instantiation: after each execution thread enters wait phase
+ static UpdateWhileCopying copyAndUpdate; //single instantiation: after each execution thread enters wait phase
copyAndUpdate.waitUntilReady();
@@ -757,7 +814,7 @@ void FreeFileSync::copyfileMultithreaded(const wxString& source, const wxString&
copyAndUpdate.source = source;
copyAndUpdate.target = target;
- copyAndUpdate.execAndUpdate(updateClass);
+ copyAndUpdate.execute(updateClass);
//no mutex needed here since longRunner is finished
if (!copyAndUpdate.success)
@@ -765,25 +822,9 @@ void FreeFileSync::copyfileMultithreaded(const wxString& source, const wxString&
}
-FreeFileSync::FreeFileSync()
- : recycleBinAvailable(false)
+FreeFileSync::FreeFileSync(bool useRecycleBin) :
+ recycleBinShouldBeUsed(useRecycleBin)
{
- // Get a handle to the DLL module containing Recycle Bin functionality
- hinstShell = LoadLibrary("shell32.dll");
- if (hinstShell == NULL)
- recycleBinAvailable = false;
- else
- {
- fileOperation = (DLLFUNC)GetProcAddress(hinstShell, "SHFileOperation");
- if (fileOperation == NULL )
- {
- FreeLibrary(hinstShell);
- recycleBinAvailable = false;
- }
- else
- recycleBinAvailable = true;
- }
-
//prevent wxWidgets logging
noWxLogs = new wxLogNull;
}
@@ -791,27 +832,13 @@ FreeFileSync::FreeFileSync()
FreeFileSync::~FreeFileSync()
{
- if (recycleBinAvailable)
- FreeLibrary(hinstShell);
-
delete noWxLogs;
}
bool FreeFileSync::recycleBinExists()
{
- FreeFileSync dummyObject;
- return dummyObject.recycleBinAvailable;
-}
-
-
-bool FreeFileSync::setRecycleBinUsage(bool activate)
-{ //If recycleBin is not available it mustn't be activated: This should NEVER happen!
- if (!recycleBinAvailable && activate)
- throw std::runtime_error("Initialization of Recycle Bin failed! It cannot be used!");
- else
- recycleBinAvailable = activate;
- return true;
+ return recycler.recycleBinExists();
}
@@ -847,15 +874,6 @@ SyncDirection getSyncDirection(const CompareFilesResult cmpResult, const SyncCon
}
-void FreeFileSync::wxULongLongToMpz(mpz_t& output, const wxULongLong& input)
-{
- mpz_set_ui(output, input.GetHi());
- mpz_mul_ui(output, output, 65536);
- mpz_mul_ui(output, output, 65536);
- mpz_add_ui(output, output, input.GetLo());
-}
-
-
bool getBytesToTransfer(double& result, const FileCompareLine& fileCmpLine, const SyncConfiguration& config)
{ //false if nothing has to be done
@@ -905,7 +923,7 @@ void FreeFileSync::calcTotalBytesToSync(int& objectsTotal, double& dataTotal, co
if (getBytesToTransfer(tmp, *i, config))
{
dataTotal+= tmp;
- objectsTotal++;
+ ++objectsTotal;
}
}
}
@@ -926,13 +944,13 @@ bool FreeFileSync::synchronizeFile(const FileCompareLine& filename, const SyncCo
switch (config.exLeftSideOnly)
{
case syncDirLeft: //delete files on left
- statusUpdater->updateStatusText(wxString(_("Deleting file ") + filename.fileDescrLeft.filename));
+ statusUpdater->updateStatusText(wxString(_("Deleting file ")) + "\"" + filename.fileDescrLeft.filename + "\"");
removeFile(filename.fileDescrLeft.filename);
break;
case syncDirRight: //copy files to right
- target = filename.fileDescrRight.directory + filename.fileDescrLeft.relFilename.c_str();
- statusUpdater->updateStatusText(wxString(_("Copying file ")) + filename.fileDescrLeft.filename +
- _(" to ") + target);
+ target = filename.fileDescrRight.directory + filename.fileDescrLeft.relFilename;
+ statusUpdater->updateStatusText(wxString(_("Copying file ")) + "\"" + filename.fileDescrLeft.filename + "\"" +
+ _(" to ") + "\"" + target + "\"");
copyfileMultithreaded(filename.fileDescrLeft.filename, target, statusUpdater);
break;
@@ -948,13 +966,13 @@ bool FreeFileSync::synchronizeFile(const FileCompareLine& filename, const SyncCo
{
case syncDirLeft: //copy files to left
target = filename.fileDescrLeft.directory + filename.fileDescrRight.relFilename;
- statusUpdater->updateStatusText(wxString(_("Copying file ")) + filename.fileDescrRight.filename +
- _(" to ") + target);
+ statusUpdater->updateStatusText(wxString(_("Copying file ")) + "\"" + filename.fileDescrRight.filename + "\"" +
+ _(" to ") + "\"" + target + "\"");
copyfileMultithreaded(filename.fileDescrRight.filename, target, statusUpdater);
break;
case syncDirRight: //delete files on right
- statusUpdater->updateStatusText(wxString(_("Deleting file ") + filename.fileDescrRight.filename));
+ statusUpdater->updateStatusText(wxString(_("Deleting file ")) + "\"" + filename.fileDescrRight.filename + "\"");
removeFile(filename.fileDescrRight.filename);
break;
case syncDirNone:
@@ -970,15 +988,15 @@ bool FreeFileSync::synchronizeFile(const FileCompareLine& filename, const SyncCo
switch (getSyncDirection(filename.cmpResult, config))
{
case syncDirLeft: //copy from right to left
- statusUpdater->updateStatusText(wxString(_("Copying file ")) + filename.fileDescrRight.filename +
- _(" overwriting ") + filename.fileDescrLeft.filename);
+ statusUpdater->updateStatusText(wxString(_("Copying file ")) + "\"" + filename.fileDescrRight.filename + "\"" +
+ _(" overwriting ") + "\"" + filename.fileDescrLeft.filename + "\"");
removeFile(filename.fileDescrLeft.filename); //only used if switch activated by user, else file is simply deleted
copyfileMultithreaded(filename.fileDescrRight.filename, filename.fileDescrLeft.filename, statusUpdater);
break;
case syncDirRight: //copy from left to right
- statusUpdater->updateStatusText(wxString(_("Copying file ")) + filename.fileDescrLeft.filename +
- _(" overwriting ") + filename.fileDescrRight.filename);
+ statusUpdater->updateStatusText(wxString(_("Copying file ")) + "\"" + filename.fileDescrLeft.filename + "\"" +
+ _(" overwriting ") + "\"" + filename.fileDescrRight.filename + "\"");
removeFile(filename.fileDescrRight.filename); //only used if switch activated by user, else file is simply deleted
copyfileMultithreaded(filename.fileDescrLeft.filename, filename.fileDescrRight.filename, statusUpdater);
@@ -1015,12 +1033,12 @@ bool FreeFileSync::synchronizeFolder(const FileCompareLine& filename, const Sync
switch (config.exLeftSideOnly)
{
case syncDirLeft: //delete folders on left
- statusUpdater->updateStatusText(wxString(_("Deleting folder ") + filename.fileDescrLeft.filename));
+ statusUpdater->updateStatusText(wxString(_("Deleting folder ")) + "\"" + filename.fileDescrLeft.filename + "\"");
removeDirectory(filename.fileDescrLeft.filename);
break;
case syncDirRight: //create folders on right
target = filename.fileDescrRight.directory + filename.fileDescrLeft.relFilename;
- statusUpdater->updateStatusText(wxString(_("Creating folder ") + target));
+ statusUpdater->updateStatusText(wxString(_("Creating folder ")) + "\"" + target + "\"");
//some check to catch the error that directory on source has been deleted externally after the "compare"...
if (!wxDirExists(filename.fileDescrLeft.filename))
@@ -1039,15 +1057,15 @@ bool FreeFileSync::synchronizeFolder(const FileCompareLine& filename, const Sync
{
case syncDirLeft: //create folders on left
target = filename.fileDescrLeft.directory + filename.fileDescrRight.relFilename;
- statusUpdater->updateStatusText(wxString(_("Creating folder ") + target));
+ statusUpdater->updateStatusText(wxString(_("Creating folder ")) + "\"" + target + "\"");
//some check to catch the error that directory on source has been deleted externally after the "compare"...
if (!wxDirExists(filename.fileDescrRight.filename))
- throw FileError(wxString(_("Error: Source directory does not exist anymore: ")) + filename.fileDescrRight.filename);
+ throw FileError(wxString(_("Error: Source directory does not exist anymore: ")) + "\"" + filename.fileDescrRight.filename + "\"");
createDirectory(target);
break;
case syncDirRight: //delete folders on right
- statusUpdater->updateStatusText(wxString(_("Deleting folder ") + filename.fileDescrRight.filename));
+ statusUpdater->updateStatusText(wxString(_("Deleting folder ")) + "\"" + filename.fileDescrRight.filename + "\"");
removeDirectory(filename.fileDescrRight.filename);
break;
case syncDirNone:
@@ -1069,9 +1087,15 @@ bool FreeFileSync::synchronizeFolder(const FileCompareLine& filename, const Sync
}
-wxString FreeFileSync::formatFilesizeToShortString(const mpz_class& filesize)
+wxString FreeFileSync::formatFilesizeToShortString(const wxULongLong& filesize)
+{
+ return formatFilesizeToShortString(filesize.ToDouble());
+}
+
+
+wxString FreeFileSync::formatFilesizeToShortString(const double filesize)
{
- mpf_class nrOfBytes = filesize;
+ double nrOfBytes = filesize;
wxString unit = " Byte";
if (nrOfBytes > 999)
@@ -1100,37 +1124,51 @@ wxString FreeFileSync::formatFilesizeToShortString(const mpz_class& filesize)
}
}
- mp_exp_t exponent = 0;
-
wxString temp;
- if (unit == " Byte") //no decimal places in case of bytes
+ if (unit == " Byte") //no decimal places in case of bytes
{
- temp = nrOfBytes.get_str(exponent, 10, 3);
- if (!temp.Len()) //if nrOfBytes is zero GMP returns an empty string
- temp = "0";
+ double integer = 0;
+ modf(nrOfBytes, &integer); //get integer part of nrOfBytes
+ temp = numberToWxString(int(integer));
+ // if (!temp.Len()) //if nrOfBytes is zero GMP returns an empty string
+ // temp = "0";
}
else
{
- temp = wxString(nrOfBytes.get_str(exponent, 10, 3) + "000").substr(0, 3); //returns mantisse of length 3 in all cases
+ nrOfBytes*= 100; //we want up to two decimal places
+ double integer = 0;
+ modf(nrOfBytes, &integer); //get integer part of nrOfBytes
- if (exponent < 0 || exponent > 3)
- temp = _("Error");
- else
- switch (exponent)
- {
- case 0:
- temp = wxString("0") + GlobalResources::floatingPointSeparator + temp.substr(0, 2); //shorten mantisse as a 0 will be inserted
- break;
- case 1:
- case 2:
- temp.insert(exponent, GlobalResources::floatingPointSeparator);
- break;
- case 3:
- break;
- }
+ temp = numberToWxString(int(integer));
+
+ int length = temp.Len();
+
+ switch (length)
+ {
+ case 0:
+ temp = "Error";
+ break;
+ case 1:
+ temp = wxString("0") + GlobalResources::floatingPointSeparator + "0" + temp;
+ break; //0,01
+ case 2:
+ temp = wxString("0") + GlobalResources::floatingPointSeparator + temp;
+ break; //0,11
+ case 3:
+ temp.insert(1, GlobalResources::floatingPointSeparator);
+ break; //1,11
+ case 4:
+ temp = temp.substr(0, 3);
+ temp.insert(2, GlobalResources::floatingPointSeparator);
+ break; //11,1
+ case 5:
+ temp = temp.substr(0, 3);
+ break; //111
+ default:
+ return "Error";
+ }
}
- temp+= unit;
- return temp;
+ return (temp + unit);
}
@@ -1170,7 +1208,7 @@ void FreeFileSync::filterCurrentGridData(FileCompareResult& currentGridData, con
//###########################
//filter currentGridData
- for (FileCompareResult::iterator i = currentGridData.begin(); i != currentGridData.end(); i++)
+ for (FileCompareResult::iterator i = currentGridData.begin(); i != currentGridData.end(); ++i)
{
//process include filters
if (i->fileDescrLeft.objType != isNothing)
@@ -1230,7 +1268,7 @@ void FreeFileSync::filterCurrentGridData(FileCompareResult& currentGridData, con
void FreeFileSync::removeFilterOnCurrentGridData(FileCompareResult& currentGridData)
{
//remove all filters on currentGridData
- for (FileCompareResult::iterator i = currentGridData.begin(); i != currentGridData.end(); i++)
+ for (FileCompareResult::iterator i = currentGridData.begin(); i != currentGridData.end(); ++i)
i->selectedForSynchronization = true;
}
@@ -1296,10 +1334,9 @@ void FreeFileSync::startSynchronizationProcess(FileCompareResult& grid, const Sy
try
{
- FreeFileSync fileSyncObject; //currently only needed for recycle bin
- fileSyncObject.setRecycleBinUsage(useRecycleBin);
+ FreeFileSync fileSyncObject(useRecycleBin); //currently only needed for recycle bin and wxLog suppression => do NOT declare static!
- // it should never happen, that a directory on left side has same name as file on right side. GetModelDiff should take care of this
+ // it should never happen, that a directory on left side has same name as file on right side. startCompareProcess() should take care of this
// and split into two "exists on one side only" cases
// Note: this case is not handled by this tool as this is considered to be a bug and must be solved by the user
@@ -1432,8 +1469,7 @@ void FreeFileSync::addSubElements(set<int>& subElements, const FileCompareResult
void FreeFileSync::deleteOnGridAndHD(FileCompareResult& grid, const set<int>& rowsToDelete, StatusUpdater* statusUpdater, bool useRecycleBin)
{
- FreeFileSync fileSyncObject; //currently only needed for recycle bin
- fileSyncObject.setRecycleBinUsage(useRecycleBin);
+ FreeFileSync fileSyncObject(useRecycleBin); //currently only needed for recycle bin and wxLog suppression => do NOT declare static!
set<int> rowsToDeleteInGrid;
bgstack15