diff options
Diffstat (limited to 'lib')
-rw-r--r-- | lib/Batch.ico | bin | 134332 -> 116037 bytes | |||
-rw-r--r-- | lib/ShadowCopy/Shadow_Server2003.vcxproj | 7 | ||||
-rw-r--r-- | lib/ShadowCopy/Shadow_Windows7.vcxproj | 7 | ||||
-rw-r--r-- | lib/ShadowCopy/Shadow_XP.vcxproj | 7 | ||||
-rw-r--r-- | lib/Thumbnail/Thumbnail.vcxproj | 7 | ||||
-rw-r--r-- | lib/binary.cpp | 12 | ||||
-rw-r--r-- | lib/db_file.cpp | 6 | ||||
-rw-r--r-- | lib/dir_lock.cpp | 16 | ||||
-rw-r--r-- | lib/generate_logfile.h | 174 | ||||
-rw-r--r-- | lib/localization.cpp | 2 | ||||
-rw-r--r-- | lib/lock_holder.h | 67 | ||||
-rw-r--r-- | lib/parallel_scan.cpp | 2 | ||||
-rw-r--r-- | lib/process_xml.cpp | 12 | ||||
-rw-r--r-- | lib/process_xml.h | 2 | ||||
-rw-r--r-- | lib/resolve_path.cpp | 2 | ||||
-rw-r--r-- | lib/shadow.cpp | 3 | ||||
-rw-r--r-- | lib/status_handler.cpp | 2 |
17 files changed, 198 insertions, 130 deletions
diff --git a/lib/Batch.ico b/lib/Batch.ico Binary files differindex 14e2bb10..1856b1fb 100644 --- a/lib/Batch.ico +++ b/lib/Batch.ico diff --git a/lib/ShadowCopy/Shadow_Server2003.vcxproj b/lib/ShadowCopy/Shadow_Server2003.vcxproj index 3e70cd7a..50a3a830 100644 --- a/lib/ShadowCopy/Shadow_Server2003.vcxproj +++ b/lib/ShadowCopy/Shadow_Server2003.vcxproj @@ -100,6 +100,7 @@ <DebugInformationFormat>EditAndContinue</DebugInformationFormat> <DisableSpecificWarnings>4100;4996</DisableSpecificWarnings> <AdditionalIncludeDirectories>../..;C:\Program Files\C++\boost</AdditionalIncludeDirectories> + <SmallerTypeCheck>true</SmallerTypeCheck> </ClCompile> <Link> <OutputFile>$(OutDir)$(TargetName)$(TargetExt)</OutputFile> @@ -112,6 +113,7 @@ <ImportLibrary>$(IntDir)$(TargetName).lib</ImportLibrary> <TargetMachine>MachineX86</TargetMachine> <AdditionalLibraryDirectories>C:\Program Files\C++\Boost\stage\lib</AdditionalLibraryDirectories> + <AdditionalDependencies>%(AdditionalDependencies)</AdditionalDependencies> </Link> </ItemDefinitionGroup> <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'"> @@ -134,6 +136,7 @@ <DebugInformationFormat>ProgramDatabase</DebugInformationFormat> <DisableSpecificWarnings>4100;4996</DisableSpecificWarnings> <AdditionalIncludeDirectories>../..;C:\Program Files\C++\boost</AdditionalIncludeDirectories> + <SmallerTypeCheck>true</SmallerTypeCheck> </ClCompile> <Link> <OutputFile>$(OutDir)$(TargetName)$(TargetExt)</OutputFile> @@ -146,6 +149,7 @@ <ImportLibrary>$(IntDir)$(TargetName).lib</ImportLibrary> <TargetMachine>MachineX64</TargetMachine> <AdditionalLibraryDirectories>C:\Program Files\C++\Boost\stage_x64\lib</AdditionalLibraryDirectories> + <AdditionalDependencies>%(AdditionalDependencies)</AdditionalDependencies> </Link> </ItemDefinitionGroup> <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'"> @@ -180,6 +184,7 @@ <ImportLibrary>$(IntDir)$(TargetName).lib</ImportLibrary> <TargetMachine>MachineX86</TargetMachine> <AdditionalLibraryDirectories>C:\Program Files\C++\Boost\stage\lib</AdditionalLibraryDirectories> + <AdditionalDependencies>%(AdditionalDependencies)</AdditionalDependencies> </Link> </ItemDefinitionGroup> <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'"> @@ -217,9 +222,11 @@ <ImportLibrary>$(IntDir)$(TargetName).lib</ImportLibrary> <TargetMachine>MachineX64</TargetMachine> <AdditionalLibraryDirectories>C:\Program Files\C++\Boost\stage_x64\lib</AdditionalLibraryDirectories> + <AdditionalDependencies>%(AdditionalDependencies)</AdditionalDependencies> </Link> </ItemDefinitionGroup> <ItemGroup> + <ClCompile Include="..\..\zen\debug_memory_leaks.cpp" /> <ClCompile Include="dll_main.cpp"> <PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'"> </PrecompiledHeader> diff --git a/lib/ShadowCopy/Shadow_Windows7.vcxproj b/lib/ShadowCopy/Shadow_Windows7.vcxproj index 985936b4..aa32253b 100644 --- a/lib/ShadowCopy/Shadow_Windows7.vcxproj +++ b/lib/ShadowCopy/Shadow_Windows7.vcxproj @@ -100,6 +100,7 @@ <DebugInformationFormat>EditAndContinue</DebugInformationFormat> <DisableSpecificWarnings>4100;4996</DisableSpecificWarnings> <AdditionalIncludeDirectories>../..;C:\Program Files\C++\boost</AdditionalIncludeDirectories> + <SmallerTypeCheck>true</SmallerTypeCheck> </ClCompile> <Link> <OutputFile>$(OutDir)$(TargetName)$(TargetExt)</OutputFile> @@ -112,6 +113,7 @@ <ImportLibrary>$(IntDir)$(TargetName).lib</ImportLibrary> <TargetMachine>MachineX86</TargetMachine> <AdditionalLibraryDirectories>C:\Program Files\C++\Boost\stage\lib</AdditionalLibraryDirectories> + <AdditionalDependencies>%(AdditionalDependencies)</AdditionalDependencies> </Link> </ItemDefinitionGroup> <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'"> @@ -134,6 +136,7 @@ <DisableSpecificWarnings>4100;4996</DisableSpecificWarnings> <AdditionalIncludeDirectories>../..;C:\Program Files\C++\boost</AdditionalIncludeDirectories> <PreprocessorDefinitions>_DEBUG;_WINDOWS;_USRDLL;SHADOWDLL_EXPORTS;USE_SHADOW_WINDOWS7;%(PreprocessorDefinitions)</PreprocessorDefinitions> + <SmallerTypeCheck>true</SmallerTypeCheck> </ClCompile> <Link> <OutputFile>$(OutDir)$(TargetName)$(TargetExt)</OutputFile> @@ -146,6 +149,7 @@ <ImportLibrary>$(IntDir)$(TargetName).lib</ImportLibrary> <TargetMachine>MachineX64</TargetMachine> <AdditionalLibraryDirectories>C:\Program Files\C++\Boost\stage_x64\lib</AdditionalLibraryDirectories> + <AdditionalDependencies>%(AdditionalDependencies)</AdditionalDependencies> </Link> </ItemDefinitionGroup> <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'"> @@ -180,6 +184,7 @@ <ImportLibrary>$(IntDir)$(TargetName).lib</ImportLibrary> <TargetMachine>MachineX86</TargetMachine> <AdditionalLibraryDirectories>C:\Program Files\C++\Boost\stage\lib</AdditionalLibraryDirectories> + <AdditionalDependencies>%(AdditionalDependencies)</AdditionalDependencies> </Link> </ItemDefinitionGroup> <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'"> @@ -217,9 +222,11 @@ <ImportLibrary>$(IntDir)$(TargetName).lib</ImportLibrary> <TargetMachine>MachineX64</TargetMachine> <AdditionalLibraryDirectories>C:\Program Files\C++\Boost\stage_x64\lib</AdditionalLibraryDirectories> + <AdditionalDependencies>%(AdditionalDependencies)</AdditionalDependencies> </Link> </ItemDefinitionGroup> <ItemGroup> + <ClCompile Include="..\..\zen\debug_memory_leaks.cpp" /> <ClCompile Include="dll_main.cpp"> <PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'"> </PrecompiledHeader> diff --git a/lib/ShadowCopy/Shadow_XP.vcxproj b/lib/ShadowCopy/Shadow_XP.vcxproj index b49bff4c..70b792ec 100644 --- a/lib/ShadowCopy/Shadow_XP.vcxproj +++ b/lib/ShadowCopy/Shadow_XP.vcxproj @@ -100,6 +100,7 @@ <FavorSizeOrSpeed>Neither</FavorSizeOrSpeed> <DisableSpecificWarnings>4100;4996</DisableSpecificWarnings> <AdditionalIncludeDirectories>../..;C:\Program Files\C++\boost</AdditionalIncludeDirectories> + <SmallerTypeCheck>true</SmallerTypeCheck> </ClCompile> <Link> <OutputFile>$(OutDir)$(TargetName)$(TargetExt)</OutputFile> @@ -112,6 +113,7 @@ <ImportLibrary>$(IntDir)$(TargetName).lib</ImportLibrary> <TargetMachine>MachineX86</TargetMachine> <AdditionalLibraryDirectories>C:\Program Files\C++\Boost\stage\lib</AdditionalLibraryDirectories> + <AdditionalDependencies>%(AdditionalDependencies)</AdditionalDependencies> </Link> </ItemDefinitionGroup> <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'"> @@ -135,6 +137,7 @@ <FavorSizeOrSpeed>Neither</FavorSizeOrSpeed> <DisableSpecificWarnings>4100;4996</DisableSpecificWarnings> <AdditionalIncludeDirectories>../..;C:\Program Files\C++\boost</AdditionalIncludeDirectories> + <SmallerTypeCheck>true</SmallerTypeCheck> </ClCompile> <Link> <OutputFile>$(OutDir)$(TargetName)$(TargetExt)</OutputFile> @@ -147,6 +150,7 @@ <ImportLibrary>$(IntDir)$(TargetName).lib</ImportLibrary> <TargetMachine>MachineX64</TargetMachine> <AdditionalLibraryDirectories>C:\Program Files\C++\Boost\stage_x64\lib</AdditionalLibraryDirectories> + <AdditionalDependencies>%(AdditionalDependencies)</AdditionalDependencies> </Link> </ItemDefinitionGroup> <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'"> @@ -181,6 +185,7 @@ <ImportLibrary>$(IntDir)$(TargetName).lib</ImportLibrary> <TargetMachine>MachineX86</TargetMachine> <AdditionalLibraryDirectories>C:\Program Files\C++\Boost\stage\lib</AdditionalLibraryDirectories> + <AdditionalDependencies>%(AdditionalDependencies)</AdditionalDependencies> </Link> </ItemDefinitionGroup> <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'"> @@ -218,9 +223,11 @@ <ImportLibrary>$(IntDir)$(TargetName).lib</ImportLibrary> <TargetMachine>MachineX64</TargetMachine> <AdditionalLibraryDirectories>C:\Program Files\C++\Boost\stage_x64\lib</AdditionalLibraryDirectories> + <AdditionalDependencies>%(AdditionalDependencies)</AdditionalDependencies> </Link> </ItemDefinitionGroup> <ItemGroup> + <ClCompile Include="..\..\zen\debug_memory_leaks.cpp" /> <ClCompile Include="dll_main.cpp"> <PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'"> </PrecompiledHeader> diff --git a/lib/Thumbnail/Thumbnail.vcxproj b/lib/Thumbnail/Thumbnail.vcxproj index e3909ff8..3baa2d61 100644 --- a/lib/Thumbnail/Thumbnail.vcxproj +++ b/lib/Thumbnail/Thumbnail.vcxproj @@ -98,6 +98,7 @@ <DebugInformationFormat>EditAndContinue</DebugInformationFormat> <DisableSpecificWarnings>4100</DisableSpecificWarnings> <AdditionalIncludeDirectories>../..</AdditionalIncludeDirectories> + <SmallerTypeCheck>true</SmallerTypeCheck> </ClCompile> <Link> <OutputFile>$(OutDir)$(TargetName)$(TargetExt)</OutputFile> @@ -109,6 +110,7 @@ </ProfileGuidedDatabase> <ImportLibrary>$(IntDir)$(TargetName).lib</ImportLibrary> <TargetMachine>MachineX86</TargetMachine> + <AdditionalDependencies>%(AdditionalDependencies)</AdditionalDependencies> </Link> </ItemDefinitionGroup> <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'"> @@ -131,6 +133,7 @@ <DebugInformationFormat>ProgramDatabase</DebugInformationFormat> <DisableSpecificWarnings>4100</DisableSpecificWarnings> <AdditionalIncludeDirectories>../..</AdditionalIncludeDirectories> + <SmallerTypeCheck>true</SmallerTypeCheck> </ClCompile> <Link> <OutputFile>$(OutDir)$(TargetName)$(TargetExt)</OutputFile> @@ -142,6 +145,7 @@ </ProfileGuidedDatabase> <ImportLibrary>$(IntDir)$(TargetName).lib</ImportLibrary> <TargetMachine>MachineX64</TargetMachine> + <AdditionalDependencies>%(AdditionalDependencies)</AdditionalDependencies> </Link> </ItemDefinitionGroup> <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'"> @@ -175,6 +179,7 @@ </ProfileGuidedDatabase> <ImportLibrary>$(IntDir)$(TargetName).lib</ImportLibrary> <TargetMachine>MachineX86</TargetMachine> + <AdditionalDependencies>%(AdditionalDependencies)</AdditionalDependencies> </Link> </ItemDefinitionGroup> <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'"> @@ -211,9 +216,11 @@ </ProfileGuidedDatabase> <ImportLibrary>$(IntDir)$(TargetName).lib</ImportLibrary> <TargetMachine>MachineX64</TargetMachine> + <AdditionalDependencies>%(AdditionalDependencies)</AdditionalDependencies> </Link> </ItemDefinitionGroup> <ItemGroup> + <ClCompile Include="..\..\zen\debug_memory_leaks.cpp" /> <ClCompile Include="dll_main.cpp"> <PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'"> </PrecompiledHeader> diff --git a/lib/binary.cpp b/lib/binary.cpp index b9e3028d..10994cc9 100644 --- a/lib/binary.cpp +++ b/lib/binary.cpp @@ -44,7 +44,7 @@ public: private: static const size_t BUFFER_SIZE_MIN = 64 * 1024; - static const size_t BUFFER_SIZE_START = 512 * 1024; //512 kb seems to be a reasonable initial buffer size + static const size_t BUFFER_SIZE_START = 128 * 1024; //initial buffer size static const size_t BUFFER_SIZE_MAX = 16 * 1024 * 1024; /*Tests on Win7 x64 show that buffer size does NOT matter if files are located on different physical disks! @@ -99,23 +99,23 @@ bool zen::filesHaveSameContent(const Zstring& filename1, const Zstring& filename const size_t length1 = file1.read(&memory1[0], bufferSize); //returns actual number of bytes read; throw FileError() const size_t length2 = file2.read(&memory2[0], bufferSize); // - const TickVal stopTime = getTicks(); + const TickVal now = getTicks(); //-------- dynamically set buffer size to keep callback interval between 100 - 500ms --------------------- if (TICKS_PER_SEC > 0) { - const std::int64_t loopTime = (stopTime - startTime) * 1000 / TICKS_PER_SEC; //unit: [ms] + const std::int64_t loopTime = dist(startTime, now) * 1000 / TICKS_PER_SEC; //unit: [ms] if (loopTime < 100) { - if ((stopTime - lastDelayViolation) / TICKS_PER_SEC > 2) //avoid "flipping back": e.g. DVD-Roms read 32MB at once, so first read may be > 500 ms, but second one will be 0ms! + if (dist(lastDelayViolation, now) / TICKS_PER_SEC > 2) //avoid "flipping back": e.g. DVD-Roms read 32MB at once, so first read may be > 500 ms, but second one will be 0ms! { - lastDelayViolation = stopTime; + lastDelayViolation = now; bufferSize.inc(); } } else if (loopTime > 500) { - lastDelayViolation = stopTime; + lastDelayViolation = now; bufferSize.dec(); } } diff --git a/lib/db_file.cpp b/lib/db_file.cpp index 53830afe..f81ada21 100644 --- a/lib/db_file.cpp +++ b/lib/db_file.cpp @@ -636,12 +636,12 @@ std::shared_ptr<InSyncDir> zen::loadLastSynchronousState(const BaseDirMapping& b const Zstring fileNameLeft = getDBFilename<LEFT_SIDE >(baseMapping); const Zstring fileNameRight = getDBFilename<RIGHT_SIDE>(baseMapping); - if (!baseMapping.wasExisting<LEFT_SIDE >() || - !baseMapping.wasExisting<RIGHT_SIDE>()) + if (!baseMapping.isExisting<LEFT_SIDE >() || + !baseMapping.isExisting<RIGHT_SIDE>()) { //avoid race condition with directory existence check: reading sync.ffs_db may succeed although first dir check had failed => conflicts! //https://sourceforge.net/tracker/?func=detail&atid=1093080&aid=3531351&group_id=234430 - const Zstring filename = !baseMapping.wasExisting<LEFT_SIDE>() ? fileNameLeft : fileNameRight; + const Zstring filename = !baseMapping.isExisting<LEFT_SIDE>() ? fileNameLeft : fileNameRight; throw FileErrorDatabaseNotExisting(_("Initial synchronization:") + L" \n" + //it could be due to a to-be-created target directory not yet existing => FileErrorDatabaseNotExisting replaceCpy(_("Database file %x does not yet exist."), L"%x", fmtFileName(filename))); } diff --git a/lib/dir_lock.cpp b/lib/dir_lock.cpp index bbd97454..5041b37e 100644 --- a/lib/dir_lock.cpp +++ b/lib/dir_lock.cpp @@ -105,7 +105,7 @@ public: #elif defined FFS_LINUX const int fileHandle = ::open(lockfilename_.c_str(), O_WRONLY | O_APPEND); - if (fileHandle == -1) + if (fileHandle < 0) return; ZEN_ON_SCOPE_EXIT(::close(fileHandle)); @@ -418,20 +418,20 @@ void waitOnDirLock(const Zstring& lockfilename, DirLockCallback* callback) //thr while (true) { - const TickVal currentTime = getTicks(); + const TickVal now = getTicks(); const UInt64 fileSizeNew = ::getLockFileSize(lockfilename); //throw FileError, ErrorNotExisting - if (TICKS_PER_SEC <= 0 || !lastLifeSign.isValid() || !currentTime.isValid()) + if (TICKS_PER_SEC <= 0 || !lastLifeSign.isValid() || !now.isValid()) throw FileError(L"System Timer failed!"); //no i18n: "should" never throw ;) if (fileSizeNew != fileSizeOld) //received life sign from lock { fileSizeOld = fileSizeNew; - lastLifeSign = currentTime; + lastLifeSign = now; } if (lockOwnderDead || //no need to wait any longer... - (currentTime - lastLifeSign) / TICKS_PER_SEC > DETECT_ABANDONED_INTERVAL) + dist(lastLifeSign, now) / TICKS_PER_SEC > DETECT_ABANDONED_INTERVAL) { DirLock dummy(deleteAbandonedLockName(lockfilename), callback); //throw FileError @@ -458,11 +458,9 @@ void waitOnDirLock(const Zstring& lockfilename, DirLockCallback* callback) //thr if (callback) { //one signal missed: it's likely this is an abandoned lock => show countdown - if ((currentTime - lastLifeSign) / TICKS_PER_SEC > EMIT_LIFE_SIGN_INTERVAL) + if (dist(lastLifeSign, now) / TICKS_PER_SEC > EMIT_LIFE_SIGN_INTERVAL) { - int remainingSeconds = DETECT_ABANDONED_INTERVAL - (getTicks() - lastLifeSign) / TICKS_PER_SEC; - remainingSeconds = std::max(0, remainingSeconds); - + const int remainingSeconds = std::max<int>(0, DETECT_ABANDONED_INTERVAL - dist(lastLifeSign, getTicks()) / TICKS_PER_SEC); const std::wstring remSecMsg = replaceCpy(_P("1 sec", "%x sec", remainingSeconds), L"%x", numberTo<std::wstring>(remainingSeconds)); callback->reportInfo(infoMsg + L" " + remSecMsg); } diff --git a/lib/generate_logfile.h b/lib/generate_logfile.h index beb4f5d3..875d5b98 100644 --- a/lib/generate_logfile.h +++ b/lib/generate_logfile.h @@ -16,16 +16,24 @@ namespace zen { -Utf8String generateLogStream(const ErrorLog& log, - const std::wstring& jobName, //may be empty - const std::wstring& finalStatus, - int itemsSynced, Int64 dataSynced, - int itemsTotal, Int64 dataTotal, - long totalTime); //unit: [sec] - -void saveToLastSyncsLog(const Utf8String& logstream); //throw FileError +struct SummaryInfo +{ + std::wstring jobName; //may be empty + std::wstring finalStatus; + int itemsSynced; + Int64 dataSynced; + int itemsTotal; + Int64 dataTotal; + long totalTime; //unit: [sec] +}; +void saveLogToFile(const SummaryInfo& summary, //throw FileError + const ErrorLog& log, + FileOutput& fileOut); +void saveToLastSyncsLog(const SummaryInfo& summary, //throw FileError + const ErrorLog& log, + size_t maxBytesToWrite); @@ -34,114 +42,136 @@ void saveToLastSyncsLog(const Utf8String& logstream); //throw FileError //####################### implementation ####################### namespace { -Utf8String generateLogStream_impl(const ErrorLog& log, - const std::wstring& jobName, //may be empty - const std::wstring& finalStatus, - int itemsSynced, Int64 dataSynced, - int itemsTotal, Int64 dataTotal, - long totalTime) //unit: [sec] +std::wstring generateLogHeader(const SummaryInfo& s) { - assert(itemsSynced <= itemsTotal); - assert(dataSynced <= dataTotal); + assert(s.itemsSynced <= s.itemsTotal); + assert(s.dataSynced <= s.dataTotal); - Utf8String output; + std::wstring output; //write header std::wstring headerLine = formatTime<std::wstring>(FORMAT_DATE); - if (!jobName.empty()) - headerLine += L" - " + jobName; - headerLine += L": " + finalStatus; + if (!s.jobName.empty()) + headerLine += L" - " + s.jobName; + headerLine += L": " + s.finalStatus; //assemble results box std::vector<std::wstring> results; results.push_back(headerLine); results.push_back(L""); - const wchar_t tabSpace[] = L" "; + const wchar_t tabSpace[] = L" "; - std::wstring itemsProc = tabSpace + _("Items processed:") + L" " + toGuiString(itemsSynced); //show always, even if 0! - if (itemsSynced != 0 || dataSynced != 0) //[!] don't show 0 bytes processed if 0 items were processed - itemsProc += + L" (" + filesizeToShortString(dataSynced) + L")"; + std::wstring itemsProc = tabSpace + _("Items processed:") + L" " + toGuiString(s.itemsSynced); //show always, even if 0! + if (s.itemsSynced != 0 || s.dataSynced != 0) //[!] don't show 0 bytes processed if 0 items were processed + itemsProc += + L" (" + filesizeToShortString(s.dataSynced) + L")"; results.push_back(itemsProc); - if (itemsTotal != 0 || dataTotal != 0) //=: sync phase was reached and there were actual items to sync + if (s.itemsTotal != 0 || s.dataTotal != 0) //=: sync phase was reached and there were actual items to sync { - if (itemsSynced != itemsTotal || - dataSynced != dataTotal) - results.push_back(tabSpace + _("Items remaining:") + L" " + toGuiString(itemsTotal - itemsSynced) + L" (" + filesizeToShortString(dataTotal - dataSynced) + L")"); + if (s.itemsSynced != s.itemsTotal || + s.dataSynced != s.dataTotal) + results.push_back(tabSpace + _("Items remaining:") + L" " + toGuiString(s.itemsTotal - s.itemsSynced) + L" (" + filesizeToShortString(s.dataTotal - s.dataSynced) + L")"); } - results.push_back(tabSpace + _("Total time:") + L" " + copyStringTo<std::wstring>(wxTimeSpan::Seconds(totalTime).Format())); + results.push_back(tabSpace + _("Total time:") + L" " + copyStringTo<std::wstring>(wxTimeSpan::Seconds(s.totalTime).Format())); //calculate max width, this considers UTF-16 only, not true Unicode... size_t sepLineLen = 0; std::for_each(results.begin(), results.end(), [&](const std::wstring& str) { sepLineLen = std::max(sepLineLen, str.size()); }); - for (size_t i = 0; i < sepLineLen; ++i) output += '_'; //this considers UTF-16 only, not true Unicode!!! - output += "\n"; - - std::for_each(results.begin(), results.end(), [&](const std::wstring& str) { output += utfCvrtTo<Utf8String>(str); output += '\n'; }); + for (size_t i = 0; i < sepLineLen; ++i) output += L'_'; //this considers UTF-16 only, not true Unicode!!! + output += L'\n'; - for (size_t i = 0; i < sepLineLen; ++i) output += '_'; - output += "\n\n"; + std::for_each(results.begin(), results.end(), [&](const std::wstring& str) { output += str; output += L'\n'; }); - //write log items - const auto& entries = log.getEntries(); - for (auto iter = entries.begin(); iter != entries.end(); ++iter) - { - output += utfCvrtTo<Utf8String>(formatMessage(*iter)); - output += '\n'; - } + for (size_t i = 0; i < sepLineLen; ++i) output += L'_'; + output += L'\n'; - return replaceCpy(output, '\n', LINE_BREAK); //don't replace line break any earlier + return output; } } inline -Utf8String generateLogStream(const ErrorLog& log, - const std::wstring& jobName, //may be empty - const std::wstring& finalStatus, - int itemsSynced, Int64 dataSynced, - int itemsTotal, Int64 dataTotal, - long totalTime) //unit: [sec] +void saveLogToFile(const SummaryInfo& summary, //throw FileError + const ErrorLog& log, + FileOutput& fileOut) { - return generateLogStream_impl(log, jobName, finalStatus, itemsSynced, dataSynced, itemsTotal, dataTotal, totalTime); + Utf8String header = utfCvrtTo<Utf8String>(generateLogHeader(summary)); + replace(header, '\n', LINE_BREAK); //don't replace line break any earlier + header += LINE_BREAK; //make sure string is not empty! + + fileOut.write(&*header.begin(), header.size()); //throw FileError + + //write log items one after the other instead of creating one big string: memory allocation might fail; think 1 million entries! + for (auto iter = log.begin(); iter != log.end(); ++iter) + { + Utf8String msg = replaceCpy(utfCvrtTo<Utf8String>(formatMessage<std::wstring>(*iter)), '\n', LINE_BREAK); + msg += LINE_BREAK; //make sure string is not empty! + + fileOut.write(&*msg.begin(), msg.size()); //throw FileError + } } inline -void saveToLastSyncsLog(const Utf8String& logstream) //throw FileError +void saveToLastSyncsLog(const SummaryInfo& summary, //throw FileError + const ErrorLog& log, + size_t maxBytesToWrite) //log may be *huge*, e.g. 1 million items; LastSyncs.log *must not* create performance problems! + { const Zstring filename = getConfigDir() + Zstr("LastSyncs.log"); - Utf8String oldStream; - try - { - oldStream = loadBinStream<Utf8String>(filename); //throw FileError, ErrorNotExisting - } - catch (const ErrorNotExisting&) {} + Utf8String newStream = utfCvrtTo<Utf8String>(generateLogHeader(summary)); + replace(newStream, '\n', LINE_BREAK); //don't replace line break any earlier + newStream += LINE_BREAK; - Utf8String newStream = logstream; - if (!oldStream.empty()) + //write log items one after the other instead of creating one big string: memory allocation might fail; think 1 million entries! + for (auto iter = log.begin(); iter != log.end(); ++iter) { + newStream += replaceCpy(utfCvrtTo<Utf8String>(formatMessage<std::wstring>(*iter)), '\n', LINE_BREAK); newStream += LINE_BREAK; - newStream += LINE_BREAK; - newStream += oldStream; - } - //limit file size: 128 kB (but do not truncate new log) - const size_t newSize = std::min(newStream.size(), std::max<size_t>(logstream.size(), 128 * 1024)); + if (newStream.size() > maxBytesToWrite) + { + newStream += "[...]"; + newStream += LINE_BREAK; + break; + } + } - //do not cut in the middle of a row - auto iter = std::search(newStream.cbegin() + newSize, newStream.cend(), std::begin(LINE_BREAK), std::end(LINE_BREAK) - 1); - if (iter != newStream.cend()) + //fill up the rest of permitted space by appending old log + if (newStream.size() < maxBytesToWrite) { - newStream.resize(iter - newStream.cbegin()); - - newStream += LINE_BREAK; - newStream += "[...]"; - newStream += LINE_BREAK; + Utf8String oldStream; + try + { + oldStream = loadBinStream<Utf8String>(filename); //throw FileError, ErrorNotExisting + } + catch (const ErrorNotExisting&) {} + + if (!oldStream.empty()) + { + newStream += LINE_BREAK; + newStream += LINE_BREAK; + newStream += oldStream; //impliticly limited by "maxBytesToWrite"! + + //truncate size if required + if (newStream.size() > maxBytesToWrite) + { + //but do not cut in the middle of a row + auto iter = std::search(newStream.cbegin() + maxBytesToWrite, newStream.cend(), std::begin(LINE_BREAK), std::end(LINE_BREAK) - 1); + if (iter != newStream.cend()) + { + newStream.resize(iter - newStream.cbegin()); + newStream += LINE_BREAK; + + newStream += "[...]"; + newStream += LINE_BREAK; + } + } + } } saveBinStream(filename, newStream); //throw FileError diff --git a/lib/localization.cpp b/lib/localization.cpp index 64c8b0f3..5792b3d1 100644 --- a/lib/localization.cpp +++ b/lib/localization.cpp @@ -123,7 +123,7 @@ public: virtual HandleLink onSymlink(const Zchar* shortName, const Zstring& fullName, const SymlinkInfo& details) { return LINK_SKIP; } virtual std::shared_ptr<TraverseCallback> onDir(const Zchar* shortName, const Zstring& fullName) { return nullptr; } - virtual HandleError onError(const std::wstring& msg) { return ON_ERROR_IGNORE; } //errors are not really critical in this context + virtual HandleError onError(const std::wstring& msg) { assert(false); return ON_ERROR_IGNORE; } //errors are not really critical in this context private: std::vector<Zstring>& lngFiles_; diff --git a/lib/lock_holder.h b/lib/lock_holder.h index 6265747b..5ae2f8ae 100644 --- a/lib/lock_holder.h +++ b/lib/lock_holder.h @@ -3,6 +3,7 @@ #include <map> #include <zen/zstring.h> +#include <zen/stl_tools.h> #include "dir_lock.h" #include "status_handler.h" #include "dir_exist_async.h" @@ -11,43 +12,49 @@ namespace zen { const Zstring LOCK_FILE_ENDING = Zstr(".ffs_lock"); //intermediate locks created by DirLock use this extension, too! -//convenience class for creating and holding locks for a number of directories +//hold locks for a number of directories without blocking during lock creation class LockHolder { public: - LockHolder(bool allowUserInteraction) : allowUserInteraction_(allowUserInteraction) {} - - void addDir(const Zstring& dirnameFmt, ProcessCallback& procCallback) //resolved dirname ending with path separator + LockHolder(const std::vector<Zstring>& dirnamesFmt, //resolved dirname ending with path separator + ProcessCallback& procCallback, + bool allowUserInteraction) : allowUserInteraction_(allowUserInteraction) { - if (dirnameFmt.empty()) - return; + std::vector<Zstring> dirs = dirnamesFmt; + vector_remove_if(dirs, [](const Zstring& dir) { return dir.empty(); }); - if (!dirExistsUpdating(dirnameFmt, allowUserInteraction_, procCallback)) - return; + for (auto iter = dirs.begin(); iter != dirs.end(); ++iter) + { + const Zstring& dirnameFmt = *iter; - if (lockHolder.find(dirnameFmt) != lockHolder.end()) return; - assert(endsWith(dirnameFmt, FILE_NAME_SEPARATOR)); //this is really the contract, formatting does other things as well, e.g. macro substitution + if (!dirExistsUpdating(dirnameFmt, allowUserInteraction_, procCallback)) + continue; - class WaitOnLockHandler : public DirLockCallback - { - public: - WaitOnLockHandler(ProcessCallback& pc) : pc_(pc) {} - virtual void requestUiRefresh() { pc_.requestUiRefresh(); } //allowed to throw exceptions - virtual void reportInfo(const std::wstring& text) { pc_.reportStatus(text); } - private: - ProcessCallback& pc_; - } callback(procCallback); - - try - { - //lock file creation is synchronous and may block noticably for very slow devices (usb sticks, mapped cloud storages) - procCallback.forceUiRefresh(); //=> make sure the right folder name is shown on GUI during this time! - lockHolder.insert(std::make_pair(dirnameFmt, DirLock(dirnameFmt + Zstr("sync") + LOCK_FILE_ENDING, &callback))); - } - catch (const FileError& e) - { - bool dummy = false; //this warning shall not be shown but logged only - procCallback.reportWarning(e.toString(), dummy); //may throw! + if (lockHolder.find(dirnameFmt) != lockHolder.end()) + continue; + assert(endsWith(dirnameFmt, FILE_NAME_SEPARATOR)); //this is really the contract, formatting does other things as well, e.g. macro substitution + + class WaitOnLockHandler : public DirLockCallback + { + public: + WaitOnLockHandler(ProcessCallback& pc) : pc_(pc) {} + virtual void requestUiRefresh() { pc_.requestUiRefresh(); } //allowed to throw exceptions + virtual void reportInfo(const std::wstring& text) { pc_.reportStatus(text); } + private: + ProcessCallback& pc_; + } callback(procCallback); + + try + { + //lock file creation is synchronous and may block noticably for very slow devices (usb sticks, mapped cloud storages) + procCallback.forceUiRefresh(); //=> make sure the right folder name is shown on GUI during this time! + lockHolder.insert(std::make_pair(dirnameFmt, DirLock(dirnameFmt + Zstr("sync") + LOCK_FILE_ENDING, &callback))); + } + catch (const FileError& e) + { + bool dummy = false; //this warning shall not be shown but logged only + procCallback.reportWarning(e.toString(), dummy); //may throw! + } } } diff --git a/lib/parallel_scan.cpp b/lib/parallel_scan.cpp index b9d29699..a31e30ee 100644 --- a/lib/parallel_scan.cpp +++ b/lib/parallel_scan.cpp @@ -541,7 +541,7 @@ void zen::fillBuffer(const std::set<DirectoryKey>& keysToRead, //in 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) { - if (wt.joinable()) //this is a precondition of thread::join()!!! Latter will throw an exception if violated! + if (wt.joinable()) //= precondition of thread::join(), which throws an exception if violated! wt.join(); //in this context it is possible a thread is *not* joinable anymore due to the thread::timed_join() below! }); }); diff --git a/lib/process_xml.cpp b/lib/process_xml.cpp index 57ba69e6..aed9c35f 100644 --- a/lib/process_xml.cpp +++ b/lib/process_xml.cpp @@ -715,10 +715,10 @@ template <> inline void writeStruc(const ColumnAttributeRim& value, XmlElement& output) { XmlOut out(output); - out.attribute("Type", value.type_); - out.attribute("Visible", value.visible_); - out.attribute("Width", value.offset_); - out.attribute("Stretch", value.stretch_); + out.attribute("Type", value.type_); + out.attribute("Visible", value.visible_); + out.attribute("Width", value.offset_); + out.attribute("Stretch", value.stretch_); } @@ -943,6 +943,8 @@ void readConfig(const XmlIn& in, XmlGlobalSettings& config) //max. allowed file time deviation inShared["FileTimeTolerance"](config.fileTimeTolerance); + inShared["LastSyncsFileSizeMax"](config.lastSyncsLogFileSizeMax); + XmlIn inOpt = inShared["OptionalDialogs"]; inOpt["WarnUnresolvedConflicts" ](config.optDialogs.warningUnresolvedConflicts); inOpt["WarnNotEnoughDiskSpace" ](config.optDialogs.warningNotEnoughDiskSpace); @@ -1248,6 +1250,8 @@ void writeConfig(const XmlGlobalSettings& config, XmlOut& out) //max. allowed file time deviation outShared["FileTimeTolerance"](config.fileTimeTolerance); + outShared["LastSyncsFileSizeMax"](config.lastSyncsLogFileSizeMax); + XmlOut outOpt = outShared["OptionalDialogs"]; outOpt["WarnUnresolvedConflicts" ](config.optDialogs.warningUnresolvedConflicts); outOpt["WarnNotEnoughDiskSpace" ](config.optDialogs.warningNotEnoughDiskSpace); diff --git a/lib/process_xml.h b/lib/process_xml.h index d21f7ffc..8d1d4538 100644 --- a/lib/process_xml.h +++ b/lib/process_xml.h @@ -124,6 +124,7 @@ struct XmlGlobalSettings copyFilePermissions(false), runWithBackgroundPriority(false), fileTimeTolerance(2), //default 2s: FAT vs NTFS + lastSyncsLogFileSizeMax(100000), //maximum size for LastSyncs.log: use a human-readable number verifyFileCopy(false), transactionalFileCopy(true), createLockFile(true) {} @@ -135,6 +136,7 @@ struct XmlGlobalSettings bool runWithBackgroundPriority; size_t fileTimeTolerance; //max. allowed file time deviation + size_t lastSyncsLogFileSizeMax; bool verifyFileCopy; //verify copied files bool transactionalFileCopy; bool createLockFile; diff --git a/lib/resolve_path.cpp b/lib/resolve_path.cpp index 0b8e80b9..248e3507 100644 --- a/lib/resolve_path.cpp +++ b/lib/resolve_path.cpp @@ -300,7 +300,7 @@ public: devices_.insert(std::make_pair(shortName, fullName)); return nullptr; //DON'T traverse into subdirs } - virtual HandleError onError(const std::wstring& msg) { return ON_ERROR_IGNORE; } + virtual HandleError onError(const std::wstring& msg) { assert(false); return ON_ERROR_IGNORE; } private: DeviceList& devices_; diff --git a/lib/shadow.cpp b/lib/shadow.cpp index 5f2225e7..8ef86f30 100644 --- a/lib/shadow.cpp +++ b/lib/shadow.cpp @@ -35,7 +35,6 @@ bool runningWOW64() //test if process is running under WOW64 (reference http://m //############################################################################################################# - class ShadowCopy::ShadowVolume { public: @@ -84,8 +83,8 @@ private: Zstring shadowVolPf; ShadowHandle backupHandle; }; -//############################################################################################################# +//############################################################################################################# Zstring ShadowCopy::makeShadowCopy(const Zstring& inputFile) { diff --git a/lib/status_handler.cpp b/lib/status_handler.cpp index 3188ba0d..c24c6f50 100644 --- a/lib/status_handler.cpp +++ b/lib/status_handler.cpp @@ -29,7 +29,7 @@ TickVal lastExec = getTicks(); bool zen::updateUiIsAllowed() { const TickVal now = getTicks(); //0 on error - if (now - lastExec >= TICKS_UPDATE_INTERVAL) //perform ui updates not more often than necessary + if (dist(lastExec, now) >= TICKS_UPDATE_INTERVAL) //perform ui updates not more often than necessary { lastExec = now; return true; |