From 88a2d0007db222c339f0b6a17794a2014a241892 Mon Sep 17 00:00:00 2001 From: Daniel Wilhelm Date: Fri, 18 Apr 2014 17:16:21 +0200 Subject: 4.3 --- lib/FindFilePlus/FindFilePlus.vcxproj | 245 ----------------- lib/FindFilePlus/dll_main.cpp | 30 --- lib/FindFilePlus/find_file_plus.cpp | 298 --------------------- lib/FindFilePlus/find_file_plus.h | 78 ------ lib/FindFilePlus/init_dll_binding.h | 16 -- lib/FindFilePlus/load_dll.cpp | 23 -- lib/FindFilePlus/load_dll.h | 46 ---- lib/custom_grid.cpp | 169 ++++++------ lib/db_file.cpp | 476 +++++++++++++++------------------- lib/db_file.h | 5 +- lib/detect_renaming.cpp | 285 -------------------- lib/detect_renaming.h | 26 -- lib/dir_exist_async.h | 4 +- lib/dir_lock.cpp | 16 +- lib/dir_name.cpp | 2 +- lib/localization.cpp | 1 + lib/parallel_scan.cpp | 15 +- lib/status_handler.h | 18 +- 18 files changed, 327 insertions(+), 1426 deletions(-) delete mode 100644 lib/FindFilePlus/FindFilePlus.vcxproj delete mode 100644 lib/FindFilePlus/dll_main.cpp delete mode 100644 lib/FindFilePlus/find_file_plus.cpp delete mode 100644 lib/FindFilePlus/find_file_plus.h delete mode 100644 lib/FindFilePlus/init_dll_binding.h delete mode 100644 lib/FindFilePlus/load_dll.cpp delete mode 100644 lib/FindFilePlus/load_dll.h delete mode 100644 lib/detect_renaming.cpp delete mode 100644 lib/detect_renaming.h (limited to 'lib') diff --git a/lib/FindFilePlus/FindFilePlus.vcxproj b/lib/FindFilePlus/FindFilePlus.vcxproj deleted file mode 100644 index 2c4256a6..00000000 --- a/lib/FindFilePlus/FindFilePlus.vcxproj +++ /dev/null @@ -1,245 +0,0 @@ - - - - - Debug - Win32 - - - Debug - x64 - - - Release - Win32 - - - Release - x64 - - - - {70394AEF-5897-4911-AFA1-82EAF0581EFA} - ShadowDll - Win32Proj - - - - DynamicLibrary - Unicode - true - Windows7.1SDK - - - DynamicLibrary - Unicode - Windows7.1SDK - - - DynamicLibrary - Unicode - true - Windows7.1SDK - - - DynamicLibrary - Unicode - Windows7.1SDK - - - - - - - - - - - - - - - - - - - <_ProjectFileVersion>10.0.30319.1 - OBJ\ - OBJ\$(ProjectName)_$(Configuration)_$(Platform)\ - false - OBJ\ - OBJ\$(ProjectName)_$(Configuration)_$(Platform)\ - false - .\ - OBJ\$(ProjectName)_$(Configuration)_$(Platform)\ - false - .\ - OBJ\$(ProjectName)_$(Configuration)_$(Platform)\ - false - FindFilePlus_$(Platform) - FindFilePlus_$(Platform) - FindFilePlus_$(Platform) - FindFilePlus_$(Platform) - D:\Data\WinDDK\inc\ddk;D:\Data\WinDDK\inc\api;D:\Data\WinDDK\inc\crt;$(WindowsSdkDir)\include;$(VCInstallDir)include - D:\Data\WinDDK\inc\ddk;D:\Data\WinDDK\inc\api;D:\Data\WinDDK\inc\crt;$(WindowsSdkDir)\include;$(VCInstallDir)include - D:\Data\WinDDK\inc\ddk;D:\Data\WinDDK\inc\api;D:\Data\WinDDK\inc\crt;$(WindowsSdkDir)\include;$(VCInstallDir)include - D:\Data\WinDDK\inc\ddk;D:\Data\WinDDK\inc\api;D:\Data\WinDDK\inc\crt;$(WindowsSdkDir)\include;$(VCInstallDir)include - - - - $(IntDir)Build.html - - - Disabled - _X86_;_DEBUG;_WINDOWS;_USRDLL;FIND_FILE_PLUS_DLL_EXPORTS;%(PreprocessorDefinitions) - true - EnableFastChecks - MultiThreadedDebugDLL - - - Level4 - true - EditAndContinue - 4100 - ../.. - - - $(OutDir)$(TargetName)$(TargetExt) - true - true - $(IntDir)$(TargetName).pdb - Windows - - - $(IntDir)$(TargetName).lib - MachineX86 - - - - - $(IntDir)Build.html - - - X64 - - - Disabled - _AMD64_;_DEBUG;_WINDOWS;_USRDLL;FIND_FILE_PLUS_DLL_EXPORTS;%(PreprocessorDefinitions) - true - EnableFastChecks - MultiThreadedDebugDLL - - - Level4 - true - ProgramDatabase - 4100 - ../.. - - - $(OutDir)$(TargetName)$(TargetExt) - true - true - $(IntDir)$(TargetName).pdb - Windows - - - $(IntDir)$(TargetName).lib - MachineX64 - - - - - $(IntDir)Build.html - - - MaxSpeed - true - _X86_;NDEBUG;_WINDOWS;_USRDLL;FIND_FILE_PLUS_DLL_EXPORTS;%(PreprocessorDefinitions) - MultiThreaded - true - - - Level4 - true - ProgramDatabase - 4100 - Speed - ../.. - - - $(OutDir)$(TargetName)$(TargetExt) - true - false - Windows - true - true - UseLinkTimeCodeGeneration - - - $(IntDir)$(TargetName).lib - MachineX86 - - - - - $(IntDir)Build.html - - - X64 - - - MaxSpeed - true - _AMD64_;NDEBUG;_WINDOWS;_USRDLL;FIND_FILE_PLUS_DLL_EXPORTS;%(PreprocessorDefinitions) - MultiThreaded - true - - - Level4 - true - ProgramDatabase - 4100 - Speed - ../.. - - - $(OutDir)$(TargetName)$(TargetExt) - true - false - Windows - true - true - UseLinkTimeCodeGeneration - - - $(IntDir)$(TargetName).lib - MachineX64 - - - - - - - false - - - false - - - false - - - false - - - - - - - - - - - - \ No newline at end of file diff --git a/lib/FindFilePlus/dll_main.cpp b/lib/FindFilePlus/dll_main.cpp deleted file mode 100644 index 5d64181b..00000000 --- a/lib/FindFilePlus/dll_main.cpp +++ /dev/null @@ -1,30 +0,0 @@ -// ************************************************************************** -// * This file is part of the FreeFileSync project. It is distributed under * -// * GNU General Public License: http://www.gnu.org/licenses/gpl.html * -// * Copyright (C) 2008-2011 ZenJu (zhnmju123 AT gmx.de) * -// ************************************************************************** - - -#define WIN32_LEAN_AND_MEAN -#include - -#include "init_dll_binding.h" - - -//optional: add init/teardown logic here -BOOL APIENTRY DllMain(HINSTANCE hinstDLL, - DWORD fdwReason, - LPVOID lpvReserved) -{ - switch (fdwReason) - { - case DLL_PROCESS_ATTACH: - if (!findplus::initDllBinding()) - return false; - case DLL_PROCESS_DETACH: - case DLL_THREAD_ATTACH: - case DLL_THREAD_DETACH: - break; - } - return true; -} diff --git a/lib/FindFilePlus/find_file_plus.cpp b/lib/FindFilePlus/find_file_plus.cpp deleted file mode 100644 index becfe553..00000000 --- a/lib/FindFilePlus/find_file_plus.cpp +++ /dev/null @@ -1,298 +0,0 @@ -// ************************************************************************** -// * This file is part of the FreeFileSync project. It is distributed under * -// * GNU General Public License: http://www.gnu.org/licenses/gpl.html * -// * Copyright (C) 2008-2011 ZenJu (zhnmju123 AT gmx.de) * -// ************************************************************************** - -#include "find_file_plus.h" -#include "init_dll_binding.h" -//#include //these two don't play nice with each other -#include "load_dll.h" -#include - -using namespace dll; -using namespace findplus; - - -namespace -{ -struct FileError -{ - FileError(ULONG errorCode) : win32Error(errorCode) {} - ULONG win32Error; -}; - - -//-------------------------------------------------------------------------------------------------------------- -typedef NTSTATUS (NTAPI* NtOpenFileFunc)(PHANDLE fileHandle, - ACCESS_MASK desiredAccess, - POBJECT_ATTRIBUTES objectAttributes, - PIO_STATUS_BLOCK ioStatusBlock, - ULONG shareAccess, - ULONG openOptions); - -typedef NTSTATUS (NTAPI* NtCloseFunc)(HANDLE handle); - -typedef NTSTATUS (NTAPI* NtQueryDirectoryFileFunc)(HANDLE fileHandle, - HANDLE event, - PIO_APC_ROUTINE apcRoutine, - PVOID apcContext, - PIO_STATUS_BLOCK ioStatusBlock, - PVOID fileInformation, - ULONG length, - FILE_INFORMATION_CLASS fileInformationClass, - BOOLEAN ReturnSingleEntry, - PUNICODE_STRING fileMask, - BOOLEAN restartScan); - -typedef ULONG (NTAPI* RtlNtStatusToDosErrorFunc)(NTSTATUS /*__in status*/); - -typedef struct _RTL_RELATIVE_NAME_U -{ - UNICODE_STRING RelativeName; - HANDLE ContainingDirectory; - PVOID /*PRTLP_CURDIR_REF*/ CurDirRef; -} RTL_RELATIVE_NAME_U, *PRTL_RELATIVE_NAME_U; - -typedef BOOLEAN (NTAPI* RtlDosPathNameToNtPathName_UFunc)(PCWSTR, //__in dosFileName, - PUNICODE_STRING, //__out ntFileName, - PCWSTR*, //__out_optFilePart, - PRTL_RELATIVE_NAME_U); //__out_opt relativeName - -typedef BOOLEAN (NTAPI* RtlDosPathNameToRelativeNtPathName_UFunc)(PCWSTR, //__in dosFileName, - PUNICODE_STRING, //__out ntFileName, - PCWSTR*, //__out_optFilePart, - PRTL_RELATIVE_NAME_U); //__out_opt relativeName - -typedef VOID (NTAPI* RtlFreeUnicodeStringFunc)(PUNICODE_STRING); //__inout unicodeString - -//-------------------------------------------------------------------------------------------------------------- - -//it seems we cannot use any of the ntoskrnl.lib files in WinDDK as they produce access violations -//fortunately dynamic binding works fine: -const SysDllFun ntOpenFile (L"ntdll.dll", "NtOpenFile"); -const SysDllFun ntClose (L"ntdll.dll", "NtClose"); -const SysDllFun ntQueryDirectoryFile (L"ntdll.dll", "NtQueryDirectoryFile"); -const SysDllFun rtlNtStatusToDosError (L"ntdll.dll", "RtlNtStatusToDosError"); -const SysDllFun rtlFreeUnicodeString (L"ntdll.dll", "RtlFreeUnicodeString"); -const SysDllFun rtlDosPathNameToNtPathName_U(SysDllFun(L"ntdll.dll", "RtlDosPathNameToRelativeNtPathName_U") ? - SysDllFun(L"ntdll.dll", "RtlDosPathNameToRelativeNtPathName_U") : //use the newer version if available - SysDllFun(L"ntdll.dll", "RtlDosPathNameToNtPathName_U")); //fallback for XP -//global constants only -> preserve thread safety! -} - - -bool findplus::initDllBinding() //evaluate in ::DllMain() when attaching process -{ - //NT/ZwXxx Routines - //http://msdn.microsoft.com/en-us/library/ff567122(v=VS.85).aspx - - //Run-Time Library (RTL) Routines - //http://msdn.microsoft.com/en-us/library/ff563638(v=VS.85).aspx - - //verify dynamic dll binding - return ntOpenFile && - ntClose && - ntQueryDirectoryFile && - rtlNtStatusToDosError && - rtlFreeUnicodeString && - rtlDosPathNameToNtPathName_U; - - //this may become handy some time: nt status code STATUS_ORDINAL_NOT_FOUND maps to win32 code ERROR_INVALID_ORDINAL -} - - -class findplus::FileSearcher -{ -public: - FileSearcher(const wchar_t* dirname); //throw FileError - ~FileSearcher(); - - void readdir(FileInformation& output); //throw FileError - -private: - UNICODE_STRING ntPathName; //it seems hDir implicitly keeps a reference to this, at least ::FindFirstFile() does no cleanup before ::FindClose()! - HANDLE hDir; - - ULONG nextEntryOffset; //!= 0 if entry is waiting in buffer - //::FindNextFileW() uses 0x1000 = 4096 = sizeof(FILE_BOTH_DIR_INFORMATION) + sizeof(TCHAR) * 2000 - //=> let's use the same, even if our header is 16 byte larger; maybe there is some packet size advantage for networks? Note that larger buffers seem to degrade performance. - static const ULONG BUFFER_SIZE = 4096; - LONGLONG buffer[BUFFER_SIZE / sizeof(LONGLONG)]; //buffer needs to be aligned at LONGLONG boundary - - static_assert(BUFFER_SIZE % sizeof(LONGLONG) == 0, "ups, our buffer is trimmed!"); -}; - - -FileSearcher::FileSearcher(const wchar_t* dirname) : - hDir(NULL), - nextEntryOffset(0) -{ - ntPathName.Buffer = NULL; - ntPathName.Length = 0; - ntPathName.MaximumLength = 0; - - zen::ScopeGuard guardConstructor = zen::makeGuard([&]() { this->~FileSearcher(); }); - //-------------------------------------------------------------------------------------------------------------- - - //convert dosFileName, e.g. C:\Users or \\?\C:\Users to ntFileName \??\C:\Users - //in contrast to ::FindFirstFile() we don't evaluate the relativeName, however tests indicate ntFileName is *always* filled with an absolute name, even if dosFileName is relative - - //NOTE: RtlDosPathNameToNtPathName_U may be used on all XP/Win7/Win8 for compatibility - // RtlDosPathNameToNtPathName_U: used by Windows XP available with OS version 3.51 (Windows NT) and higher - // RtlDosPathNameToRelativeNtPathName_U: used by Win7/Win8 available with OS version 5.2 (Windows Server 2003) and higher - if (!rtlDosPathNameToNtPathName_U(dirname, //__in dosFileName, - &ntPathName, //__out ntFileName, - NULL, //__out_optFilePart, - NULL)) //__out_opt relativeName - empty if dosFileName is absolute - throw FileError(rtlNtStatusToDosError(STATUS_OBJECT_PATH_NOT_FOUND)); //translates to ERROR_PATH_NOT_FOUND, same behavior like ::FindFirstFileEx() - - OBJECT_ATTRIBUTES objAttr = {}; - InitializeObjectAttributes(&objAttr, //[out] POBJECT_ATTRIBUTES initializedAttributes, - &ntPathName, //[in] PUNICODE_STRING objectName, - OBJ_CASE_INSENSITIVE, //[in] ULONG attributes, - NULL, //[in] HANDLE rootDirectory, - NULL); //[in, optional] PSECURITY_DESCRIPTOR securityDescriptor - - { - IO_STATUS_BLOCK status = {}; - NTSTATUS rv = ntOpenFile(&hDir, //__out PHANDLE FileHandle, - FILE_LIST_DIRECTORY | SYNCHRONIZE, //__in ACCESS_MASK desiredAccess, - 100001 used by ::FindFirstFile() on all XP/Win7/Win8 - &objAttr, //__in POBJECT_ATTRIBUTES objectAttributes, - &status, //__out PIO_STATUS_BLOCK ioStatusBlock, - FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, //__in ULONG shareAccess, - 7 on Win7/Win8, 3 on XP - FILE_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT | FILE_OPEN_FOR_BACKUP_INTENT); //__in ULONG openOptions - 4021 used on all XP/Win7/Win8 - if (!NT_SUCCESS(rv)) - throw FileError(rtlNtStatusToDosError(rv)); - } - - guardConstructor.dismiss(); -} - - -inline -FileSearcher::~FileSearcher() -{ - //cleanup in reverse order - if (hDir) - ntClose(hDir); - - if (ntPathName.Buffer) - rtlFreeUnicodeString(&ntPathName); //cleanup identical to ::FindFirstFile() - //note that most if this function seems inlined by the linker, so that its assembly looks equivalent to "RtlFreeHeap(GetProcessHeap(), 0, ntPathName.Buffer)" -} - - -void FileSearcher::readdir(FileInformation& output) -{ - //although FILE_ID_FULL_DIR_INFORMATION should suffice for our purposes, there are problems on Windows XP for certain directories, e.g. "\\Vboxsvr\build" - //making NtQueryDirectoryFile() return with STATUS_INVALID_PARAMETER while other directories, e.g. "C:\" work fine for some reason - //FILE_ID_BOTH_DIR_INFORMATION on the other hand works on XP/Win7/Win8 - //performance: there is no noticable difference between FILE_ID_BOTH_DIR_INFORMATION and FILE_ID_FULL_DIR_INFORMATION - - /* corresponding first access in ::FindFirstFileW() - - NTSTATUS rv = ntQueryDirectoryFile(hDir, //__in HANDLE fileHandle, - NULL, //__in_opt HANDLE event, - NULL, //__in_opt PIO_APC_ROUTINE apcRoutine, - NULL, //__in_opt PVOID apcContext, - &status, //__out PIO_STATUS_BLOCK ioStatusBlock, - &buffer, //__out_bcount(Length) PVOID fileInformation, - BUFFER_SIZE, //__in ULONG length, ::FindFirstFileW() on all XP/Win7/Win8 uses sizeof(FILE_BOTH_DIR_INFORMATION) + sizeof(TCHAR) * MAX_PATH == 0x268 - FileIdBothDirectoryInformation, //__in FILE_INFORMATION_CLASS fileInformationClass - all XP/Win7/Win8 use "FileBothDirectoryInformation" - true, //__in BOOLEAN returnSingleEntry, - NULL, //__in_opt PUNICODE_STRING mask, - false); //__in BOOLEAN restartScan - */ - - //analog to ::FindNextFileW() with performance optimized access (in contrast to first access in ::FindFirstFileW()) - if (nextEntryOffset == 0) - { - IO_STATUS_BLOCK status = {}; - NTSTATUS rv = ntQueryDirectoryFile(hDir, //__in HANDLE fileHandle, - NULL, //__in_opt HANDLE event, - NULL, //__in_opt PIO_APC_ROUTINE apcRoutine, - NULL, //__in_opt PVOID apcContext, - &status, //__out PIO_STATUS_BLOCK ioStatusBlock, - &buffer, //__out_bcount(Length) PVOID fileInformation, - BUFFER_SIZE, //__in ULONG length, ::FindNextFileW() on all XP/Win7/Win8 uses sizeof(FILE_BOTH_DIR_INFORMATION) + sizeof(TCHAR) * 2000 == 0x1000 - FileIdBothDirectoryInformation, //__in FILE_INFORMATION_CLASS fileInformationClass - all XP/Win7/Win8 use "FileBothDirectoryInformation" - false, //__in BOOLEAN returnSingleEntry, - NULL, //__in_opt PUNICODE_STRING mask, - false); //__in BOOLEAN restartScan - if (!NT_SUCCESS(rv)) - throw FileError(rtlNtStatusToDosError(rv)); //throws STATUS_NO_MORE_FILES when finished - - if (status.Information == 0) //except for the first call to call ::NtQueryDirectoryFile(): - throw FileError(rtlNtStatusToDosError(STATUS_BUFFER_OVERFLOW)); //if buffer size is too small, return value is STATUS_SUCCESS and Information == 0 -> we don't expect this! - } - - const FILE_ID_BOTH_DIR_INFORMATION& dirInfo = *reinterpret_cast(reinterpret_cast(buffer) + nextEntryOffset); - - if (dirInfo.NextEntryOffset == 0) - nextEntryOffset = 0; //our offset is relative to the beginning of the buffer - else - nextEntryOffset += dirInfo.NextEntryOffset; - - - auto toFileTime = [](const LARGE_INTEGER & rawTime) -> FILETIME - { - FILETIME tmp = { rawTime.LowPart, rawTime.HighPart }; - return tmp; - }; - - output.creationTime = toFileTime(dirInfo.CreationTime); - output.lastWriteTime = toFileTime(dirInfo.LastWriteTime); - output.fileSize.QuadPart = dirInfo.EndOfFile.QuadPart; - output.fileId.QuadPart = dirInfo.FileId.QuadPart; - output.fileAttributes = dirInfo.FileAttributes; - output.shortNameLength = dirInfo.FileNameLength / sizeof(TCHAR); //FileNameLength is in bytes! - - if (dirInfo.FileNameLength + sizeof(TCHAR) > sizeof(output.shortName)) //this may actually happen if ::NtQueryDirectoryFile() decides to return a - throw FileError(rtlNtStatusToDosError(STATUS_BUFFER_OVERFLOW)); //short name of length MAX_PATH + 1, 0-termination is not required! - - ::memcpy(output.shortName, dirInfo.FileName, dirInfo.FileNameLength); - output.shortName[output.shortNameLength] = 0; //NOTE: FILE_ID_BOTH_DIR_INFORMATION::FileName in general is NOT 0-terminated! It is on XP/Win7, but NOT on Win8! - - static_assert(sizeof(output.creationTime) == sizeof(dirInfo.CreationTime), "dang!"); - static_assert(sizeof(output.lastWriteTime) == sizeof(dirInfo.LastWriteTime), "dang!"); - static_assert(sizeof(output.fileSize) == sizeof(dirInfo.EndOfFile), "dang!"); - static_assert(sizeof(output.fileId) == sizeof(dirInfo.FileId), "dang!"); - static_assert(sizeof(output.fileAttributes) == sizeof(dirInfo.FileAttributes), "dang!"); -} - - -FindHandle findplus::openDir(const wchar_t* dirname) -{ - try - { - return new FileSearcher(dirname); //throw FileError - } - catch (const FileError& err) - { - setWin32Error(err.win32Error); - return NULL; - } -} - - -bool findplus::readDir(FindHandle hnd, FileInformation& output) -{ - try - { - hnd->readdir(output); //throw FileError - return true; - } - catch (const FileError& err) - { - setWin32Error(err.win32Error); - return false; - } -} - - -void findplus::closeDir(FindHandle hnd) -{ - if (hnd) //play a little "nice" - delete hnd; -} diff --git a/lib/FindFilePlus/find_file_plus.h b/lib/FindFilePlus/find_file_plus.h deleted file mode 100644 index aacdf0ea..00000000 --- a/lib/FindFilePlus/find_file_plus.h +++ /dev/null @@ -1,78 +0,0 @@ -// ************************************************************************** -// * This file is part of the FreeFileSync project. It is distributed under * -// * GNU General Public License: http://www.gnu.org/licenses/gpl.html * -// * Copyright (C) 2008-2011 ZenJu (zhnmju123 AT gmx.de) * -// ************************************************************************** - -#ifndef FIND_FIRST_FILE_PLUS_HEADER_087483434 -#define FIND_FIRST_FILE_PLUS_HEADER_087483434 - -#ifdef FIND_FILE_PLUS_DLL_EXPORTS -#define DLL_FUNCTION_DECLARATION extern "C" __declspec(dllexport) -#else -#define DLL_FUNCTION_DECLARATION extern "C" __declspec(dllimport) -#endif - - -#ifdef FIND_FILE_PLUS_DLL_EXPORTS -#include //driver level headers must be included *before* windows api headers! -#endif -#include // -#undef min -#undef max - -#include - -namespace findplus -{ -/*-------------- - |declarations| - --------------*/ - -struct FileInformation -{ - FILETIME creationTime; - FILETIME lastWriteTime; - ULARGE_INTEGER fileSize; - ULARGE_INTEGER fileId; - DWORD fileAttributes; - DWORD shortNameLength; - WCHAR shortName[MAX_PATH + 1]; //shortName is 0-terminated -}; //no need for #pragma pack -> all members already starting at 4 byte boundary! - -class FileSearcher; -typedef FileSearcher* FindHandle; - -DLL_FUNCTION_DECLARATION -FindHandle openDir(const wchar_t* dirname); //returns NULL on error, call ::GetLastError() -//note: do NOT place an asterisk at end, e.g. C:\SomeDir\*, as one would do for ::FindFirstFile() - -DLL_FUNCTION_DECLARATION -bool readDir(FindHandle hnd, FileInformation& output); //returns false on error or if there are no more files; ::GetLastError() returns ERROR_NO_MORE_FILES - -DLL_FUNCTION_DECLARATION -void closeDir(FindHandle hnd); - -/*---------- - |typedefs| - ----------*/ -typedef FindHandle (*OpenDirFunc )(const wchar_t* dirname); -typedef bool (*ReadDirFunc )(FindHandle hnd, FileInformation& dirInfo); -typedef void (*CloseDirFunc)(FindHandle hnd); - -/*-------------- - |symbol names| - --------------*/ -//const pointers ensure internal linkage -const char openDirFuncName [] = "openDir"; -const char readDirFuncName [] = "readDir"; -const char closeDirFuncName[] = "closeDir"; - -/*--------------- - |library names| - ---------------*/ -inline const wchar_t* getDllName() { return zen::is64BitBuild ? L"FindFilePlus_x64.dll" : L"FindFilePlus_Win32.dll"; } -} - - -#endif //FIND_FIRST_FILE_PLUS_HEADER_087483434 diff --git a/lib/FindFilePlus/init_dll_binding.h b/lib/FindFilePlus/init_dll_binding.h deleted file mode 100644 index 51b32c99..00000000 --- a/lib/FindFilePlus/init_dll_binding.h +++ /dev/null @@ -1,16 +0,0 @@ -// ************************************************************************** -// * This file is part of the FreeFileSync project. It is distributed under * -// * GNU General Public License: http://www.gnu.org/licenses/gpl.html * -// * Copyright (C) 2008-2011 ZenJu (zhnmju123 AT gmx.de) * -// ************************************************************************** - -#ifndef INIT_DLL_BINDING_HEADER_ß018356031467832145 -#define INIT_DLL_BINDING_HEADER_ß018356031467832145 - -namespace findplus -{ -//load and check dll binding at startup -bool initDllBinding(); //evaluate in ::DllMain() when attaching process -} - -#endif //INIT_DLL_BINDING_HEADER_ß018356031467832145 diff --git a/lib/FindFilePlus/load_dll.cpp b/lib/FindFilePlus/load_dll.cpp deleted file mode 100644 index 20d9a5fe..00000000 --- a/lib/FindFilePlus/load_dll.cpp +++ /dev/null @@ -1,23 +0,0 @@ -// ************************************************************************** -// * This file is part of the FreeFileSync project. It is distributed under * -// * GNU General Public License: http://www.gnu.org/licenses/gpl.html * -// * Copyright (C) 2008-2011 ZenJu (zhnmju123 AT gmx.de) * -// ************************************************************************** - -#include "load_dll.h" -#define WIN32_LEAN_AND_MEAN -#include - -void* /*FARPROC*/ dll::loadSymbol(const wchar_t* libraryName, const char* functionName) -{ - return ::GetProcAddress(::GetModuleHandle(libraryName), functionName); - //cleanup neither required nor allowed (::FreeLibrary()) - -} -//note: void* and FARPROC function pointer have same binary size on Windows - - -void dll::setWin32Error(unsigned long lastError) -{ - ::SetLastError(lastError); -} diff --git a/lib/FindFilePlus/load_dll.h b/lib/FindFilePlus/load_dll.h deleted file mode 100644 index 350de9f8..00000000 --- a/lib/FindFilePlus/load_dll.h +++ /dev/null @@ -1,46 +0,0 @@ -// ************************************************************************** -// * This file is part of the FreeFileSync project. It is distributed under * -// * GNU General Public License: http://www.gnu.org/licenses/gpl.html * -// * Copyright (C) 2008-2011 ZenJu (zhnmju123 AT gmx.de) * -// ************************************************************************** - -#ifndef LOAD_DLL_HEADER_0312463214872163832174 -#define LOAD_DLL_HEADER_0312463214872163832174 - -namespace dll -{ -void setWin32Error(unsigned long lastError); - -//NOTE: uses ::GetModuleHandle => call for system DLLs only! -template -class SysDllFun -{ -public: - SysDllFun(const wchar_t* systemLibrary, const char* functionName) : - fun(reinterpret_cast(loadSymbol(systemLibrary, functionName))) {} - - operator Func() const { return fun; } - -private: - Func fun; -}; - - - - - - - - - - - - - - - - -void* /*FARPROC*/ loadSymbol(const wchar_t* libraryName, const char* functionName); -} - -#endif //LOAD_DLL_HEADER_0312463214872163832174 diff --git a/lib/custom_grid.cpp b/lib/custom_grid.cpp index 97db1676..f2892624 100644 --- a/lib/custom_grid.cpp +++ b/lib/custom_grid.cpp @@ -557,23 +557,24 @@ private: case SO_CREATE_NEW_LEFT: case SO_OVERWRITE_LEFT: case SO_DELETE_LEFT: + case SO_MOVE_LEFT_SOURCE: + case SO_MOVE_LEFT_TARGET: + case SO_COPY_METADATA_TO_LEFT: result.first = *wxBLACK; result.second = COLOR_SYNC_BLUE; break; - case SO_COPY_METADATA_TO_LEFT: - result.first = *wxBLACK; - result.second = COLOR_SYNC_BLUE_LIGHT; + // result.second = COLOR_SYNC_BLUE_LIGHT; break; case SO_CREATE_NEW_RIGHT: case SO_OVERWRITE_RIGHT: case SO_DELETE_RIGHT: - result.first = *wxBLACK; - result.second = COLOR_SYNC_GREEN; - break; + case SO_MOVE_RIGHT_SOURCE: + case SO_MOVE_RIGHT_TARGET: case SO_COPY_METADATA_TO_RIGHT: result.first = *wxBLACK; - result.second = COLOR_SYNC_GREEN_LIGHT; + result.second = COLOR_SYNC_GREEN; break; + // result.second = COLOR_SYNC_GREEN_LIGHT; case SO_UNRESOLVED_CONFLICT: result.first = *wxBLACK; result.second = COLOR_YELLOW; @@ -2038,70 +2039,77 @@ void CustomGridMiddle::showToolTip(int rowNumber, wxPoint pos) if (getGridDataTableMiddle()->syncPreviewIsActive()) //synchronization preview { - const SyncOperation syncOp = fsObj->getSyncOperation(); - switch (syncOp) + const wchar_t* imageName = [&]() -> const wchar_t* { - case SO_CREATE_NEW_LEFT: - toolTip.show(getDescription(syncOp), pos, &GlobalResources::getImage(wxT("createLeft"))); - break; - case SO_CREATE_NEW_RIGHT: - toolTip.show(getDescription(syncOp), pos, &GlobalResources::getImage(wxT("createRight"))); - break; - case SO_DELETE_LEFT: - toolTip.show(getDescription(syncOp), pos, &GlobalResources::getImage(wxT("deleteLeft"))); - break; - case SO_DELETE_RIGHT: - toolTip.show(getDescription(syncOp), pos, &GlobalResources::getImage(wxT("deleteRight"))); - break; - case SO_OVERWRITE_LEFT: - case SO_COPY_METADATA_TO_LEFT: - toolTip.show(getDescription(syncOp), pos, &GlobalResources::getImage(wxT("updateLeft"))); - break; - case SO_OVERWRITE_RIGHT: - case SO_COPY_METADATA_TO_RIGHT: - toolTip.show(getDescription(syncOp), pos, &GlobalResources::getImage(wxT("updateRight"))); - break; - case SO_DO_NOTHING: - toolTip.show(getDescription(syncOp), pos, &GlobalResources::getImage(wxT("none"))); - break; - case SO_EQUAL: - toolTip.show(getDescription(syncOp), pos, &GlobalResources::getImage(wxT("equal"))); - break; - case SO_UNRESOLVED_CONFLICT: - toolTip.show(fsObj->getSyncOpConflict(), pos, &GlobalResources::getImage(wxT("conflict"))); - break; - }; + const SyncOperation syncOp = fsObj->getSyncOperation(); + switch (syncOp) + { + case SO_CREATE_NEW_LEFT: + return L"createLeft"; + case SO_CREATE_NEW_RIGHT: + return L"createRight"; + case SO_DELETE_LEFT: + return L"deleteLeft"; + case SO_DELETE_RIGHT: + return L"deleteRight"; + case SO_MOVE_LEFT_SOURCE: + return L"moveLeftSource"; + case SO_MOVE_LEFT_TARGET: + return L"moveLeftTarget"; + case SO_MOVE_RIGHT_SOURCE: + return L"moveRightSource"; + case SO_MOVE_RIGHT_TARGET: + return L"moveRightTarget"; + case SO_OVERWRITE_LEFT: + return L"updateLeft"; + case SO_COPY_METADATA_TO_LEFT: + return L"moveLeft"; + case SO_OVERWRITE_RIGHT: + return L"updateRight"; + case SO_COPY_METADATA_TO_RIGHT: + return L"moveRight"; + case SO_DO_NOTHING: + return L"none"; + case SO_EQUAL: + return L"equal"; + case SO_UNRESOLVED_CONFLICT: + return L"conflict"; + }; + assert(false); + return L""; + }(); + + toolTip.show(getSyncOpDescription(*fsObj), pos, &GlobalResources::getImage(imageName)); } else { - const CompareFilesResult cmpRes = fsObj->getCategory(); - switch (cmpRes) + const wchar_t* imageName = [&]() -> const wchar_t* { - case FILE_LEFT_SIDE_ONLY: - toolTip.show(getDescription(cmpRes), pos, &GlobalResources::getImage(wxT("leftOnly"))); - break; - case FILE_RIGHT_SIDE_ONLY: - toolTip.show(getDescription(cmpRes), pos, &GlobalResources::getImage(wxT("rightOnly"))); - break; - case FILE_LEFT_NEWER: - toolTip.show(getDescription(cmpRes), pos, &GlobalResources::getImage(wxT("leftNewer"))); - break; - case FILE_RIGHT_NEWER: - toolTip.show(getDescription(cmpRes), pos, &GlobalResources::getImage(wxT("rightNewer"))); - break; - case FILE_DIFFERENT: - toolTip.show(getDescription(cmpRes), pos, &GlobalResources::getImage(wxT("different"))); - break; - case FILE_EQUAL: - toolTip.show(getDescription(cmpRes), pos, &GlobalResources::getImage(wxT("equal"))); - break; - case FILE_DIFFERENT_METADATA: - toolTip.show(getDescription(cmpRes), pos, &GlobalResources::getImage(wxT("conflict"))); - break; - case FILE_CONFLICT: - toolTip.show(fsObj->getCatConflict(), pos, &GlobalResources::getImage(wxT("conflict"))); - break; - } + const CompareFilesResult cmpRes = fsObj->getCategory(); + switch (cmpRes) + { + case FILE_LEFT_SIDE_ONLY: + return L"leftOnly"; + case FILE_RIGHT_SIDE_ONLY: + return L"rightOnly"; + case FILE_LEFT_NEWER: + return L"leftNewer"; + case FILE_RIGHT_NEWER: + return L"rightNewer"; + case FILE_DIFFERENT: + return L"different"; + case FILE_EQUAL: + return L"equal"; + case FILE_DIFFERENT_METADATA: + return L"conflict"; + case FILE_CONFLICT: + return L"conflict"; + } + assert(false); + return L""; + }(); + + toolTip.show(getCategoryDescription(*fsObj), pos, &GlobalResources::getImage(imageName)); } } @@ -2284,6 +2292,7 @@ void GridCellRendererMiddle::Draw(wxGrid& grid, //HIGHLIGHTNING (sync direction): if (rowIsHighlighted && m_gridMiddle.highlightedPos != CustomGridMiddle::BLOCKPOS_CHECK_BOX) //don't allow changing direction for "=="-files + switch (m_gridMiddle.highlightedPos) { case CustomGridMiddle::BLOCKPOS_CHECK_BOX: @@ -2374,25 +2383,35 @@ const wxBitmap& zen::getSyncOpImage(SyncOperation syncOp) switch (syncOp) //evaluate comparison result and sync direction { case SO_CREATE_NEW_LEFT: - return GlobalResources::getImage(wxT("createLeftSmall")); + return GlobalResources::getImage(L"createLeftSmall"); case SO_CREATE_NEW_RIGHT: - return GlobalResources::getImage(wxT("createRightSmall")); + return GlobalResources::getImage(L"createRightSmall"); case SO_DELETE_LEFT: - return GlobalResources::getImage(wxT("deleteLeftSmall")); + return GlobalResources::getImage(L"deleteLeftSmall"); case SO_DELETE_RIGHT: - return GlobalResources::getImage(wxT("deleteRightSmall")); + return GlobalResources::getImage(L"deleteRightSmall"); + case SO_MOVE_LEFT_SOURCE: + return GlobalResources::getImage(L"moveLeftSourceSmall"); + case SO_MOVE_LEFT_TARGET: + return GlobalResources::getImage(L"moveLeftTargetSmall"); + case SO_MOVE_RIGHT_SOURCE: + return GlobalResources::getImage(L"moveRightSourceSmall"); + case SO_MOVE_RIGHT_TARGET: + return GlobalResources::getImage(L"moveRightTargetSmall"); case SO_OVERWRITE_RIGHT: + return GlobalResources::getImage(L"updateRightSmall"); case SO_COPY_METADATA_TO_RIGHT: - return GlobalResources::getImage(wxT("updateRightSmall")); + return GlobalResources::getImage(L"moveRightSmall"); case SO_OVERWRITE_LEFT: + return GlobalResources::getImage(L"updateLeftSmall"); case SO_COPY_METADATA_TO_LEFT: - return GlobalResources::getImage(wxT("updateLeftSmall")); + return GlobalResources::getImage(L"moveLeftSmall"); case SO_DO_NOTHING: - return GlobalResources::getImage(wxT("noneSmall")); + return GlobalResources::getImage(L"noneSmall"); case SO_EQUAL: - return GlobalResources::getImage(wxT("equalSmall")); + return GlobalResources::getImage(L"equalSmall"); case SO_UNRESOLVED_CONFLICT: - return GlobalResources::getImage(wxT("conflictSmall")); + return GlobalResources::getImage(L"conflictSmall"); } return wxNullBitmap; //dummy diff --git a/lib/db_file.cpp b/lib/db_file.cpp index faee4c8a..60a721b1 100644 --- a/lib/db_file.cpp +++ b/lib/db_file.cpp @@ -15,7 +15,7 @@ #include #include #include -#include +#include #ifdef FFS_WIN #include //includes "windows.h" @@ -29,15 +29,24 @@ namespace { //------------------------------------------------------------------------------------------------------------------------------- const char FILE_FORMAT_DESCR[] = "FreeFileSync"; -const int FILE_FORMAT_VER = 7; +const int FILE_FORMAT_VER = 8; //------------------------------------------------------------------------------------------------------------------------------- +typedef std::string UniqueId; +typedef Zbase MemoryStream; //ref-counted byte stream representing DirInformation +typedef std::map StreamMapping; //list of streams ordered by session UUID + + +//------------------------------------------------------------------------------------ +//| ensure 32/64 bit portability: used fixed size data types only e.g. std::uint32_t | +//------------------------------------------------------------------------------------ + template inline Zstring getDBFilename(const BaseDirMapping& baseMap, bool tempfile = false) { - //Linux and Windows builds are binary incompatible: char/wchar_t case, sensitive/insensitive - //32 and 64 bit db files ARE designed to be binary compatible! + //Linux and Windows builds are binary incompatible: different file id?, problem with case sensitivity? + //however 32 and 64 bit db files *are* designed to be binary compatible! //Give db files different names. //make sure they end with ".ffs_db". These files will not be included into comparison when located in base sync directories #ifdef FFS_WIN @@ -51,255 +60,209 @@ Zstring getDBFilename(const BaseDirMapping& baseMap, bool tempfile = false) } - -class FileInputStreamDB : public FileInputStream +StreamMapping loadStreams(const Zstring& filename) //throw FileError { -public: - FileInputStreamDB(const Zstring& filename) : //throw FileError - FileInputStream(filename) + if (!zen::fileExists(filename)) + throw FileErrorDatabaseNotExisting(_("Initial synchronization:") + L" \n\n" + + _("One of the FreeFileSync database files is not yet existing:") + L" \n" + + L"\"" + filename + L"\""); + try { + //read format description (uncompressed) + FileInputStream rawStream(filename); //throw FileError + //read FreeFileSync file identifier char formatDescr[sizeof(FILE_FORMAT_DESCR)] = {}; - Read(formatDescr, sizeof(formatDescr)); //throw FileError + rawStream.Read(formatDescr, sizeof(formatDescr)); //throw FileError if (!std::equal(FILE_FORMAT_DESCR, FILE_FORMAT_DESCR + sizeof(FILE_FORMAT_DESCR), formatDescr)) throw FileError(_("Incompatible synchronization database format:") + L" \n" + L"\"" + filename + L"\""); - } -private: -}; + wxZlibInputStream decompressed(rawStream, wxZLIB_ZLIB); + CheckedReader cr(decompressed, filename); -class FileOutputStreamDB : public FileOutputStream -{ -public: - FileOutputStreamDB(const Zstring& filename) : //throw FileError - FileOutputStream(filename) + std::int32_t version = cr.readNumberC(); + if (version != FILE_FORMAT_VER) //read file format version# + throw FileError(_("Incompatible synchronization database format:") + L" \n" + L"\"" + filename + L"\""); + + //read stream lists + StreamMapping output; + + std::uint32_t dbCount = cr.readNumberC(); //number of databases: one for each sync-pair + while (dbCount-- != 0) + { + //DB id of partner databases + const std::string sessionID = cr.readStringC(); + const MemoryStream stream = cr.readStringC(); //read db-entry stream (containing DirInformation) + + output.insert(std::make_pair(sessionID, stream)); + } + return output; + } + catch (const std::bad_alloc&) //this is most likely caused by a corrupted database file { - //write FreeFileSync file identifier - Write(FILE_FORMAT_DESCR, sizeof(FILE_FORMAT_DESCR)); //throw FileError + throw FileError(_("Error reading from synchronization database:") + L" (bad alloc)"); } - -private: -}; } -//####################################################################################################################################### -class ReadDirInfo : public zen::ReadInputStream +class StreamParser : private CheckedReader { public: - ReadDirInfo(wxInputStream& stream, const Zstring& errorObjName, DirInformation& dirInfo) : ReadInputStream(stream, errorObjName) + static DirInfoPtr execute(const MemoryStream& stream, const Zstring& fileName) //throw FileError -> return value always bound! { - //|------------------------------------------------------------------------------------- - //| ensure 32/64 bit portability: use fixed size data types only e.g. boost::uint32_t | - //|------------------------------------------------------------------------------------- - - //read filter settings -> currently not required, but persisting it doesn't hurt - dirInfo.filter = HardFilter::loadFilter(getStream()); - check(); - - //start recursion - execute(dirInfo.baseDirContainer); + try + { + //read streams into DirInfo + auto dirInfo = std::make_shared(); + wxMemoryInputStream buffer(&*stream.begin(), stream.size()); //convert char-array to inputstream: no copying, ownership not transferred + StreamParser(buffer, fileName, *dirInfo); //throw FileError + return dirInfo; + } + catch (const std::bad_alloc&) //this is most likely caused by a corrupted database file + { + throw FileError(_("Error reading from synchronization database:") + L" (bad alloc)"); + } } private: - void execute(DirContainer& dirCont) const + StreamParser(wxInputStream& stream, const Zstring& errorObjName, DirInformation& dirInfo) : CheckedReader(stream, errorObjName) { - while (readNumberC()) - readSubFile(dirCont); - - while (readNumberC()) - readSubLink(dirCont); - - while (readNumberC()) - readSubDirectory(dirCont); + recurse(dirInfo.baseDirContainer); } - void readSubFile(DirContainer& dirCont) const + Zstring readStringUtf8() const { - //attention: order of function argument evaluation is undefined! So do it one after the other... - const Zstring shortName = readStringC(); //file name - - const std::int64_t modTime = readNumberC(); - const std::uint64_t fileSize = readNumberC(); - - //const util::FileID fileIdentifier(stream_); - //check(); - - dirCont.addSubFile(shortName, - FileDescriptor(modTime, fileSize)); + return utf8CvrtTo(readStringC>()); } - - void readSubLink(DirContainer& dirCont) const + FileId readFileId() const { - //attention: order of function argument evaluation is undefined! So do it one after the other... - const Zstring shortName = readStringC(); //file name - const std::int64_t modTime = readNumberC(); - const Zstring targetPath = readStringC(); //file name - const LinkDescriptor::LinkType linkType = static_cast(readNumberC()); - - dirCont.addSubLink(shortName, - LinkDescriptor(modTime, targetPath, linkType)); - } + assert_static(sizeof(FileId().first ) <= sizeof(std::uint64_t)); + assert_static(sizeof(FileId().second) <= sizeof(std::uint64_t)); - - void readSubDirectory(DirContainer& dirCont) const - { - const Zstring shortName = readStringC(); //directory name - DirContainer& subDir = dirCont.addSubDir(shortName); - execute(subDir); //recurse + const auto devId = static_cast(readNumberC()); // + const auto fId = static_cast(readNumberC()); //silence "loss of precision" compiler warnings + return std::make_pair(devId, fId); } -}; -namespace -{ -typedef std::string UniqueId; -typedef std::shared_ptr > MemoryStreamPtr; //byte stream representing DirInformation -typedef std::map StreamMapping; //list of streams ordered by session UUID -} - -class ReadFileStream : public zen::ReadInputStream -{ -public: - ReadFileStream(wxInputStream& stream, const Zstring& filename, StreamMapping& streamList) : ReadInputStream(stream, filename) + void recurse(DirContainer& dirCont) const { - //|------------------------------------------------------------------------------------- - //| ensure 32/64 bit portability: used fixed size data types only e.g. boost::uint32_t | - //|------------------------------------------------------------------------------------- - - std::int32_t version = readNumberC(); + while (readNumberC()) //files + { + //attention: order of function argument evaluation is undefined! So do it one after the other... + const Zstring shortName = readStringUtf8(); //file name - if (version != FILE_FORMAT_VER) //read file format version - throw FileError(_("Incompatible synchronization database format:") + L" \n" + L"\"" + filename + L"\""); + const std::int64_t modTime = readNumberC(); + const std::uint64_t fileSize = readNumberC(); + const FileId fileID = readFileId(); - streamList.clear(); + dirCont.addSubFile(shortName, + FileDescriptor(modTime, fileSize, fileID)); + } - boost::uint32_t dbCount = readNumberC(); //number of databases: one for each sync-pair - while (dbCount-- != 0) + while (readNumberC()) //symlinks { - //DB id of partner databases - const CharArray tmp2 = readArrayC(); - const std::string sessionID(tmp2->begin(), tmp2->end()); - - CharArray buffer = readArrayC(); //read db-entry stream (containing DirInformation) + //attention: order of function argument evaluation is undefined! So do it one after the other... + const Zstring shortName = readStringUtf8(); //file name + const std::int64_t modTime = readNumberC(); + const Zstring targetPath = readStringUtf8(); //file name + const LinkDescriptor::LinkType linkType = static_cast(readNumberC()); + + dirCont.addSubLink(shortName, + LinkDescriptor(modTime, targetPath, linkType)); + } - streamList.insert(std::make_pair(sessionID, buffer)); + while (readNumberC()) //directories + { + const Zstring shortName = readStringUtf8(); //directory name + DirContainer& subDir = dirCont.addSubDir(shortName); + recurse(subDir); } } }; -namespace -{ -StreamMapping loadStreams(const Zstring& filename) //throw FileError -{ - if (!zen::fileExists(filename)) - throw FileErrorDatabaseNotExisting(_("Initial synchronization:") + L" \n\n" + - _("One of the FreeFileSync database files is not yet existing:") + L" \n" + - L"\"" + filename + L"\""); - - try - { - //read format description (uncompressed) - FileInputStreamDB uncompressed(filename); //throw FileError - - wxZlibInputStream input(uncompressed, wxZLIB_ZLIB); - StreamMapping streamList; - ReadFileStream(input, filename, streamList); - return streamList; - } - catch (const std::bad_alloc&) //this is most likely caused by a corrupted database file +//save/load DirContainer +void saveFile(const StreamMapping& streamList, const Zstring& filename) //throw FileError +{ { - throw FileError(_("Error reading from synchronization database:") + L" (bad_alloc)"); - } -} + FileOutputStream rawStream(filename); //throw FileError + //write FreeFileSync file identifier + rawStream.Write(FILE_FORMAT_DESCR, sizeof(FILE_FORMAT_DESCR)); //throw FileError -DirInfoPtr parseStream(const std::vector& stream, const Zstring& fileName) //throw FileError -> return value always bound! -{ - try - { - //read streams into DirInfo - auto dirInfo = std::make_shared(); - wxMemoryInputStream buffer(&stream[0], stream.size()); //convert char-array to inputstream: no copying, ownership not transferred - ReadDirInfo(buffer, fileName, *dirInfo); //throw FileError - return dirInfo; - } - catch (const std::bad_alloc&) //this is most likely caused by a corrupted database file - { - throw FileError(_("Error reading from synchronization database:") + L" (bad_alloc)"); - } -} -} + wxZlibOutputStream compressed(rawStream, 4, wxZLIB_ZLIB); + /* 4 - best compromise between speed and compression: (scanning 200.000 objects) + 0 (uncompressed) 8,95 MB - 422 ms + 2 2,07 MB - 470 ms + 4 1,87 MB - 500 ms + 6 1,77 MB - 613 ms + 9 (maximal compression) 1,74 MB - 3330 ms */ + CheckedWriter cw(compressed, filename); -std::pair zen::loadFromDisk(const BaseDirMapping& baseMapping) //throw FileError -{ - const Zstring fileNameLeft = getDBFilename(baseMapping); - const Zstring fileNameRight = getDBFilename(baseMapping); + //save file format version + cw.writeNumberC(FILE_FORMAT_VER); - //read file data: list of session ID + DirInfo-stream - const StreamMapping streamListLeft = ::loadStreams(fileNameLeft); //throw FileError - const StreamMapping streamListRight = ::loadStreams(fileNameRight); //throw FileError + //save stream list + cw.writeNumberC(static_cast(streamList.size())); //number of database records: one for each sync-pair - //find associated session: there can be at most one session within intersection of left and right ids - StreamMapping::const_iterator streamLeft = streamListLeft .end(); - StreamMapping::const_iterator streamRight = streamListRight.end(); - for (auto iterLeft = streamListLeft.begin(); iterLeft != streamListLeft.end(); ++iterLeft) - { - auto iterRight = streamListRight.find(iterLeft->first); - if (iterRight != streamListRight.end()) + for (auto iter = streamList.begin(); iter != streamList.end(); ++iter) { - streamLeft = iterLeft; - streamRight = iterRight; - break; + cw.writeStringC(iter->first ); //sync session id + cw.writeStringC(iter->second); //DirInformation stream } } - - if (streamLeft == streamListLeft .end() || - streamRight == streamListRight.end() || - !streamLeft ->second.get() || - !streamRight->second.get()) - throw FileErrorDatabaseNotExisting(_("Initial synchronization:") + L" \n\n" + - _("Database files do not share a common synchronization session:") + L" \n" + - L"\"" + fileNameLeft + L"\"\n" + - L"\"" + fileNameRight + L"\""); - //read streams into DirInfo - DirInfoPtr dirInfoLeft = parseStream(*streamLeft ->second, fileNameLeft); //throw FileError - DirInfoPtr dirInfoRight = parseStream(*streamRight->second, fileNameRight); //throw FileError - - return std::make_pair(dirInfoLeft, dirInfoRight); + //(try to) hide database file +#ifdef FFS_WIN + ::SetFileAttributes(zen::applyLongPathPrefix(filename).c_str(), FILE_ATTRIBUTE_HIDDEN); +#endif } -//------------------------------------------------------------------------------------------------------------------------- template -class SaveDirInfo : public WriteOutputStream +class StreamGenerator : private CheckedWriter { public: - SaveDirInfo(const BaseDirMapping& baseMapping, const DirContainer* oldDirInfo, const Zstring& errorObjName, wxOutputStream& stream) : WriteOutputStream(errorObjName, stream) + static MemoryStream execute(const BaseDirMapping& baseMapping, const DirContainer* oldDirInfo, const Zstring& errorObjName) { - //save filter settings - baseMapping.getFilter()->saveFilter(getStream()); - check(); + wxMemoryOutputStream buffer; + StreamGenerator(baseMapping, oldDirInfo, errorObjName, buffer); - //start recursion - execute(baseMapping, oldDirInfo); + MemoryStream output; + output.resize(buffer.GetSize()); + buffer.CopyTo(&*output.begin(), buffer.GetSize()); + return output; } private: - void execute(const HierarchyObject& hierObj, const DirContainer* oldDirInfo) + StreamGenerator(const BaseDirMapping& baseMapping, const DirContainer* oldDirInfo, const Zstring& errorObjName, wxOutputStream& stream) : CheckedWriter(stream, errorObjName) + { + recurse(baseMapping, oldDirInfo); + } + + void recurse(const HierarchyObject& hierObj, const DirContainer* oldDirInfo) { - std::for_each(hierObj.refSubFiles().begin(), hierObj.refSubFiles().end(), boost::bind(&SaveDirInfo::processFile, this, _1, oldDirInfo)); + // for (const auto& fileMap : hierObj.refSubFiles()) { processFile(fileMap, oldDirInfo); }); ! + + std::for_each(hierObj.refSubFiles().begin(), hierObj.refSubFiles().end(), [&](const FileMapping& fileMap) { this->processFile(fileMap, oldDirInfo); }); writeNumberC(false); //mark last entry - std::for_each(hierObj.refSubLinks().begin(), hierObj.refSubLinks().end(), boost::bind(&SaveDirInfo::processLink, this, _1, oldDirInfo)); + std::for_each(hierObj.refSubLinks().begin(), hierObj.refSubLinks().end(), [&](const SymLinkMapping& linkObj) { this->processLink(linkObj, oldDirInfo); }); writeNumberC(false); //mark last entry - std::for_each(hierObj.refSubDirs ().begin(), hierObj.refSubDirs ().end(), boost::bind(&SaveDirInfo::processDir, this, _1, oldDirInfo)); + std::for_each(hierObj.refSubDirs ().begin(), hierObj.refSubDirs ().end(), [&](const DirMapping& dirMap) { this->processDir(dirMap, oldDirInfo); }); writeNumberC(false); //mark last entry } + void writeStringUtf8(const Zstring& str) { writeStringC(utf8CvrtTo>(str)); } + + void writeFileId(const FileId& id) + { + writeNumberC(id.first ); //device id + writeNumberC(id.second); //file id + } + void processFile(const FileMapping& fileMap, const DirContainer* oldParentDir) { if (fileMap.getCategory() == FILE_EQUAL) //data in sync: write current state @@ -307,9 +270,10 @@ private: if (!fileMap.isEmpty()) { writeNumberC(true); //mark beginning of entry - writeStringC(fileMap.getShortName()); //save respecting case! (Windows) - writeNumberC(to(fileMap.getLastWriteTime())); //last modification time - writeNumberC(to(fileMap.getFileSize())); //filesize + writeStringUtf8(fileMap.getShortName()); //save respecting case! (Windows) + writeNumberC(to(fileMap.getLastWriteTime())); + writeNumberC(to(fileMap.getFileSize())); + writeFileId(fileMap.getFileId()); } } else //not in sync: reuse last synchronous state @@ -320,9 +284,10 @@ private: if (iter != oldParentDir->files.end()) { writeNumberC(true); //mark beginning of entry - writeStringC(iter->first); //save respecting case! (Windows) - writeNumberC(to(iter->second.lastWriteTimeRaw)); //last modification time - writeNumberC(to(iter->second.fileSize)); //filesize + writeStringUtf8(iter->first); //save respecting case! (Windows) + writeNumberC(to(iter->second.lastWriteTimeRaw)); + writeNumberC(to(iter->second.fileSize)); + writeFileId(iter->second.id); } } } @@ -335,9 +300,9 @@ private: if (!linkObj.isEmpty()) { writeNumberC(true); //mark beginning of entry - writeStringC(linkObj.getShortName()); //save respecting case! (Windows) - writeNumberC(to(linkObj.getLastWriteTime())); //last modification time - writeStringC(linkObj.getTargetPath()); + writeStringUtf8(linkObj.getShortName()); //save respecting case! (Windows) + writeNumberC(to(linkObj.getLastWriteTime())); + writeStringUtf8(linkObj.getTargetPath()); writeNumberC(linkObj.getLinkType()); } } @@ -349,9 +314,9 @@ private: if (iter != oldParentDir->links.end()) { writeNumberC(true); //mark beginning of entry - writeStringC(iter->first); //save respecting case! (Windows) - writeNumberC(to(iter->second.lastWriteTimeRaw)); //last modification time - writeStringC(iter->second.targetPath); + writeStringUtf8(iter->first); //save respecting case! (Windows) + writeNumberC(to(iter->second.lastWriteTimeRaw)); + writeStringUtf8(iter->second.targetPath); writeNumberC(iter->second.type); } } @@ -379,8 +344,8 @@ private: if (!dirMap.isEmpty()) { writeNumberC(true); //mark beginning of entry - writeStringC(dirMap.getShortName()); //save respecting case! (Windows) - execute(dirMap, oldDir); //recurse + writeStringUtf8(dirMap.getShortName()); //save respecting case! (Windows) + recurse(dirMap, oldDir); } } else //not in sync: reuse last synchronous state @@ -388,8 +353,8 @@ private: if (oldDir) { writeNumberC(true); //mark beginning of entry - writeStringC(*oldDirName); //save respecting case! (Windows) - execute(dirMap, oldDir); //recurse + writeStringUtf8(*oldDirName); //save respecting case! (Windows) + recurse(dirMap, oldDir); return; } //no data is also a "synchronous state"! @@ -408,69 +373,53 @@ private: break; case DIR_DIFFERENT_METADATA: writeNumberC(true); - writeStringC(dirMap.getShortName()); + writeStringUtf8(dirMap.getShortName()); //ATTENTION: strictly this is a violation of the principle of reporting last synchronous state! //however in this case this will result in "last sync unsuccessful" for this directory within algorithm, which is fine - execute(dirMap, oldDir); //recurse and save sub-items which are in sync + recurse(dirMap, oldDir); //recurse and save sub-items which are in sync break; } } } }; +} +//####################################################################################################################################### -class WriteFileStream : public WriteOutputStream +std::pair zen::loadFromDisk(const BaseDirMapping& baseMapping) //throw FileError { -public: - WriteFileStream(const StreamMapping& streamList, const Zstring& filename, wxOutputStream& stream) : WriteOutputStream(filename, stream) - { - //save file format version - writeNumberC(FILE_FORMAT_VER); + const Zstring fileNameLeft = getDBFilename(baseMapping); + const Zstring fileNameRight = getDBFilename(baseMapping); - writeNumberC(static_cast(streamList.size())); //number of database records: one for each sync-pair + //read file data: list of session ID + DirInfo-stream + const StreamMapping streamListLeft = ::loadStreams(fileNameLeft); //throw FileError + const StreamMapping streamListRight = ::loadStreams(fileNameRight); //throw FileError - for (StreamMapping::const_iterator i = streamList.begin(); i != streamList.end(); ++i) + //find associated session: there can be at most one session within intersection of left and right ids + StreamMapping::const_iterator streamLeft = streamListLeft .end(); + StreamMapping::const_iterator streamRight = streamListRight.end(); + for (auto iterLeft = streamListLeft.begin(); iterLeft != streamListLeft.end(); ++iterLeft) + { + auto iterRight = streamListRight.find(iterLeft->first); + if (iterRight != streamListRight.end()) { - //sync session id - writeArrayC(std::vector(i->first.begin(), i->first.end())); - - //write DirInformation stream - writeArrayC(*(i->second)); + streamLeft = iterLeft; + streamRight = iterRight; + break; } } -}; + if (streamLeft == streamListLeft .end() || + streamRight == streamListRight.end()) + throw FileErrorDatabaseNotExisting(_("Initial synchronization:") + L" \n\n" + + _("Database files do not share a common synchronization session:") + L" \n" + + L"\"" + fileNameLeft + L"\"\n" + + L"\"" + fileNameRight + L"\""); + //read streams into DirInfo + DirInfoPtr dirInfoLeft = StreamParser::execute(streamLeft ->second, fileNameLeft); //throw FileError + DirInfoPtr dirInfoRight = StreamParser::execute(streamRight->second, fileNameRight); //throw FileError -//save/load DirContainer -void saveFile(const StreamMapping& streamList, const Zstring& filename) //throw FileError -{ - { - //write format description (uncompressed) - FileOutputStreamDB uncompressed(filename); //throw FileError - - wxZlibOutputStream output(uncompressed, 4, wxZLIB_ZLIB); - /* 4 - best compromise between speed and compression: (scanning 200.000 objects) - 0 (uncompressed) 8,95 MB - 422 ms - 2 2,07 MB - 470 ms - 4 1,87 MB - 500 ms - 6 1,77 MB - 613 ms - 9 (maximal compression) 1,74 MB - 3330 ms */ - - WriteFileStream(streamList, filename, output); - } - //(try to) hide database file -#ifdef FFS_WIN - ::SetFileAttributes(zen::applyLongPathPrefix(filename).c_str(), FILE_ATTRIBUTE_HIDDEN); -#endif -} - - -bool equalEntry(const MemoryStreamPtr& lhs, const MemoryStreamPtr& rhs) -{ - if (!lhs.get() || !rhs.get()) - return lhs.get() == rhs.get(); - - return *lhs == *rhs; + return std::make_pair(dirInfoLeft, dirInfoRight); } @@ -522,12 +471,10 @@ void zen::saveToDisk(const BaseDirMapping& baseMapping) //throw FileError try { if (streamLeft != streamListLeft .end() && - streamRight != streamListRight.end() && - streamLeft ->second.get() && - streamRight->second.get()) + streamRight != streamListRight.end()) { - oldDirInfoLeft = parseStream(*streamLeft ->second, dbNameLeft); //throw FileError - oldDirInfoRight = parseStream(*streamRight->second, dbNameRight); //throw FileError + oldDirInfoLeft = StreamParser::execute(streamLeft ->second, dbNameLeft ); //throw FileError + oldDirInfoRight = StreamParser::execute(streamRight->second, dbNameRight); //throw FileError } } catch (FileError&) @@ -538,28 +485,13 @@ void zen::saveToDisk(const BaseDirMapping& baseMapping) //throw FileError } //create new database entries - MemoryStreamPtr newStreamLeft = std::make_shared>(); - { - wxMemoryOutputStream buffer; - const DirContainer* oldDir = oldDirInfoLeft.get() ? &oldDirInfoLeft->baseDirContainer : NULL; - SaveDirInfo(baseMapping, oldDir, dbNameLeft, buffer); - newStreamLeft->resize(buffer.GetSize()); //convert output stream to char-array - buffer.CopyTo(&(*newStreamLeft)[0], buffer.GetSize()); // - } - - MemoryStreamPtr newStreamRight = std::make_shared>(); - { - wxMemoryOutputStream buffer; - const DirContainer* oldDir = oldDirInfoRight.get() ? &oldDirInfoRight->baseDirContainer : NULL; - SaveDirInfo(baseMapping, oldDir, dbNameRight, buffer); - newStreamRight->resize(buffer.GetSize()); //convert output stream to char-array - buffer.CopyTo(&(*newStreamRight)[0], buffer.GetSize()); // - } + MemoryStream newStreamLeft = StreamGenerator::execute(baseMapping, oldDirInfoLeft .get() ? &oldDirInfoLeft ->baseDirContainer : NULL, dbNameLeft); + MemoryStream newStreamRight = StreamGenerator::execute(baseMapping, oldDirInfoRight.get() ? &oldDirInfoRight->baseDirContainer : NULL, dbNameRight); //check if there is some work to do at all { - const bool updateRequiredLeft = streamLeft == streamListLeft .end() || !equalEntry(newStreamLeft, streamLeft ->second); - const bool updateRequiredRight = streamRight == streamListRight.end() || !equalEntry(newStreamRight, streamRight->second); + const bool updateRequiredLeft = streamLeft == streamListLeft .end() || newStreamLeft != streamLeft ->second; + const bool updateRequiredRight = streamRight == streamListRight.end() || newStreamRight != streamRight->second; //some users monitor the *.ffs_db file with RTS => don't touch the file if it isnt't strictly needed if (!updateRequiredLeft && !updateRequiredRight) return; @@ -579,10 +511,10 @@ void zen::saveToDisk(const BaseDirMapping& baseMapping) //throw FileError streamListRight.insert(std::make_pair(sessionID, newStreamRight)); //write (temp-) files... - zen::ScopeGuard guardTempFileLeft = zen::makeGuard([&]() {zen::removeFile(dbNameLeftTmp); }); + zen::ScopeGuard guardTempFileLeft = zen::makeGuard([&] {zen::removeFile(dbNameLeftTmp); }); saveFile(streamListLeft, dbNameLeftTmp); //throw FileError - zen::ScopeGuard guardTempFileRight = zen::makeGuard([&]() {zen::removeFile(dbNameRightTmp); }); + zen::ScopeGuard guardTempFileRight = zen::makeGuard([&] {zen::removeFile(dbNameRightTmp); }); saveFile(streamListRight, dbNameRightTmp); //throw FileError //operation finished: rename temp files -> this should work transactionally: diff --git a/lib/db_file.h b/lib/db_file.h index d6d765cc..0413c404 100644 --- a/lib/db_file.h +++ b/lib/db_file.h @@ -14,11 +14,8 @@ namespace zen { const Zstring SYNC_DB_FILE_ENDING = Zstr(".ffs_db"); -void saveToDisk(const BaseDirMapping& baseMapping); //throw FileError - struct DirInformation { - HardFilter::FilterRef filter; //filter settings (used when retrieving directory data) DirContainer baseDirContainer; //hierarchical directory information }; typedef std::shared_ptr DirInfoPtr; @@ -26,6 +23,8 @@ typedef std::shared_ptr DirInfoPtr; DEFINE_NEW_FILE_ERROR(FileErrorDatabaseNotExisting); std::pair loadFromDisk(const BaseDirMapping& baseMapping); //throw FileError, FileErrorDatabaseNotExisting -> return value always bound! + +void saveToDisk(const BaseDirMapping& baseMapping); //throw FileError } #endif // DBFILE_H_INCLUDED diff --git a/lib/detect_renaming.cpp b/lib/detect_renaming.cpp deleted file mode 100644 index 39e7eb4b..00000000 --- a/lib/detect_renaming.cpp +++ /dev/null @@ -1,285 +0,0 @@ -// ************************************************************************** -// * This file is part of the FreeFileSync project. It is distributed under * -// * GNU General Public License: http://www.gnu.org/licenses/gpl.html * -// * Copyright (C) 2008-2011 ZenJu (zhnmju123 AT gmx.de) * -// ************************************************************************** - -#include "detect_renaming.h" -#include -#include -#include - -using namespace FreeFileSync; - -/*detect renamed files: -Example: - X -> |_| Create right -|_| -> Y Delete right - -is detected as: - -Rename Y to X on right - -Algorithm: ----------- -DB-file left ---filename, Metadata(=:MD)---> DB-file right - /|\ | - | fileID, MD - fileID, MD | - | \|/ - X Y - -*/ - - -class FindDBAssoc -{ - /* - load and associate db-files by filename and metadata(size, date) - fileID, MD |-> fileID - */ -public: - struct AssocKey - { - AssocKey(const Utility::FileID& fileId, - const wxLongLong& lastWriteTimeRaw, - const wxULongLong& fileSize); - - bool operator<(const AssocKey& other) const; - - Utility::FileID fileId_; - wxLongLong lastWriteTimeRaw_; - wxULongLong fileSize_; - }; - - FindDBAssoc(const FreeFileSync::BaseDirMapping& baseMapping, - std::map& assocDBLeftToRight); - -private: - void recurse(const DirContainer& leftSide, const DirContainer& rightSide); - - std::map& assocDBLeftToRight_; //--> -}; - - -inline -FindDBAssoc::AssocKey::AssocKey(const Utility::FileID& fileId, - const wxLongLong& lastWriteTimeRaw, - const wxULongLong& fileSize) : - fileId_(fileId), - lastWriteTimeRaw_(lastWriteTimeRaw), - fileSize_(fileSize) {} - - -inline -bool FindDBAssoc::AssocKey::operator<(const AssocKey& other) const -{ - if (fileId_ != other.fileId_) - return fileId_ < other.fileId_; - - if (lastWriteTimeRaw_ != other.lastWriteTimeRaw_) - return lastWriteTimeRaw_ < other.lastWriteTimeRaw_; - - return fileSize_ < other.fileSize_; -} - - -FindDBAssoc::FindDBAssoc(const FreeFileSync::BaseDirMapping& baseMapping, - std::map& assocDBLeftToRight) : assocDBLeftToRight_(assocDBLeftToRight) -{ - try - { - std::pair dbInfo = - FreeFileSync::loadFromDisk(baseMapping); //throw (FileError) - - recurse(dbInfo.first->baseDirContainer, - dbInfo.second->baseDirContainer); - } - catch (...) {} //swallow... -} - - -void FindDBAssoc::recurse(const DirContainer& leftSide, const DirContainer& rightSide) -{ - for (DirContainer::SubFileList::const_iterator i = leftSide.getSubFiles().begin(); i != leftSide.getSubFiles().end(); ++i) - { - const FileDescriptor& fileDescrI = i->second.getData(); - if (!fileDescrI.fileIdentifier.isNull()) //fileIdentifier may be NULL - { - const DirContainer::SubFileList::const_iterator j = rightSide.getSubFiles().find(i->first); - - //find files that exist on left and right - if (j != rightSide.getSubFiles().end()) - { - const FileDescriptor& fileDescrJ = j->second.getData(); - if (!fileDescrJ.fileIdentifier.isNull()) //fileIdentifier may be NULL - { - if ( fileDescrI.lastWriteTimeRaw == fileDescrJ.lastWriteTimeRaw && - fileDescrI.fileSize == fileDescrJ.fileSize) - { - assocDBLeftToRight_[AssocKey(fileDescrI.fileIdentifier, - fileDescrI.lastWriteTimeRaw, - fileDescrI.fileSize)] = fileDescrJ.fileIdentifier; - } - } - } - } - } - - //----------------------------------------------------------------------------------------------- - for (DirContainer::SubDirList::const_iterator i = leftSide.getSubDirs().begin(); i != leftSide.getSubDirs().end(); ++i) - { - const DirContainer::SubDirList::const_iterator j = rightSide.getSubDirs().find(i->first); - - //directories that exist on both sides - if (j != rightSide.getSubDirs().end()) - { - recurse(i->second, j->second); //recurse into subdirectories - } - } -} - - - -class FindRenameCandidates -{ -public: - FindRenameCandidates(FreeFileSync::BaseDirMapping& baseMapping) - { - FindDBAssoc(baseMapping, - assocDBLeftToRight); - - if (!assocDBLeftToRight.empty()) - recurse(baseMapping); - } - - void getRenameCandidates(std::vector >& renameOnLeft, - std::vector >& renameOnRight); - -private: - void recurse(HierarchyObject& hierObj) - { - //files - std::for_each(hierObj.subFiles.begin(), hierObj.subFiles.end(), - boost::bind(&FindRenameCandidates::processFile, this, _1)); - - //directories - std::for_each(hierObj.subDirs.begin(), hierObj.subDirs.end(), - boost::bind(&FindRenameCandidates::recurse, this, _1));//recursion - } - - void processFile(FileMapping& fileObj) - { - switch (fileObj.getSyncOperation()) //evaluate comparison result and sync direction - { - case SO_CREATE_NEW_LEFT: - if (!fileObj.getFileID().isNull()) //fileIdentifier may be NULL - createLeft[FindDBAssoc::AssocKey(fileObj.getFileID(), - fileObj.getLastWriteTime(), - fileObj.getFileSize())] = &fileObj; - break; - - case SO_CREATE_NEW_RIGHT: - if (!fileObj.getFileID().isNull()) //fileIdentifier may be NULL - createRight.push_back(&fileObj); - break; - - case SO_DELETE_LEFT: - if (!fileObj.getFileID().isNull()) //fileIdentifier may be NULL - deleteLeft.push_back(&fileObj); - break; - - case SO_DELETE_RIGHT: - if (!fileObj.getFileID().isNull()) //fileIdentifier may be NULL - deleteRight[FindDBAssoc::AssocKey(fileObj.getFileID(), - fileObj.getLastWriteTime(), - fileObj.getFileSize())] = &fileObj; - break; - - case SO_OVERWRITE_RIGHT: - case SO_OVERWRITE_LEFT: - case SO_DO_NOTHING: - case SO_UNRESOLVED_CONFLICT: - break; - } - - } - - - std::vector createRight; //pointer always bound! - std::vector deleteLeft; // - // | - // \|/ - std::map assocDBLeftToRight; - // | - // \|/ - std::map deleteRight; //pointer always bound! - std::map createLeft; // - -}; - - - -void FindRenameCandidates::getRenameCandidates( - std::vector >& renameOnLeft, - std::vector >& renameOnRight) -{ - for (std::vector::const_iterator crRightIter = createRight.begin(); - crRightIter != createRight.end(); - ++crRightIter) - { - const FindDBAssoc::AssocKey assocDbKey((*crRightIter)->getFileID(), - (*crRightIter)->getLastWriteTime(), - (*crRightIter)->getFileSize()); - - const std::map::const_iterator assocDBIter = - assocDBLeftToRight.find(assocDbKey); - - if (assocDBIter != assocDBLeftToRight.end()) - { - std::map::const_iterator delRightIter = - deleteRight.find(FindDBAssoc::AssocKey(assocDBIter->second, //FileID of right side - assocDbKey.lastWriteTimeRaw_, - assocDbKey.fileSize_)); - - if (delRightIter != deleteRight.end()) - { - renameOnRight.push_back(std::make_pair(*crRightIter, delRightIter->second)); - } - } - } - //------------------------------------------------------------------------------------------------ - for (std::vector::const_iterator delLeftIter = deleteLeft.begin(); - delLeftIter != deleteLeft.end(); - ++delLeftIter) - { - const FindDBAssoc::AssocKey assocDbKey((*delLeftIter)->getFileID(), - (*delLeftIter)->getLastWriteTime(), - (*delLeftIter)->getFileSize()); - - const std::map::const_iterator assocDBIter = - assocDBLeftToRight.find(assocDbKey); - - if (assocDBIter != assocDBLeftToRight.end()) - { - std::map::const_iterator createLeftIter = - createLeft.find(FindDBAssoc::AssocKey(assocDBIter->second, //FileID of right side - assocDbKey.lastWriteTimeRaw_, - assocDbKey.fileSize_)); - - if (createLeftIter != createLeft.end()) - { - renameOnLeft.push_back(std::make_pair(createLeftIter->second, *delLeftIter)); - } - } - } -} - - -void FreeFileSync::getRenameCandidates(FreeFileSync::BaseDirMapping& baseMapping, //in - std::vector >& renameOnLeft, //out - std::vector >& renameOnRight) //out throw()! -{ - FindRenameCandidates(baseMapping).getRenameCandidates(renameOnLeft, renameOnRight); -} - diff --git a/lib/detect_renaming.h b/lib/detect_renaming.h deleted file mode 100644 index e94927c0..00000000 --- a/lib/detect_renaming.h +++ /dev/null @@ -1,26 +0,0 @@ -// ************************************************************************** -// * This file is part of the FreeFileSync project. It is distributed under * -// * GNU General Public License: http://www.gnu.org/licenses/gpl.html * -// * Copyright (C) 2008-2011 ZenJu (zhnmju123 AT gmx.de) * -// ************************************************************************** - -#ifndef DETECTRENAMING_H_INCLUDED -#define DETECTRENAMING_H_INCLUDED - -#include "../file_hierarchy.h" - - -//identify a file "create and delete"-operation as a file renaming! - -namespace zen -{ -typedef FileMapping* CreateOnLeft; -typedef FileMapping* DeleteOnLeft; -typedef FileMapping* CreateOnRight; -typedef FileMapping* DeleteOnRight; -void getRenameCandidates(zen::BaseDirMapping& baseMapping, //in - std::vector >& renameOnLeft, //out - std::vector >& renameOnRight); //out throw()! -} - -#endif // DETECTRENAMING_H_INCLUDED diff --git a/lib/dir_exist_async.h b/lib/dir_exist_async.h index 72741ee2..f59e9490 100644 --- a/lib/dir_exist_async.h +++ b/lib/dir_exist_async.h @@ -20,9 +20,7 @@ bool dirExistsUpdating(const Zstring& dirname, bool allowUserInteraction, Proces { using namespace zen; - std::wstring statusText = _("Searching for directory %x..."); - replace(statusText, L"%x", std::wstring(L"\"") + dirname + L"\"", false); - procCallback.reportStatus(statusText); + procCallback.reportStatus(replaceCpy(_("Searching for directory %x..."), L"%x", std::wstring(L"\"") + dirname + L"\"", false)); auto ft = async([=]() -> bool { diff --git a/lib/dir_lock.cpp b/lib/dir_lock.cpp index 735fd7b6..ab3c84ea 100644 --- a/lib/dir_lock.cpp +++ b/lib/dir_lock.cpp @@ -74,10 +74,10 @@ public: //ATTENTION: setting file pointer IS required! => use CreateFile/FILE_GENERIC_WRITE + SetFilePointerEx! //although CreateFile/FILE_APPEND_DATA without SetFilePointerEx works locally, it MAY NOT work on some network shares creating a 4 gig file!!! - const HANDLE fileHandle = ::CreateFile(applyLongPathPrefix(lockfilename_.c_str()).c_str(), + const HANDLE fileHandle = ::CreateFile(applyLongPathPrefix(lockfilename_).c_str(), GENERIC_READ | GENERIC_WRITE, //use both when writing over network, see comment in file_io.cpp FILE_SHARE_READ, - 0, + NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); @@ -340,8 +340,8 @@ std::string retrieveLockId(const Zstring& lockfilename) //throw FileError, Error void waitOnDirLock(const Zstring& lockfilename, DirLockCallback* callback) //throw FileError { - std::wstring infoMsg = _("Waiting while directory is locked (%x)..."); - replace(infoMsg, L"%x", std::wstring(L"\"") + lockfilename + L"\""); + const std::wstring infoMsg = replaceCpy(_("Waiting while directory is locked (%x)..."), L"%x", std::wstring(L"\"") + lockfilename + L"\""); + if (callback) callback->reportInfo(infoMsg); //--------------------------------------------------------------- @@ -408,8 +408,8 @@ void waitOnDirLock(const Zstring& lockfilename, DirLockCallback* callback) //thr long remainingSeconds = ((DETECT_EXITUS_INTERVAL - (wxGetLocalTimeMillis() - lockSilentStart)) / 1000).ToLong(); remainingSeconds = std::max(0L, remainingSeconds); - std::wstring remSecMsg = _P("1 sec", "%x sec", remainingSeconds); - replace(remSecMsg, L"%x", toString(remainingSeconds)); + const std::wstring remSecMsg = replaceCpy(_P("1 sec", "%x sec", remainingSeconds), L"%x", toString(remainingSeconds)); + callback->reportInfo(infoMsg + L" " + remSecMsg); } else @@ -441,7 +441,7 @@ bool tryLock(const Zstring& lockfilename) //throw FileError const HANDLE fileHandle = ::CreateFile(applyLongPathPrefix(lockfilename).c_str(), GENERIC_READ | GENERIC_WRITE, //use both when writing over network, see comment in file_io.cpp FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, - 0, + NULL, CREATE_NEW, FILE_ATTRIBUTE_NORMAL, NULL); @@ -472,7 +472,7 @@ bool tryLock(const Zstring& lockfilename) //throw FileError ::close(fileHandle); #endif - zen::ScopeGuard guardLockFile = zen::makeGuard([&]() { zen::removeFile(lockfilename); }); + ScopeGuard guardLockFile = zen::makeGuard([&] { zen::removeFile(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.) writeLockInfo(lockfilename); //throw FileError diff --git a/lib/dir_name.cpp b/lib/dir_name.cpp index 71a3e9ef..55a4185c 100644 --- a/lib/dir_name.cpp +++ b/lib/dir_name.cpp @@ -40,7 +40,7 @@ void setDirectoryNameImpl(const wxString& dirname, wxDirPickerCtrl* dirPicker, w if (dirPicker && !dirFormatted.empty()) { Zstring dir = toZ(dirFormatted); //convert to Zstring first: we don't want to pass wxString by value and risk MT issues! - auto ft = async([=]() { return zen::dirExists(dir); }); + auto ft = async([=] { return zen::dirExists(dir); }); if (ft.timed_wait(boost::posix_time::milliseconds(timeout)) && ft.get()) //potentially slow network access: wait 200ms at most dirPicker->SetPath(dirFormatted); diff --git a/lib/localization.cpp b/lib/localization.cpp index e8ff6040..574910ea 100644 --- a/lib/localization.cpp +++ b/lib/localization.cpp @@ -301,6 +301,7 @@ wxLanguage mapLanguageDialect(wxLanguage language) //case wxLANGUAGE_PORTUGUESE_BRAZILIAN: //case wxLANGUAGE_KOREAN: //case wxLANGUAGE_UKRAINIAN: + //case wxLANGUAGE_CROATIAN: //variants of wxLANGUAGE_ARABIC case wxLANGUAGE_ARABIC_ALGERIA: diff --git a/lib/parallel_scan.cpp b/lib/parallel_scan.cpp index 96b167b8..1052a408 100644 --- a/lib/parallel_scan.cpp +++ b/lib/parallel_scan.cpp @@ -141,7 +141,7 @@ Windows 7: Windows XP: 1 Thread: 41s | 13s 1 Thread: 45s | 13s 2 Threads: 42s | 11s 2 Threads: 38s | 8s -=> Traversing does not take any advantage of file locality so that even multiple threads operating on the same disk impose no performance overhead! +=> Traversing does not take any advantage of file locality so that even multiple threads operating on the same disk impose no performance overhead! (even faster on XP) */ @@ -196,7 +196,7 @@ public: errorMsg.clear(); errorResponse.reset(); - //dummy.unlock(); + dummy.unlock(); //optimization for condition_variable::notify_one() conditionCanReportError.notify_one(); return rv; @@ -204,13 +204,13 @@ public: void processErrors(FillBufferCallback& callback) //context of main thread, call repreatedly { - boost::lock_guard dummy(lockErrorMsg); + boost::unique_lock dummy(lockErrorMsg); if (!errorMsg.empty() && !errorResponse.get()) { FillBufferCallback::HandleError rv = callback.reportError(copyStringTo(errorMsg)); //throw! errorResponse.reset(new FillBufferCallback::HandleError(rv)); - //dummy.unlock(); + dummy.unlock(); //optimization for condition_variable::notify_one() conditionGotResponse.notify_one(); } } @@ -293,6 +293,7 @@ private: }; //------------------------------------------------------------------------------------------------- + struct TraverserShared { public: @@ -372,7 +373,7 @@ void DirCallback::onFile(const Zchar* shortName, const Zstring& fullName, const Linux: retrieveFileID takes about 50% longer in VM! (avoidable because of redundant stat() call!) */ - output_.addSubFile(fileNameShort, FileDescriptor(details.lastWriteTimeRaw, details.fileSize)); + output_.addSubFile(fileNameShort, FileDescriptor(details.lastWriteTimeRaw, details.fileSize, details.id)); cfg.acb_.incItemsScanned(); //add 1 element to the progress indicator } @@ -547,8 +548,8 @@ void zen::fillBuffer(const std::set& keysToRead, //in zen::ScopeGuard guardWorker = zen::makeGuard([&]() { - std::for_each(worker.begin(), worker.end(), std::mem_fun_ref(&boost::thread::interrupt)); //interrupt all at once, then join - std::for_each(worker.begin(), worker.end(), std::mem_fun_ref(&boost::thread::join)); + std::for_each(worker.begin(), worker.end(), [](boost::thread& wt) { wt.interrupt(); }); //interrupt all at once, then join + std::for_each(worker.begin(), worker.end(), [](boost::thread& wt) { wt.join(); }); }); std::shared_ptr acb = std::make_shared(); diff --git a/lib/status_handler.h b/lib/status_handler.h index 390b4f0a..686c1f0e 100644 --- a/lib/status_handler.h +++ b/lib/status_handler.h @@ -7,7 +7,6 @@ #ifndef STATUSHANDLER_H_INCLUDED #define STATUSHANDLER_H_INCLUDED -#include #include #include @@ -45,21 +44,18 @@ struct ProcessCallback //note: this one must NOT throw in order to properly allow undoing setting of statistics! //it is in general paired with a call to requestUiRefresh() to compensate! - virtual void updateProcessedData(int objectsProcessed, zen::Int64 dataProcessed) = 0; //throw() + virtual void updateProcessedData(int objectsProcessed, zen::Int64 dataProcessed) = 0; //throw()!! //opportunity to abort must be implemented in a frequently executed method like requestUiRefresh() virtual void requestUiRefresh() = 0; //throw ? - //this method is triggered repeatedly by requestUiRefresh() and can be used to refresh the ui by dispatching pending events - virtual void forceUiRefresh() = 0; - //called periodically after data was processed: expected(!) to request GUI update - virtual void reportStatus(const wxString& text) = 0; //status info only, should not be logged! + virtual void reportStatus(const std::wstring& text) = 0; //status info only, should not be logged! //called periodically after data was processed: expected(!) to request GUI update - virtual void reportInfo(const wxString& text) = 0; + virtual void reportInfo(const std::wstring& text) = 0; - virtual void reportWarning(const wxString& warningMessage, bool& warningActive) = 0; + virtual void reportWarning(const std::wstring& warningMessage, bool& warningActive) = 0; //error handling: enum Response @@ -67,8 +63,8 @@ struct ProcessCallback IGNORE_ERROR = 10, RETRY }; - virtual Response reportError (const wxString& errorMessage) = 0; //recoverable error situation - virtual void reportFatalError(const wxString& errorMessage) = 0; //non-recoverable error situation + virtual Response reportError (const std::wstring& errorMessage) = 0; //recoverable error situation + virtual void reportFatalError(const std::wstring& errorMessage) = 0; //non-recoverable error situation }; @@ -86,6 +82,8 @@ class StatusHandler : public ProcessCallback, public AbortCallback public: StatusHandler() : abortRequested(false) {} + virtual void forceUiRefresh() = 0; + virtual void requestUiRefresh() { if (updateUiIsAllowed()) //test if specific time span between ui updates is over -- cgit