diff options
Diffstat (limited to 'lib')
51 files changed, 870 insertions, 329 deletions
diff --git a/lib/ShadowCopy/LockFile.cpp b/lib/ShadowCopy/LockFile.cpp index aac4c170..701b84ec 100644 --- a/lib/ShadowCopy/LockFile.cpp +++ b/lib/ShadowCopy/LockFile.cpp @@ -1,7 +1,7 @@ // ************************************************************************** // * 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) ZenJu (zhnmju123 AT gmx DOT de) - All Rights Reserved * +// * Copyright (C) ZenJu (zenju AT gmx DOT de) - All Rights Reserved * // ************************************************************************** diff --git a/lib/ShadowCopy/Shadow_Server2003.vcxproj b/lib/ShadowCopy/Shadow_Server2003.vcxproj index ad24d4c1..3e70cd7a 100644 --- a/lib/ShadowCopy/Shadow_Server2003.vcxproj +++ b/lib/ShadowCopy/Shadow_Server2003.vcxproj @@ -145,7 +145,7 @@ </ProfileGuidedDatabase> <ImportLibrary>$(IntDir)$(TargetName).lib</ImportLibrary> <TargetMachine>MachineX64</TargetMachine> - <AdditionalLibraryDirectories>C:\Program Files\C++\Boost\stage64\lib</AdditionalLibraryDirectories> + <AdditionalLibraryDirectories>C:\Program Files\C++\Boost\stage_x64\lib</AdditionalLibraryDirectories> </Link> </ItemDefinitionGroup> <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'"> @@ -216,7 +216,7 @@ </ProfileGuidedDatabase> <ImportLibrary>$(IntDir)$(TargetName).lib</ImportLibrary> <TargetMachine>MachineX64</TargetMachine> - <AdditionalLibraryDirectories>C:\Program Files\C++\Boost\stage64\lib</AdditionalLibraryDirectories> + <AdditionalLibraryDirectories>C:\Program Files\C++\Boost\stage_x64\lib</AdditionalLibraryDirectories> </Link> </ItemDefinitionGroup> <ItemGroup> diff --git a/lib/ShadowCopy/Shadow_Windows7.vcxproj b/lib/ShadowCopy/Shadow_Windows7.vcxproj index 5381372b..985936b4 100644 --- a/lib/ShadowCopy/Shadow_Windows7.vcxproj +++ b/lib/ShadowCopy/Shadow_Windows7.vcxproj @@ -145,7 +145,7 @@ </ProfileGuidedDatabase> <ImportLibrary>$(IntDir)$(TargetName).lib</ImportLibrary> <TargetMachine>MachineX64</TargetMachine> - <AdditionalLibraryDirectories>C:\Program Files\C++\Boost\stage64\lib</AdditionalLibraryDirectories> + <AdditionalLibraryDirectories>C:\Program Files\C++\Boost\stage_x64\lib</AdditionalLibraryDirectories> </Link> </ItemDefinitionGroup> <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'"> @@ -216,7 +216,7 @@ </ProfileGuidedDatabase> <ImportLibrary>$(IntDir)$(TargetName).lib</ImportLibrary> <TargetMachine>MachineX64</TargetMachine> - <AdditionalLibraryDirectories>C:\Program Files\C++\Boost\stage64\lib</AdditionalLibraryDirectories> + <AdditionalLibraryDirectories>C:\Program Files\C++\Boost\stage_x64\lib</AdditionalLibraryDirectories> </Link> </ItemDefinitionGroup> <ItemGroup> diff --git a/lib/ShadowCopy/Shadow_XP.vcxproj b/lib/ShadowCopy/Shadow_XP.vcxproj index fce942d5..b49bff4c 100644 --- a/lib/ShadowCopy/Shadow_XP.vcxproj +++ b/lib/ShadowCopy/Shadow_XP.vcxproj @@ -146,7 +146,7 @@ </ProfileGuidedDatabase> <ImportLibrary>$(IntDir)$(TargetName).lib</ImportLibrary> <TargetMachine>MachineX64</TargetMachine> - <AdditionalLibraryDirectories>C:\Program Files\C++\Boost\stage64\lib</AdditionalLibraryDirectories> + <AdditionalLibraryDirectories>C:\Program Files\C++\Boost\stage_x64\lib</AdditionalLibraryDirectories> </Link> </ItemDefinitionGroup> <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'"> @@ -217,7 +217,7 @@ </ProfileGuidedDatabase> <ImportLibrary>$(IntDir)$(TargetName).lib</ImportLibrary> <TargetMachine>MachineX64</TargetMachine> - <AdditionalLibraryDirectories>C:\Program Files\C++\Boost\stage64\lib</AdditionalLibraryDirectories> + <AdditionalLibraryDirectories>C:\Program Files\C++\Boost\stage_x64\lib</AdditionalLibraryDirectories> </Link> </ItemDefinitionGroup> <ItemGroup> diff --git a/lib/ShadowCopy/dll_main.cpp b/lib/ShadowCopy/dll_main.cpp index 46c65311..95d14910 100644 --- a/lib/ShadowCopy/dll_main.cpp +++ b/lib/ShadowCopy/dll_main.cpp @@ -1,7 +1,7 @@ // ************************************************************************** // * 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) ZenJu (zhnmju123 AT gmx DOT de) - All Rights Reserved * +// * Copyright (C) ZenJu (zenju AT gmx DOT de) - All Rights Reserved * // ************************************************************************** diff --git a/lib/ShadowCopy/shadow.cpp b/lib/ShadowCopy/shadow.cpp index c47ce983..3bc2df87 100644 --- a/lib/ShadowCopy/shadow.cpp +++ b/lib/ShadowCopy/shadow.cpp @@ -1,7 +1,7 @@ // ************************************************************************** // * 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) ZenJu (zhnmju123 AT gmx DOT de) - All Rights Reserved * +// * Copyright (C) ZenJu (zenju AT gmx DOT de) - All Rights Reserved * // ************************************************************************** #include "shadow.h" diff --git a/lib/ShadowCopy/shadow.h b/lib/ShadowCopy/shadow.h index 66d29300..8f35c728 100644 --- a/lib/ShadowCopy/shadow.h +++ b/lib/ShadowCopy/shadow.h @@ -1,7 +1,7 @@ // ************************************************************************** // * 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) ZenJu (zhnmju123 AT gmx DOT de) - All Rights Reserved * +// * Copyright (C) ZenJu (zenju AT gmx DOT de) - All Rights Reserved * // ************************************************************************** #ifndef SHADOWCOPY_H diff --git a/lib/Thumbnail/dll_main.cpp b/lib/Thumbnail/dll_main.cpp index 46c65311..95d14910 100644 --- a/lib/Thumbnail/dll_main.cpp +++ b/lib/Thumbnail/dll_main.cpp @@ -1,7 +1,7 @@ // ************************************************************************** // * 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) ZenJu (zhnmju123 AT gmx DOT de) - All Rights Reserved * +// * Copyright (C) ZenJu (zenju AT gmx DOT de) - All Rights Reserved * // ************************************************************************** diff --git a/lib/Thumbnail/thumbnail.cpp b/lib/Thumbnail/thumbnail.cpp index d35f15c3..50c4f2a8 100644 --- a/lib/Thumbnail/thumbnail.cpp +++ b/lib/Thumbnail/thumbnail.cpp @@ -1,7 +1,7 @@ // ************************************************************************** // * 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) ZenJu (zhnmju123 AT gmx DOT de) - All Rights Reserved * +// * Copyright (C) ZenJu (zenju AT gmx DOT de) - All Rights Reserved * // ************************************************************************** #include "thumbnail.h" diff --git a/lib/Thumbnail/thumbnail.h b/lib/Thumbnail/thumbnail.h index 6c3575b5..9328b4f0 100644 --- a/lib/Thumbnail/thumbnail.h +++ b/lib/Thumbnail/thumbnail.h @@ -1,7 +1,7 @@ // ************************************************************************** // * 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) ZenJu (zhnmju123 AT gmx DOT de) - All Rights Reserved * +// * Copyright (C) ZenJu (zenju AT gmx DOT de) - All Rights Reserved * // ************************************************************************** #ifndef TASKBAR_SEVEN_DLL_H diff --git a/lib/binary.cpp b/lib/binary.cpp index 2065e13e..ec22c60f 100644 --- a/lib/binary.cpp +++ b/lib/binary.cpp @@ -1,7 +1,7 @@ // ************************************************************************** // * 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) ZenJu (zhnmju123 AT gmx DOT de) - All Rights Reserved * +// * Copyright (C) ZenJu (zenju AT gmx DOT de) - All Rights Reserved * // ************************************************************************** #include "binary.h" diff --git a/lib/binary.h b/lib/binary.h index b419e9e2..2c985de5 100644 --- a/lib/binary.h +++ b/lib/binary.h @@ -1,7 +1,7 @@ // ************************************************************************** // * 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) ZenJu (zhnmju123 AT gmx DOT de) - All Rights Reserved * +// * Copyright (C) ZenJu (zenju AT gmx DOT de) - All Rights Reserved * // ************************************************************************** #ifndef BINARY_H_INCLUDED @@ -13,13 +13,10 @@ namespace zen { - -//callback functionality for status updates while comparing -class CompareCallback +struct CompareCallback { -public: virtual ~CompareCallback() {} - virtual void updateCompareStatus(zen::UInt64 totalBytes) = 0; + virtual void updateCompareStatus(UInt64 totalBytes) = 0; }; bool filesHaveSameContent(const Zstring& filename1, const Zstring& filename2, CompareCallback& callback); //throw FileError diff --git a/lib/db_file.cpp b/lib/db_file.cpp index 2c299236..3c61137b 100644 --- a/lib/db_file.cpp +++ b/lib/db_file.cpp @@ -1,7 +1,7 @@ // ************************************************************************** // * 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) ZenJu (zhnmju123 AT gmx DOT de) - All Rights Reserved * +// * Copyright (C) ZenJu (zenju AT gmx DOT de) - All Rights Reserved * // ************************************************************************** #include "db_file.h" @@ -218,10 +218,10 @@ private: { writeNumber<std:: int64_t>(output, to<std:: int64_t>(descr.lastWriteTimeRaw)); writeNumber<std::uint64_t>(output, to<std::uint64_t>(descr.fileSize)); - writeNumber<std::uint64_t>(output, descr.id.first ); //device id - writeNumber<std::uint64_t>(output, descr.id.second); //file id - assert_static(sizeof(descr.id.first ) <= sizeof(std::uint64_t)); - assert_static(sizeof(descr.id.second) <= sizeof(std::uint64_t)); + writeNumber<std::uint64_t>(output, descr.devId); + writeNumber<std::uint64_t>(output, descr.fileIdx); + assert_static(sizeof(descr.devId ) <= sizeof(std::uint64_t)); + assert_static(sizeof(descr.fileIdx) <= sizeof(std::uint64_t)); } static void write(BinStreamOut& output, const LinkDescriptor& descr) @@ -344,8 +344,8 @@ private: //attention: order of function argument evaluation is undefined! So do it one after the other... descr.lastWriteTimeRaw = readNumber<std::int64_t>(input); //throw UnexpectedEndOfStreamError descr.fileSize = readNumber<std::uint64_t>(input); - descr.id.first = static_cast<decltype(descr.id.first )>(readNumber<std::uint64_t>(input)); // - descr.id.second = static_cast<decltype(descr.id.second)>(readNumber<std::uint64_t>(input)); //silence "loss of precision" compiler warnings + descr.devId = static_cast<DeviceId >(readNumber<std::uint64_t>(input)); // + descr.fileIdx = static_cast<FileIndex>(readNumber<std::uint64_t>(input)); //silence "loss of precision" compiler warnings } static void read(BinStreamIn& input, LinkDescriptor& descr) diff --git a/lib/db_file.h b/lib/db_file.h index 4425f52c..469cd3fa 100644 --- a/lib/db_file.h +++ b/lib/db_file.h @@ -1,7 +1,7 @@ // ************************************************************************** // * 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) ZenJu (zhnmju123 AT gmx DOT de) - All Rights Reserved * +// * Copyright (C) ZenJu (zenju AT gmx DOT de) - All Rights Reserved * // ************************************************************************** #ifndef DBFILE_H_INCLUDED diff --git a/lib/dir_exist_async.h b/lib/dir_exist_async.h index 2ab98e94..7e18d210 100644 --- a/lib/dir_exist_async.h +++ b/lib/dir_exist_async.h @@ -1,7 +1,7 @@ // ************************************************************************** // * 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) ZenJu (zhnmju123 AT gmx DOT de) - All Rights Reserved * +// * Copyright (C) ZenJu (zenju AT gmx DOT de) - All Rights Reserved * // ************************************************************************** #ifndef DIR_EXIST_HEADER_08173281673432158067342132467183267 diff --git a/lib/dir_lock.cpp b/lib/dir_lock.cpp index e385c9a8..469af262 100644 --- a/lib/dir_lock.cpp +++ b/lib/dir_lock.cpp @@ -1,13 +1,11 @@ // ************************************************************************** // * 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) ZenJu (zhnmju123 AT gmx DOT de) - All Rights Reserved * +// * Copyright (C) ZenJu (zenju AT gmx DOT de) - All Rights Reserved * // ************************************************************************** #include "dir_lock.h" #include <utility> -//#include <wx/utils.h> #include <wx/log.h> -//#include <wx/msgdlg.h> #include <memory> #include <zen/last_error.h> #include <zen/thread.h> //includes <boost/thread.hpp> diff --git a/lib/dir_lock.h b/lib/dir_lock.h index 925d99d6..b1fc1a06 100644 --- a/lib/dir_lock.h +++ b/lib/dir_lock.h @@ -1,7 +1,7 @@ // ************************************************************************** // * 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) ZenJu (zhnmju123 AT gmx DOT de) - All Rights Reserved * +// * Copyright (C) ZenJu (zenju AT gmx DOT de) - All Rights Reserved * // ************************************************************************** #ifndef DIR_LOCK_H_INCLUDED #define DIR_LOCK_H_INCLUDED diff --git a/lib/error_log.h b/lib/error_log.h index 07a8b383..2ccb4d84 100644 --- a/lib/error_log.h +++ b/lib/error_log.h @@ -1,7 +1,7 @@ // ************************************************************************** // * 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) ZenJu (zhnmju123 AT gmx DOT de) - All Rights Reserved * +// * Copyright (C) ZenJu (zenju AT gmx DOT de) - All Rights Reserved * // ************************************************************************** #ifndef ERROR_LOG_89734181783491324134 @@ -34,7 +34,7 @@ void logError(const std::string& msg) //throw() const std::string logEntry = "[" + formatTime<std::string>(FORMAT_DATE) + " "+ formatTime<std::string>(FORMAT_TIME) + "] " + msg; try { - saveBinStream(getConfigDir() + Zstr("LastError.txt"), logEntry); //throw FileError + saveBinStream(getConfigDir() + Zstr("LastError.log"), logEntry); //throw FileError } catch (const FileError&) {} } diff --git a/lib/ffs_paths.h b/lib/ffs_paths.h index d7987195..1a67af5c 100644 --- a/lib/ffs_paths.h +++ b/lib/ffs_paths.h @@ -1,7 +1,7 @@ // ************************************************************************** // * 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) ZenJu (zhnmju123 AT gmx DOT de) - All Rights Reserved * +// * Copyright (C) ZenJu (zenju AT gmx DOT de) - All Rights Reserved * // ************************************************************************** #ifndef STANDARDPATHS_H_INCLUDED diff --git a/lib/generate_logfile.h b/lib/generate_logfile.h index b54b4893..d1537311 100644 --- a/lib/generate_logfile.h +++ b/lib/generate_logfile.h @@ -1,7 +1,7 @@ // ************************************************************************** // * 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) ZenJu (zhnmju123 AT gmx DOT de) - All Rights Reserved * +// * Copyright (C) ZenJu (zenju AT gmx DOT de) - All Rights Reserved * // ************************************************************************** #ifndef GEN_LOGFILE_H_93172643216748973216458732165415 @@ -41,41 +41,41 @@ Utf8String generateLogStream_impl(const ErrorLog& log, int itemsTotal, Int64 dataTotal, long totalTime) //unit: [sec] { + assert(itemsSynced <= itemsTotal); + assert(dataSynced <= dataTotal); + Utf8String output; //write header - std::wstring headerLine = _("Batch execution") + L" - " + formatTime<std::wstring>(FORMAT_DATE); + std::wstring headerLine = formatTime<std::wstring>(FORMAT_DATE); if (!jobName.empty()) headerLine += L" - " + jobName; - - //output += utfCvrtTo<MemoryStream>(headerLine); - //output += '\n'; - - //for (size_t i = 0; i < headerLine.size(); ++i) //well, this considers UTF-16 only, not true Unicode... - // output += '='; - //output += '\n'; + headerLine += L": " + finalStatus; //assemble results box std::vector<std::wstring> results; results.push_back(headerLine); results.push_back(L""); - results.push_back(finalStatus); - results.push_back(L""); + + std::wstring itemsProc = L" " + _("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")"; + results.push_back(itemsProc); + if (itemsTotal != 0 || dataTotal != 0) //=: sync phase was reached and there were actual items to sync { - results.push_back(L" " + _("Items processed:") + L" " + toGuiString(itemsSynced) + L" (" + filesizeToShortString(dataSynced) + L")"); - if (itemsSynced != itemsTotal || dataSynced != dataTotal) results.push_back(L" " + _("Items remaining:") + L" " + toGuiString(itemsTotal - itemsSynced) + L" (" + filesizeToShortString(dataTotal - dataSynced) + L")"); } + results.push_back(L" " + _("Total time:") + L" " + copyStringTo<std::wstring>(wxTimeSpan::Seconds(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 += '_'; + 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'; }); diff --git a/lib/hard_filter.cpp b/lib/hard_filter.cpp index d66fc665..8fe0f7f4 100644 --- a/lib/hard_filter.cpp +++ b/lib/hard_filter.cpp @@ -1,7 +1,7 @@ // ************************************************************************** // * 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) ZenJu (zhnmju123 AT gmx DOT de) - All Rights Reserved * +// * Copyright (C) ZenJu (zenju AT gmx DOT de) - All Rights Reserved * // ************************************************************************** #include "hard_filter.h" @@ -79,7 +79,7 @@ void addFilterEntry(const Zstring& filtername, std::vector<Zstring>& fileFilter, filterFormatted = afterFirst(filterFormatted, FILE_NAME_SEPARATOR); //leading separator is optional! //some syntactic sugar: - if (filterFormatted == asteriskSepAsterisk) // *\* := match everything except files directly in base directory + if (filterFormatted == asteriskSepAsterisk) // *\* := match everything except files directly in base directory { fileFilter. push_back(filterFormatted); directoryFilter.push_back(asterisk); diff --git a/lib/hard_filter.h b/lib/hard_filter.h index 723c7bdf..57132e7f 100644 --- a/lib/hard_filter.h +++ b/lib/hard_filter.h @@ -1,7 +1,7 @@ // ************************************************************************** // * 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) ZenJu (zhnmju123 AT gmx DOT de) - All Rights Reserved * +// * Copyright (C) ZenJu (zenju AT gmx DOT de) - All Rights Reserved * // ************************************************************************** #ifndef FFS_FILTER_H_INCLUDED diff --git a/lib/help_provider.h b/lib/help_provider.h index 3b7443cb..d35e04c2 100644 --- a/lib/help_provider.h +++ b/lib/help_provider.h @@ -1,7 +1,7 @@ // ************************************************************************** // * 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) ZenJu (zhnmju123 AT gmx DOT de) - All Rights Reserved * +// * Copyright (C) ZenJu (zenju AT gmx DOT de) - All Rights Reserved * // ************************************************************************** #ifndef HELPPROVIDER_H_INCLUDED diff --git a/lib/icon_buffer.cpp b/lib/icon_buffer.cpp index 2dc6f389..dd449229 100644 --- a/lib/icon_buffer.cpp +++ b/lib/icon_buffer.cpp @@ -1,7 +1,7 @@ // ************************************************************************** // * 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) ZenJu (zhnmju123 AT gmx DOT de) - All Rights Reserved * +// * Copyright (C) ZenJu (zenju AT gmx DOT de) - All Rights Reserved * // ************************************************************************** #include "icon_buffer.h" diff --git a/lib/icon_buffer.h b/lib/icon_buffer.h index f3a358ef..7bbf3432 100644 --- a/lib/icon_buffer.h +++ b/lib/icon_buffer.h @@ -1,7 +1,7 @@ // ************************************************************************** // * 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) ZenJu (zhnmju123 AT gmx DOT de) - All Rights Reserved * +// * Copyright (C) ZenJu (zenju AT gmx DOT de) - All Rights Reserved * // ************************************************************************** #ifndef ICONBUFFER_H_INCLUDED diff --git a/lib/localization.cpp b/lib/localization.cpp index 16dcac9a..83bc60d2 100644 --- a/lib/localization.cpp +++ b/lib/localization.cpp @@ -1,7 +1,7 @@ // ************************************************************************** // * 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) ZenJu (zhnmju123 AT gmx DOT de) - All Rights Reserved * +// * Copyright (C) ZenJu (zenju AT gmx DOT de) - All Rights Reserved * // ************************************************************************** #include "localization.h" @@ -127,7 +127,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& errorText) { return ON_ERROR_IGNORE; } //errors are not really critical in this context + virtual HandleError onError(const std::wstring& msg) { return ON_ERROR_IGNORE; } //errors are not really critical in this context private: std::vector<Zstring>& lngFiles_; diff --git a/lib/localization.h b/lib/localization.h index 7c30ab74..a4430467 100644 --- a/lib/localization.h +++ b/lib/localization.h @@ -1,7 +1,7 @@ // ************************************************************************** // * 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) ZenJu (zhnmju123 AT gmx DOT de) - All Rights Reserved * +// * Copyright (C) ZenJu (zenju AT gmx DOT de) - All Rights Reserved * // ************************************************************************** #ifndef MISC_H_INCLUDED diff --git a/lib/norm_filter.h b/lib/norm_filter.h index dc73bc6b..aeefa8a1 100644 --- a/lib/norm_filter.h +++ b/lib/norm_filter.h @@ -1,7 +1,7 @@ // ************************************************************************** // * 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) ZenJu (zhnmju123 AT gmx DOT de) - All Rights Reserved * +// * Copyright (C) ZenJu (zenju AT gmx DOT de) - All Rights Reserved * // ************************************************************************** #ifndef NORM_FILTER_H_INCLUDED diff --git a/lib/parallel_scan.cpp b/lib/parallel_scan.cpp index f49fdc3e..6e7a6368 100644 --- a/lib/parallel_scan.cpp +++ b/lib/parallel_scan.cpp @@ -1,7 +1,7 @@ // ************************************************************************** // * 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) ZenJu (zhnmju123 AT gmx DOT de) - All Rights Reserved * +// * Copyright (C) ZenJu (zenju AT gmx DOT de) - All Rights Reserved * // ************************************************************************** #include "parallel_scan.h" @@ -330,7 +330,7 @@ public: onDir (const Zchar* shortName, const Zstring& fullName); virtual void onFile (const Zchar* shortName, const Zstring& fullName, const FileInfo& details); virtual HandleLink onSymlink(const Zchar* shortName, const Zstring& fullName, const SymlinkInfo& details); - virtual HandleError onError (const std::wstring& errorText); + virtual HandleError onError (const std::wstring& msg); private: TraverserShared& cfg; @@ -437,9 +437,9 @@ std::shared_ptr<TraverseCallback> DirCallback::onDir(const Zchar* shortName, con } -DirCallback::HandleError DirCallback::onError(const std::wstring& errorText) +DirCallback::HandleError DirCallback::onError(const std::wstring& msg) { - switch (cfg.acb_.reportError(errorText)) + switch (cfg.acb_.reportError(msg)) { case FillBufferCallback::ON_ERROR_IGNORE: cfg.failedReads_.insert(relNameParentPf_); diff --git a/lib/parallel_scan.h b/lib/parallel_scan.h index 0ce0114d..41712a55 100644 --- a/lib/parallel_scan.h +++ b/lib/parallel_scan.h @@ -1,7 +1,7 @@ // ************************************************************************** // * 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) ZenJu (zhnmju123 AT gmx DOT de) - All Rights Reserved * +// * Copyright (C) ZenJu (zenju AT gmx DOT de) - All Rights Reserved * // ************************************************************************** #ifndef PARALLEL_SCAN_H_INCLUDED @@ -45,7 +45,7 @@ bool operator<(const DirectoryKey& lhs, const DirectoryKey& rhs) struct DirectoryValue { DirContainer dirCont; - std::set<Zstring> failedReads; //relative postfixed names of directories that could not be read (empty string for root), e.g. access denied, or temporal network drop + std::set<Zstring> failedReads; //relative postfixed names of directories that could not be read completely (empty string for root), e.g. access denied, or temporal network drop }; @@ -59,8 +59,8 @@ public: ON_ERROR_RETRY, ON_ERROR_IGNORE }; - virtual HandleError reportError (const std::wstring& errorText) = 0; //may throw! - virtual void reportStatus(const std::wstring& statusMsg, int itemsTotal) = 0; // + virtual HandleError reportError (const std::wstring& msg) = 0; //may throw! + virtual void reportStatus(const std::wstring& msg, int itemsTotal) = 0; // }; //attention: ensure directory filtering is applied later to exclude filtered directories which have been kept as parent folders diff --git a/lib/parse_lng.h b/lib/parse_lng.h index 6a0b9dc5..3cbadf65 100644 --- a/lib/parse_lng.h +++ b/lib/parse_lng.h @@ -1,7 +1,7 @@ // ************************************************************************** // * 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) ZenJu (zhnmju123 AT gmx DOT de) - All Rights Reserved * +// * Copyright (C) ZenJu (zenju AT gmx DOT de) - All Rights Reserved * // ************************************************************************** #ifndef PARSE_LNG_HEADER_INCLUDED diff --git a/lib/parse_plural.h b/lib/parse_plural.h index 141266b6..d3473821 100644 --- a/lib/parse_plural.h +++ b/lib/parse_plural.h @@ -1,7 +1,7 @@ // ************************************************************************** // * 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) ZenJu (zhnmju123 AT gmx DOT de) - All Rights Reserved * +// * Copyright (C) ZenJu (zenju AT gmx DOT de) - All Rights Reserved * // ************************************************************************** #ifndef PARSE_PLURAL_H_INCLUDED diff --git a/lib/perf_check.cpp b/lib/perf_check.cpp index f01af061..f8d80191 100644 --- a/lib/perf_check.cpp +++ b/lib/perf_check.cpp @@ -1,7 +1,7 @@ // ************************************************************************** // * 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) ZenJu (zhnmju123 AT gmx DOT de) - All Rights Reserved * +// * Copyright (C) ZenJu (zenju AT gmx DOT de) - All Rights Reserved * // ************************************************************************** #include "perf_check.h" @@ -75,8 +75,8 @@ wxString PerfCheck::getRemainingTime(double dataRemaining) const if (!numeric::isNull(dataDelta)) //sign(dataRemaining) != sign(dataDelta) usually an error, so show it! { - int remTimeSec = dataRemaining * timeDelta / (1000.0 * dataDelta); - return zen::remainingTimeToShortString(remTimeSec); + const double remTimeSec = dataRemaining * timeDelta / (1000.0 * dataDelta); + return remainingTimeToShortString(remTimeSec); } } return L"-"; //fallback @@ -100,7 +100,7 @@ wxString PerfCheck::getBytesPerSecond() const if (!numeric::isNull(timeDelta)) if (dataDelta > 0) //may be negative if user cancels copying - return zen::filesizeToShortString(zen::Int64(dataDelta * 1000 / timeDelta)) + _("/sec"); + return filesizeToShortString(zen::Int64(dataDelta * 1000 / timeDelta)) + _("/sec"); } return L"-"; //fallback } diff --git a/lib/perf_check.h b/lib/perf_check.h index b0d4db89..d16c35f9 100644 --- a/lib/perf_check.h +++ b/lib/perf_check.h @@ -1,7 +1,7 @@ // ************************************************************************** // * 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) ZenJu (zhnmju123 AT gmx DOT de) - All Rights Reserved * +// * Copyright (C) ZenJu (zenju AT gmx DOT de) - All Rights Reserved * // ************************************************************************** #ifndef STATISTICS_H_INCLUDED @@ -34,7 +34,7 @@ private: int objCount_; double data_; //unit: [bytes] }; - std::multimap<long, Record> samples; ////time, unit: [ms] + std::multimap<long, Record> samples; //time, unit: [ms] }; #endif // STATISTICS_H_INCLUDED diff --git a/lib/process_xml.cpp b/lib/process_xml.cpp index f5a6a4d1..0b53a0f5 100644 --- a/lib/process_xml.cpp +++ b/lib/process_xml.cpp @@ -1,7 +1,7 @@ // ************************************************************************** // * 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) ZenJu (zhnmju123 AT gmx DOT de) - All Rights Reserved * +// * Copyright (C) ZenJu (zenju AT gmx DOT de) - All Rights Reserved * // ************************************************************************** #include "process_xml.h" @@ -114,23 +114,7 @@ xmlAccess::XmlGuiConfig xmlAccess::convertBatchToGui(const xmlAccess::XmlBatchCo xmlAccess::XmlBatchConfig xmlAccess::convertGuiToBatch(const xmlAccess::XmlGuiConfig& guiCfg, const Zstring& referenceFile) { - //try to take over batch-specific settings from reference - if (!referenceFile.empty() && getXmlType(referenceFile) == XML_TYPE_BATCH) - try - { - XmlBatchConfig output; - - std::vector<Zstring> filenames; - filenames.push_back(referenceFile); - convertConfig(filenames, output); //throw xmlAccess::FfsXmlError - - output.mainCfg = guiCfg.mainCfg; - return output; - } - catch (xmlAccess::FfsXmlError&) {} - XmlBatchConfig output; //use default batch-settings - output.mainCfg = guiCfg.mainCfg; switch (guiCfg.handleError) { @@ -142,6 +126,17 @@ xmlAccess::XmlBatchConfig xmlAccess::convertGuiToBatch(const xmlAccess::XmlGuiCo break; } + //try to take over batch-specific settings from reference + if (!referenceFile.empty() && getXmlType(referenceFile) == XML_TYPE_BATCH) + try + { + std::vector<Zstring> filenames; + filenames.push_back(referenceFile); + convertConfig(filenames, output); //throw xmlAccess::FfsXmlError + } + catch (xmlAccess::FfsXmlError&) {} + + output.mainCfg = guiCfg.mainCfg; return output; } @@ -428,13 +423,13 @@ void writeText(const DeletionPolicy& value, std::string& output) switch (value) { case DELETE_PERMANENTLY: - output = "DeletePermanently"; + output = "Permanent"; break; - case MOVE_TO_RECYCLE_BIN: - output = "MoveToRecycleBin"; + case DELETE_TO_RECYCLER: + output = "RecycleBin"; break; - case MOVE_TO_CUSTOM_DIRECTORY: - output = "MoveToCustomDirectory"; + case DELETE_TO_VERSIONING: + output = "Versioning"; break; } } @@ -444,14 +439,24 @@ bool readText(const std::string& input, DeletionPolicy& value) { std::string tmp = input; zen::trim(tmp); - if (tmp == "DeletePermanently") + //------------------ + warn_static("remove after migration?") + if (tmp == "DeletePermanently")//obsolete name value = DELETE_PERMANENTLY; - else if (tmp == "MoveToRecycleBin") - value = MOVE_TO_RECYCLE_BIN; - else if (tmp == "MoveToCustomDirectory") - value = MOVE_TO_CUSTOM_DIRECTORY; + else if (tmp == "MoveToRecycleBin")//obsolete name + value = DELETE_TO_RECYCLER; + else if (tmp == "MoveToCustomDirectory")//obsolete name + value = DELETE_TO_VERSIONING; else - return false; + //------------------ + if (tmp == "Permanent") + value = DELETE_PERMANENTLY; + else if (tmp == "RecycleBin") + value = DELETE_TO_RECYCLER; + else if (tmp == "Versioning") + value = DELETE_TO_VERSIONING; + else + return false; return true; } @@ -501,9 +506,6 @@ void writeText(const UnitTime& value, std::string& output) case UTIME_TODAY: output = "Today"; break; - //case UTIME_THIS_WEEK: - // output = "Week"; - // break; case UTIME_THIS_MONTH: output = "Month"; break; @@ -525,8 +527,6 @@ bool readText(const std::string& input, UnitTime& value) value = UTIME_NONE; else if (tmp == "Today") value = UTIME_TODAY; - //else if (tmp == "Week") - // value = UTIME_THIS_WEEK; else if (tmp == "Month") value = UTIME_THIS_MONTH; else if (tmp == "Year") @@ -772,8 +772,19 @@ void readConfig(const XmlIn& in, SyncConfig& syncCfg) { readConfig(in, syncCfg.directionCfg); - in["DeletionPolicy" ](syncCfg.handleDeletion); - in["CustomDeletionFolder"](syncCfg.customDeletionDirectory); + in["DeletionPolicy"](syncCfg.handleDeletion); + + warn_static("remove after migration?") + if (in["CustomDeletionFolder"]) + { + in["CustomDeletionFolder"](syncCfg.versioningDirectory);//obsolete name + syncCfg.versionCountLimit = 0; //new parameter + } + else + { + in["VersioningFolder"](syncCfg.versioningDirectory); + in["VersioningFolder"].attribute("Limit", syncCfg.versionCountLimit); + } } @@ -782,14 +793,21 @@ void readConfig(const XmlIn& in, FilterConfig& filter) in["Include"](filter.includeFilter); in["Exclude"](filter.excludeFilter); - in["TimeSpan" ](filter.timeSpan); - in["UnitTimeSpan"](filter.unitTimeSpan); + in["TimeSpan"](filter.timeSpan); + warn_static("remove after migration?") + if (in["UnitTimeSpan"]) in["UnitTimeSpan"](filter.unitTimeSpan);//obsolete name + else + in["TimeSpan"].attribute("Type", filter.unitTimeSpan); - in["SizeMin" ](filter.sizeMin); - in["UnitSizeMin"](filter.unitSizeMin); + in["SizeMin"](filter.sizeMin); + if (in["UnitSizeMin"]) in["UnitSizeMin"](filter.unitSizeMin);//obsolete name + else + in["SizeMin"].attribute("Unit", filter.unitSizeMin); - in["SizeMax" ](filter.sizeMax); - in["UnitSizeMax"](filter.unitSizeMax); + in["SizeMax"](filter.sizeMax); + if (in["UnitSizeMax"]) in["UnitSizeMax"](filter.unitSizeMax);//obsolete name + else + in["SizeMax"].attribute("Unit", filter.unitSizeMax); } @@ -859,7 +877,10 @@ void readConfig(const XmlIn& in, MainConfiguration& mainCfg) mainCfg.additionalPairs.push_back(newPair); //set additional folder pairs } - inMain["ExecuteWhenFinished"](mainCfg.onCompletion); + warn_static("remove after migration?") + if (inMain["ExecuteWhenFinished"]) inMain["ExecuteWhenFinished"](mainCfg.onCompletion); //obsolete name + else + inMain["OnCompletion"](mainCfg.onCompletion); } @@ -870,7 +891,15 @@ void readConfig(const XmlIn& in, xmlAccess::XmlGuiConfig& config) //read GUI specific config data XmlIn inGuiCfg = in["GuiConfig"]; - inGuiCfg["HideFiltered" ](config.hideFilteredElements); + warn_static("remove after migration?") + if (inGuiCfg["HideFiltered" ]) //obsolete name + { + inGuiCfg["HideFiltered" ](config.showFilteredElements); + config.showFilteredElements = !config.showFilteredElements; + } + else + inGuiCfg["ShowFiltered"](config.showFilteredElements); + inGuiCfg["HandleError" ](config.handleError); inGuiCfg["SyncPreviewActive"](config.showSyncAction); } @@ -883,10 +912,17 @@ void readConfig(const XmlIn& in, xmlAccess::XmlBatchConfig& config) //read GUI specific config data XmlIn inBatchCfg = in["BatchConfig"]; - inBatchCfg["ShowProgress" ](config.showProgress); - inBatchCfg["LogfileDirectory"](config.logFileDirectory); - inBatchCfg["LogfileCountMax" ](config.logFileCountMax); inBatchCfg["HandleError" ](config.handleError); + inBatchCfg["ShowProgress" ](config.showProgress); + + warn_static("remove after migration?") + if (inBatchCfg["LogfileDirectory"]) inBatchCfg["LogfileDirectory"](config.logFileDirectory); //obsolete name + else + inBatchCfg["LogfileFolder"](config.logFileDirectory); + + if (inBatchCfg["LogfileCountMax" ]) inBatchCfg["LogfileCountMax"](config.logfilesCountLimit); //obsolete name + else + inBatchCfg["LogfileFolder"].attribute("Limit", config.logfilesCountLimit); } @@ -960,6 +996,15 @@ void readConfig(const XmlIn& in, XmlGlobalSettings& config) inWnd["Layout"](config.gui.guiPerspectiveLast); + //load config file history + warn_static("remove after migration?") + if (inGui["LastConfigActive"]) inGui["LastConfigActive"](config.gui.lastUsedConfigFiles);//obsolete name + else + inGui["LastUsedConfig"](config.gui.lastUsedConfigFiles); + + inGui["ConfigHistory"](config.gui.cfgFileHistory); + inGui["ConfigHistory"].attribute("MaxSize", config.gui.cfgFileHistMax); + inGui["FolderHistoryLeft" ](config.gui.folderHistoryLeft); inGui["FolderHistoryRight"](config.gui.folderHistoryRight); inGui["FolderHistoryLeft"].attribute("MaxSize", config.gui.folderHistMax); @@ -970,9 +1015,17 @@ void readConfig(const XmlIn& in, XmlGlobalSettings& config) //external applications inGui["ExternalApplications"](config.gui.externelApplications); - //load config file history - inGui["LastConfigActive"](config.gui.lastUsedConfigFiles); - inGui["ConfigHistory"](config.gui.cfgFileHistory); + + warn_static("remove after migration?") + //convert new internal macro naming convention: %name -> %item_path%; %dir -> %item_folder% + for (auto iter = config.gui.externelApplications.begin(); iter != config.gui.externelApplications.end(); ++iter) + { + replace(iter->second, L"%nameCo", L"%item2_path%"); //unambiguous "Co" names first + replace(iter->second, L"%dirCo" , L"%item2_folder%"); + replace(iter->second, L"%name" , L"%item_path%"); + replace(iter->second, L"%dir" , L"%item_folder%"); + } + //last update check inGui["LastUpdateCheck"](config.gui.lastUpdateCheck); @@ -1047,8 +1100,9 @@ void writeConfig(const SyncConfig& syncCfg, XmlOut& out) { writeConfig(syncCfg.directionCfg, out); - out["DeletionPolicy" ](syncCfg.handleDeletion); - out["CustomDeletionFolder"](syncCfg.customDeletionDirectory); + out["DeletionPolicy" ](syncCfg.handleDeletion); + out["VersioningFolder"](syncCfg.versioningDirectory); + out["VersioningFolder"].attribute("Limit", syncCfg.versionCountLimit); } @@ -1057,14 +1111,14 @@ void writeConfig(const FilterConfig& filter, XmlOut& out) out["Include"](filter.includeFilter); out["Exclude"](filter.excludeFilter); - out["TimeSpan" ](filter.timeSpan); - out["UnitTimeSpan"](filter.unitTimeSpan); + out["TimeSpan"](filter.timeSpan); + out["TimeSpan"].attribute("Type", filter.unitTimeSpan); - out["SizeMin" ](filter.sizeMin); - out["UnitSizeMin"](filter.unitSizeMin); + out["SizeMin"](filter.sizeMin); + out["SizeMin"].attribute("Unit", filter.unitSizeMin); - out["SizeMax" ](filter.sizeMax); - out["UnitSizeMax"](filter.unitSizeMax); + out["SizeMax"](filter.sizeMax); + out["SizeMax"].attribute("Unit", filter.unitSizeMax); } @@ -1131,7 +1185,7 @@ void writeConfig(const MainConfiguration& mainCfg, XmlOut& out) std::for_each(mainCfg.additionalPairs.begin(), mainCfg.additionalPairs.end(), [&](const FolderPairEnh& fp) { writeConfigFolderPair(fp, outFp); }); - outMain["ExecuteWhenFinished"](mainCfg.onCompletion); + outMain["OnCompletion"](mainCfg.onCompletion); } @@ -1142,7 +1196,7 @@ void writeConfig(const XmlGuiConfig& config, XmlOut& out) //write GUI specific config data XmlOut outGuiCfg = out["GuiConfig"]; - outGuiCfg["HideFiltered" ](config.hideFilteredElements); + outGuiCfg["ShowFiltered" ](config.showFilteredElements); outGuiCfg["HandleError" ](config.handleError); outGuiCfg["SyncPreviewActive"](config.showSyncAction); } @@ -1155,10 +1209,10 @@ void writeConfig(const XmlBatchConfig& config, XmlOut& out) //write GUI specific config data XmlOut outBatchCfg = out["BatchConfig"]; - outBatchCfg["ShowProgress" ](config.showProgress); - outBatchCfg["LogfileDirectory"](config.logFileDirectory); - outBatchCfg["LogfileCountMax" ](config.logFileCountMax); - outBatchCfg["HandleError" ](config.handleError); + outBatchCfg["HandleError" ](config.handleError); + outBatchCfg["ShowProgress" ](config.showProgress); + outBatchCfg["LogfileFolder" ](config.logFileDirectory); + outBatchCfg["LogfileFolder"].attribute("Limit", config.logfilesCountLimit); } @@ -1231,6 +1285,11 @@ void writeConfig(const XmlGlobalSettings& config, XmlOut& out) outWnd["Layout"](config.gui.guiPerspectiveLast); + //load config file history + outGui["LastUsedConfig"](config.gui.lastUsedConfigFiles); + outGui["ConfigHistory" ](config.gui.cfgFileHistory); + outGui["ConfigHistory"].attribute("MaxSize", config.gui.cfgFileHistMax); + outGui["FolderHistoryLeft" ](config.gui.folderHistoryLeft); outGui["FolderHistoryRight"](config.gui.folderHistoryRight); outGui["FolderHistoryLeft" ].attribute("MaxSize", config.gui.folderHistMax); @@ -1241,10 +1300,6 @@ void writeConfig(const XmlGlobalSettings& config, XmlOut& out) //external applications outGui["ExternalApplications"](config.gui.externelApplications); - //load config file history - outGui["LastConfigActive"](config.gui.lastUsedConfigFiles); - outGui["ConfigHistory" ](config.gui.cfgFileHistory); - //last update check outGui["LastUpdateCheck"](config.gui.lastUpdateCheck); diff --git a/lib/process_xml.h b/lib/process_xml.h index 540b4ef3..7191e0c2 100644 --- a/lib/process_xml.h +++ b/lib/process_xml.h @@ -1,7 +1,7 @@ // ************************************************************************** // * 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) ZenJu (zhnmju123 AT gmx DOT de) - All Rights Reserved * +// * Copyright (C) ZenJu (zenju AT gmx DOT de) - All Rights Reserved * // ************************************************************************** #ifndef PROCESSXML_H_INCLUDED @@ -12,6 +12,7 @@ #include "xml_base.h" #include "localization.h" #include "../ui/column_attr.h" +//#include "ffs_paths.h" namespace xmlAccess { @@ -47,25 +48,23 @@ typedef std::vector<std::pair<Description, Commandline> > ExternalApps; struct XmlGuiConfig { XmlGuiConfig() : - hideFilteredElements(false), + showFilteredElements(true), handleError(ON_GUIERROR_POPUP), showSyncAction(true) {} //initialize values zen::MainConfiguration mainCfg; - bool hideFilteredElements; + bool showFilteredElements; OnGuiError handleError; //reaction on error situation during synchronization bool showSyncAction; bool operator==(const XmlGuiConfig& other) const { - return mainCfg == other.mainCfg && - hideFilteredElements == other.hideFilteredElements && - handleError == other.handleError && + return mainCfg == other.mainCfg && + showFilteredElements == other.showFilteredElements && + handleError == other.handleError && showSyncAction == other.showSyncAction; } - - bool operator!=(const XmlGuiConfig& other) const { return !(*this == other); } }; @@ -73,15 +72,15 @@ struct XmlBatchConfig { XmlBatchConfig() : showProgress(true), - logFileCountMax(200), + logfilesCountLimit(-1), handleError(ON_ERROR_POPUP) {} zen::MainConfiguration mainCfg; bool showProgress; - wxString logFileDirectory; - size_t logFileCountMax; - OnError handleError; //reaction on error situation during synchronization + Zstring logFileDirectory; + int logfilesCountLimit; //max logfiles; 0 := don't save logfiles; < 0 := no limit + OnError handleError; //reaction on error situation during synchronization }; @@ -155,6 +154,7 @@ struct XmlGlobalSettings naviLastSortColumn(zen::defaultValueLastSortColumn), naviLastSortAscending(zen::defaultValueLastSortAscending), showPercentBar(zen::defaultValueShowPercentage), + cfgFileHistMax(20), folderHistMax(15), onCompletionHistoryMax(8), deleteOnBothSides(false), @@ -171,14 +171,14 @@ struct XmlGlobalSettings //default external apps will be translated "on the fly"!!! First entry will be used for [Enter] or mouse double-click! #ifdef FFS_WIN externelApplications.push_back(std::make_pair(L"Show in Explorer", //mark for extraction: _("Show in Explorer") - L"explorer /select, \"%name\"")); + L"explorer /select, \"%item_path%\"")); externelApplications.push_back(std::make_pair(L"Open with default application", //mark for extraction: _("Open with default application") - L"\"%name\"")); + L"\"%item_path%\"")); #elif defined FFS_LINUX externelApplications.push_back(std::make_pair(L"Browse directory", //mark for extraction: _("Browse directory") Linux doesn't use the term "folder" - L"xdg-open \"%dir\"")); + L"xdg-open \"%item_folder%\"")); externelApplications.push_back(std::make_pair(L"Open with default application", //mark for extraction: _("Open with default application") - L"xdg-open \"%name\"")); + L"xdg-open \"%item_path%\"")); #endif } @@ -201,11 +201,13 @@ struct XmlGlobalSettings ExternalApps externelApplications; std::vector<wxString> cfgFileHistory; + size_t cfgFileHistMax; + std::vector<wxString> lastUsedConfigFiles; std::vector<Zstring> folderHistoryLeft; std::vector<Zstring> folderHistoryRight; - unsigned int folderHistMax; + size_t folderHistMax; std::vector<std::wstring> onCompletionHistory; size_t onCompletionHistoryMax; diff --git a/lib/resolve_path.cpp b/lib/resolve_path.cpp index 57f4ff30..425a640b 100644 --- a/lib/resolve_path.cpp +++ b/lib/resolve_path.cpp @@ -1,17 +1,18 @@ #include "resolve_path.h" -#include <wx/utils.h> -#include <zen/time.h> -#include <wx+/string_conv.h> #include <map> #include <set> +#include <zen/time.h> #include <zen/scope_guard.h> #include <zen/thread.h> +#include <wx/utils.h> +#include <wx+/string_conv.h> #ifdef FFS_WIN #include <zen/dll.h> #include <Shlobj.h> #include <zen/win.h> //includes "windows.h" #include <zen/long_path_prefix.h> +#include <zen/file_handling.h> #ifdef _MSC_VER #pragma comment(lib, "Mpr.lib") #endif @@ -138,119 +139,114 @@ private: }; //caveat: function scope static initialization is not thread-safe in VS 2010! => make sure to call at app start! -namespace -{ struct Dummy { Dummy() { CsidlConstants::get(); }} blah; -} #endif -wxString getEnvValue(const wxString& envName) //return empty on error +std::unique_ptr<Zstring> getEnvironmentVar(const Zstring& envName) //return nullptr if not found { - //try to apply environment variables - wxString envValue; - if (wxGetEnv(envName, &envValue)) - { - //some postprocessing: - trim(envValue); //remove leading, trailing blanks - - //remove leading, trailing double-quotes - if (startsWith(envValue, L"\"") && - endsWith(envValue, L"\"") && - envValue.length() >= 2) - envValue = wxString(envValue.c_str() + 1, envValue.length() - 2); - } - return envValue; + wxString value; + if (!wxGetEnv(utfCvrtTo<wxString>(envName), &value)) + return nullptr; + + //some postprocessing: + trim(value); //remove leading, trailing blanks + + //remove leading, trailing double-quotes + if (startsWith(value, L"\"") && + endsWith (value, L"\"") && + value.length() >= 2) + value = wxString(value.c_str() + 1, value.length() - 2); + + return make_unique<Zstring>(utfCvrtTo<Zstring>(value)); } -bool replaceMacro(wxString& macro) //macro without %-characters, return true if replaced successfully +std::unique_ptr<Zstring> resolveMacro(const Zstring& macro, //macro without %-characters + const std::vector<std::pair<Zstring, Zstring>>& ext) //return nullptr if not resolved { - if (macro.IsEmpty()) - return false; + auto equalNoCase = [](const Zstring& lhs, const Zstring& rhs) { return utfCvrtTo<wxString>(lhs).CmpNoCase(utfCvrtTo<wxString>(rhs)) == 0; }; - //there are equally named environment variables %TIME%, %DATE% existing, so replace these first! - if (macro.CmpNoCase(L"time") == 0) - { - macro = formatTime<wxString>(L"%H%M%S"); - return true; - } + //there exist environment variables named %TIME%, %DATE% so check for our internal macros first! + if (equalNoCase(macro, Zstr("time"))) + return make_unique<Zstring>(formatTime<Zstring>(Zstr("%H%M%S"))); - if (macro.CmpNoCase(L"date") == 0) - { - macro = formatTime<wxString>(FORMAT_ISO_DATE); - return true; - } + if (equalNoCase(macro, Zstr("date"))) + return make_unique<Zstring>(formatTime<Zstring>(FORMAT_ISO_DATE)); - auto processPhrase = [&](const wchar_t* phrase, const wchar_t* format) -> bool + std::unique_ptr<Zstring> cand; + auto processPhrase = [&](const Zchar* phrase, const Zchar* format) -> bool { - if (macro.CmpNoCase(phrase) != 0) + if (!equalNoCase(macro, phrase)) return false; - macro = formatTime<wxString>(format); + cand = make_unique<Zstring>(formatTime<Zstring>(format)); return true; }; - if (processPhrase(L"weekday", L"%A")) return true; - if (processPhrase(L"day" , L"%d")) return true; - if (processPhrase(L"month" , L"%B")) return true; - if (processPhrase(L"week" , L"%U")) return true; - if (processPhrase(L"year" , L"%Y")) return true; - if (processPhrase(L"hour" , L"%H")) return true; - if (processPhrase(L"min" , L"%M")) return true; - if (processPhrase(L"sec" , L"%S")) return true; - - //try to apply environment variables - { - wxString envValue = getEnvValue(macro); - if (!envValue.empty()) - { - macro = envValue; - return true; - } - } + if (processPhrase(Zstr("weekday"), Zstr("%A"))) return cand; + if (processPhrase(Zstr("day" ), Zstr("%d"))) return cand; + if (processPhrase(Zstr("month" ), Zstr("%B"))) return cand; + if (processPhrase(Zstr("week" ), Zstr("%U"))) return cand; + if (processPhrase(Zstr("year" ), Zstr("%Y"))) return cand; + if (processPhrase(Zstr("hour" ), Zstr("%H"))) return cand; + if (processPhrase(Zstr("min" ), Zstr("%M"))) return cand; + if (processPhrase(Zstr("sec" ), Zstr("%S"))) return cand; + + //check domain-specific extensions + { + auto iter = std::find_if(ext.begin(), ext.end(), [&](const std::pair<Zstring, Zstring>& p){ return equalNoCase(macro, p.first); }); + if (iter != ext.end()) + return make_unique<Zstring>(iter->second); + } + + //try to resolve as environment variable + if (std::unique_ptr<Zstring> value = getEnvironmentVar(macro)) + return value; #ifdef FFS_WIN - //try to resolve CSIDL values + //try to resolve as CSIDL value { - auto csidlMap = CsidlConstants::get(); - auto iter = csidlMap.find(toZ(macro)); + const auto& csidlMap = CsidlConstants::get(); + auto iter = csidlMap.find(macro); if (iter != csidlMap.end()) - { - macro = toWx(iter->second); - return true; - } + return make_unique<Zstring>(iter->second); } #endif - return false; + return nullptr; } +const Zchar MACRO_SEP = Zstr('%'); //returns expanded or original string -wxString expandMacros(const wxString& text) +Zstring expandMacros(const Zstring& text, const std::vector<std::pair<Zstring, Zstring>>& ext) { - const wxChar SEPARATOR = L'%'; - - if (contains(text, SEPARATOR)) + if (contains(text, MACRO_SEP)) { - wxString prefix = text.BeforeFirst(SEPARATOR); - wxString rest = text.AfterFirst(SEPARATOR); - if (contains(rest, SEPARATOR)) + Zstring prefix = beforeFirst(text, MACRO_SEP); + Zstring rest = afterFirst (text, MACRO_SEP); + if (contains(rest, MACRO_SEP)) { - wxString potentialMacro = beforeFirst(rest, SEPARATOR); - wxString postfix = afterFirst (rest, SEPARATOR); //text == prefix + SEPARATOR + potentialMacro + SEPARATOR + postfix + Zstring potentialMacro = beforeFirst(rest, MACRO_SEP); + Zstring postfix = afterFirst (rest, MACRO_SEP); //text == prefix + MACRO_SEP + potentialMacro + MACRO_SEP + postfix - if (replaceMacro(potentialMacro)) - return prefix + potentialMacro + expandMacros(postfix); + if (std::unique_ptr<Zstring> value = resolveMacro(potentialMacro, ext)) + return prefix + *value + expandMacros(postfix, ext); else - return prefix + SEPARATOR + potentialMacro + expandMacros(SEPARATOR + postfix); + return prefix + MACRO_SEP + potentialMacro + expandMacros(MACRO_SEP + postfix, ext); } } return text; } +} + + +Zstring zen::expandMacros(const Zstring& text) { return ::expandMacros(text, std::vector<std::pair<Zstring, Zstring>>()); } +namespace +{ #ifdef FFS_LINUX class TraverseMedia : public zen::TraverseCallback { @@ -266,7 +262,7 @@ public: devices_.insert(std::make_pair(shortName, fullName)); return nullptr; //DON'T traverse into subdirs } - virtual HandleError onError(const std::wstring& errorText) { return ON_ERROR_IGNORE; } + virtual HandleError onError(const std::wstring& msg) { return ON_ERROR_IGNORE; } private: DeviceList& devices_; @@ -275,7 +271,7 @@ private: //networks and cdrom excluded - this should not block -Zstring volumenNameToPath(const Zstring& volumeName) //return empty string on error +Zstring getPathByVolumenName(const Zstring& volumeName) //return empty string on error { #ifdef FFS_WIN //FindFirstVolume(): traverses volumes on local hard disks only! @@ -340,7 +336,7 @@ Zstring volumenNameToPath(const Zstring& volumeName) //return empty string on er #ifdef FFS_WIN //networks and cdrom excluded - this should not block -Zstring volumePathToName(const Zstring& volumePath) //return empty string on error +Zstring getVolumeName(const Zstring& volumePath) //return empty string on error { UINT rv = ::GetDriveType(volumePath.c_str()); //non-blocking call! if (rv != DRIVE_REMOTE && @@ -387,7 +383,7 @@ Zstring expandVolumeName(const Zstring& text) // [volname]:\folder [volna //[.*] pattern was found... if (!volname.empty()) { - Zstring volPath = volumenNameToPath(volname); //should not block?! + Zstring volPath = getPathByVolumenName(volname); //should not block?! if (!volPath.empty()) return appendSeparator(volPath) + rest; //successfully replaced pattern } @@ -421,7 +417,7 @@ void getDirectoryAliasesRecursive(const Zstring& dirname, std::set<Zstring, Less dirname[1] == L':' && dirname[2] == L'\\') { - Zstring volname = volumePathToName(Zstring(dirname.c_str(), 3)); //should not block + Zstring volname = getVolumeName(Zstring(dirname.c_str(), 3)); //should not block if (!volname.empty()) output.insert(L"[" + volname + L"]" + Zstring(dirname.c_str() + 2)); } @@ -439,11 +435,10 @@ void getDirectoryAliasesRecursive(const Zstring& dirname, std::set<Zstring, Less std::map<Zstring, Zstring> envToDir; //get list of useful variables - auto addEnvVar = [&](const wxString& envName) + auto addEnvVar = [&](const Zstring& envName) { - wxString envVal = getEnvValue(envName); //return empty on error - if (!envVal.empty()) - envToDir.insert(std::make_pair(toZ(envName), toZ(envVal))); + if (std::unique_ptr<Zstring> value = getEnvironmentVar(envName)) + envToDir.insert(std::make_pair(envName, *value)); }; addEnvVar(L"AllUsersProfile"); // C:\ProgramData addEnvVar(L"AppData"); // C:\Users\username\AppData\Roaming @@ -457,9 +452,10 @@ void getDirectoryAliasesRecursive(const Zstring& dirname, std::set<Zstring, Less addEnvVar(L"Temp"); // C:\Windows\Temp //add CSIDL values: http://msdn.microsoft.com/en-us/library/bb762494(v=vs.85).aspx - auto csidlMap = CsidlConstants::get(); + const auto& csidlMap = CsidlConstants::get(); envToDir.insert(csidlMap.begin(), csidlMap.end()); + //substitute paths by symbolic names Zstring tmp = dirname; ::makeUpper(tmp); std::for_each(envToDir.begin(), envToDir.end(), @@ -468,13 +464,13 @@ void getDirectoryAliasesRecursive(const Zstring& dirname, std::set<Zstring, Less Zstring tmp2 = entry.second; //case-insensitive "startsWith()" ::makeUpper(tmp2); // if (startsWith(tmp, tmp2)) - output.insert(L"%" + entry.first + L"%" + (dirname.c_str() + tmp2.size())); + output.insert(MACRO_SEP + entry.first + MACRO_SEP + (dirname.c_str() + tmp2.size())); }); } //4. replace (all) macros: %USERPROFILE% -> C:\Users\username { - Zstring testMacros = toZ(expandMacros(toWx(dirname))); + Zstring testMacros = expandMacros(dirname); if (testMacros != dirname) if (output.insert(testMacros).second) getDirectoryAliasesRecursive(testMacros, output); //recurse! @@ -502,9 +498,9 @@ std::vector<Zstring> zen::getDirectoryAliases(const Zstring& dirString) Zstring zen::getFormattedDirectoryName(const Zstring& dirString) // throw() { - //Formatting is needed since functions expect the directory to end with '\' to be able to split the relative names. + //formatting is needed since functions expect the directory to end with '\' to be able to split the relative names. - Zstring dirname = toZ(expandMacros(toWx(dirString))); + Zstring dirname = expandMacros(dirString); dirname = expandVolumeName(dirname); //should not block @@ -517,7 +513,7 @@ Zstring zen::getFormattedDirectoryName(const Zstring& dirString) // throw() return Zstring(); /* - resolve relative names; required by: + need to resolve relative paths: WINDOWS: - \\?\-prefix which needs absolute names - Volume Shadow Copy: volume name needs to be part of each filename @@ -544,14 +540,68 @@ void zen::loginNetworkShare(const Zstring& dirnameOrig, bool allowUserInteractio WebDrive | NO_ERROR | \\Webdrive-ZenJu\GNU | NO Box.net (WebDav) | NO_ERROR | \\www.box.net\DavWWWRoot\dav | YES NetDrive | ERROR_NOT_CONNECTED | <empty> | NO + ____________________________________________________________________________________________________________ + + Windows Login Prompt Naming Conventions: + user account: <Domain>\<user> e.g. WIN-XP\ZenJu + network share: \\<server>\<share> e.g. \\WIN-XP\test + + Windows Command Line: + - list *all* active network connections, including deviceless ones which are hidden in Explorer: + net use + - delete active connection: + net use /delete \\server\share + ____________________________________________________________________________________________________________ + + Scenario: XP-shared folder is accessed by Win 7 over LAN with access limited to a certain user + + Problems: + I. WNetAddConnection2() allows (at least certain) invalid credentials (e.g. username: a/password: a) and establishes an *unusable* connection + II. WNetAddConnection2() refuses to overwrite an existing (unusable) connection created in I), but shows prompt repeatedly + III. WNetAddConnection2() won't bring up the prompt if *wrong* credentials had been entered just recently, even with CONNECT_INTERACTIVE specified! => 2-step proccess */ - //if (::GetFileAttributes((driveLetter + L'\\').c_str()) == INVALID_FILE_ATTRIBUTES) <- this will seriously block if network is not reachable!!! + auto connect = [&](NETRESOURCE& trgRes) //blocks heavily if network is not reachable!!! + { + //1. first try to connect without user interaction - blocks! + DWORD rv = ::WNetAddConnection2(&trgRes, // __in LPNETRESOURCE lpNetResource, + nullptr, // __in LPCTSTR lpPassword, + nullptr, // __in LPCTSTR lpUsername, + 0); //__in DWORD dwFlags + if (somethingExists(trgRes.lpRemoteName)) //blocks! + return; //success: connection usable! -> don't care about "rv" + + if (rv == ERROR_BAD_NETPATH || //Windows 7 + rv == ERROR_BAD_NET_NAME) //XP + return; //no need to show a prompt for an unreachable network device + + //2. if first attempt failed, we need to *force* prompt by using CONNECT_PROMPT + if (allowUserInteraction) + { + //avoid problem II.) + DWORD rv2= WNetCancelConnection2(trgRes.lpRemoteName, //_In_ LPCTSTR lpName, + 0, //_In_ DWORD dwFlags, + true); //_In_ BOOL fForce + //enforce login prompt + DWORD rv3 = ::WNetAddConnection2(&trgRes, // __in LPNETRESOURCE lpNetResource, + nullptr, // __in LPCTSTR lpPassword, + nullptr, // __in LPCTSTR lpUsername, + CONNECT_INTERACTIVE | CONNECT_PROMPT); //__in DWORD dwFlags + (void)rv2; + (void)rv3; + //Sample error codes: + //53L ERROR_BAD_NETPATH The network path was not found. + //86L ERROR_INVALID_PASSWORD + //1219L ERROR_SESSION_CREDENTIAL_CONFLICT Multiple connections to a server or shared resource by the same user, using more than one user name, are not allowed. Disconnect all previous connections to the server or shared resource and try again. + //1326L ERROR_LOGON_FAILURE Logon failure: unknown user name or bad password. + } + }; + Zstring dirname = removeLongPathPrefix(dirnameOrig); trim(dirname, true, false); - //1. local path + //1. locally mapped network share if (dirname.size() >= 2 && iswalpha(dirname[0]) && dirname[1] == L':') { Zstring driveLetter(dirname.c_str(), 2); //e.g.: "Q:" @@ -577,22 +627,13 @@ void zen::loginNetworkShare(const Zstring& dirnameOrig, bool allowUserInteractio trgRes.lpLocalName = const_cast<LPWSTR>(driveLetter.c_str()); //lpNetResource is marked "__in", seems WNetAddConnection2 is not const correct! trgRes.lpRemoteName = const_cast<LPWSTR>(networkShare.c_str()); // - //note: following function call may block heavily if network is not reachable!!! - DWORD rv2 = ::WNetAddConnection2(&trgRes, // __in LPNETRESOURCE lpNetResource, - nullptr, // __in LPCTSTR lpPassword, - nullptr, // __in LPCTSTR lpUsername, - allowUserInteraction ? CONNECT_INTERACTIVE : 0); //__in DWORD dwFlags - if (rv2 == NO_ERROR) - return; //mapping reestablished - - //restoring connection failed for some reason... - //we could use full UNC path instead: networkShare + (dirname.c_str() + 2); //replace "Q:\subdir" by "\\server\share\subdir" + connect(trgRes); //blocks! } } } } - //2. UNC path - else if (startsWith(dirname, L"\\\\")) + //2. deviceless network connection + else if (startsWith(dirname, L"\\\\")) //UNC path { const Zstring networkShare = [&]() -> Zstring //extract prefix "\\server\share" { @@ -612,49 +653,7 @@ void zen::loginNetworkShare(const Zstring& dirnameOrig, bool allowUserInteractio trgRes.dwType = RESOURCETYPE_DISK; trgRes.lpRemoteName = const_cast<LPWSTR>(networkShare.c_str()); //trgRes is "__in" - //following function call may block heavily if network is not reachable!!! - DWORD rv2 = ::WNetAddConnection2(&trgRes, // __in LPNETRESOURCE lpNetResource, - nullptr, // __in LPCTSTR lpPassword, - nullptr, // __in LPCTSTR lpUsername, - allowUserInteraction ? CONNECT_INTERACTIVE : 0); //__in DWORD dwFlags - if (rv2 == NO_ERROR) - return; //mapping reestablished - - /* - NETRESOURCE nr = {}; - nr.dwType = RESOURCETYPE_DISK; - nr.lpRemoteName = const_cast<LPWSTR>(networkShare.c_str()); //nr is "__in" - - DWORD bufferSize = sizeof(NETRESOURCE) + 20000; - std::vector<char> buffer(bufferSize); - - LPTSTR relPath = nullptr; - - //note: following function call may block heavily if network is not reachable!!! - const DWORD rv = WNetGetResourceInformation(&nr, // __in LPNETRESOURCE lpNetResource, - &buffer[0], // __out LPVOID lpBuffer, - &bufferSize, // __inout LPDWORD lpcbBuffer, - &relPath); // __out LPTSTR *lplpSystem - if (rv == NO_ERROR) - { - //NO_ERROR: network share is existing, *either* connected or disconnected - - //we have no way to check if network is already connected, so let's try to connect anyway: - - NETRESOURCE& trgRes = reinterpret_cast<NETRESOURCE&>(buffer[0]); - - if (trgRes.dwUsage & RESOURCEUSAGE_CONNECTABLE) - { - //note: following function call may block heavily if network is not reachable!!! - DWORD rv2 = ::WNetAddConnection2(&trgRes, // __in LPNETRESOURCE lpNetResource, - nullptr, // __in LPCTSTR lpPassword, - nullptr, // __in LPCTSTR lpUsername, - allowUserInteraction ? CONNECT_INTERACTIVE : 0); //__in DWORD dwFlags - if (rv2 == NO_ERROR) - return; //mapping reestablished - } - } - */ + connect(trgRes); //blocks! } } } diff --git a/lib/resolve_path.h b/lib/resolve_path.h index bc74441a..ccc8f42e 100644 --- a/lib/resolve_path.h +++ b/lib/resolve_path.h @@ -1,25 +1,34 @@ // ************************************************************************** // * 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) ZenJu (zhnmju123 AT gmx DOT de) - All Rights Reserved * +// * Copyright (C) ZenJu (zenju AT gmx DOT de) - All Rights Reserved * // ************************************************************************** #ifndef RESOLVE_PATH_H_INCLUDED #define RESOLVE_PATH_H_INCLUDED +#include <vector> #include <zen/zstring.h> - namespace zen { -//resolve environment variables, relative paths, ect. and append file name separator +/* +FULL directory format: + - expand macros + - expand volume path by name + - convert relative paths into absolute + - trim whitespace and append file name separator +*/ Zstring getFormattedDirectoryName(const Zstring& dirString); //throw() - non-blocking! no I/O! -#ifdef FFS_WIN -std::vector<Zstring> getDirectoryAliases(const Zstring& dirString); +//macro substitution only +Zstring expandMacros(const Zstring& text); -//this call may block if network is not reachable or when showing login prompt! +#ifdef FFS_WIN +//*blocks* if network is not reachable or when showing login prompt dialog! void loginNetworkShare(const Zstring& dirname, bool allowUserInteraction); //throw() - user interaction: show OS password prompt + +std::vector<Zstring> getDirectoryAliases(const Zstring& dirString); #endif } diff --git a/lib/resources.cpp b/lib/resources.cpp index 0d86279b..ac20066a 100644 --- a/lib/resources.cpp +++ b/lib/resources.cpp @@ -1,7 +1,7 @@ // ************************************************************************** // * 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) ZenJu (zhnmju123 AT gmx DOT de) - All Rights Reserved * +// * Copyright (C) ZenJu (zenju AT gmx DOT de) - All Rights Reserved * // ************************************************************************** #include "resources.h" @@ -10,7 +10,6 @@ #include <wx/zipstrm.h> #include <wx/image.h> #include <wx/mstream.h> -//#include <wx+/string_conv.h> #include "ffs_paths.h" using namespace zen; diff --git a/lib/resources.h b/lib/resources.h index 56b23a5f..df13340d 100644 --- a/lib/resources.h +++ b/lib/resources.h @@ -1,7 +1,7 @@ // ************************************************************************** // * 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) ZenJu (zhnmju123 AT gmx DOT de) - All Rights Reserved * +// * Copyright (C) ZenJu (zenju AT gmx DOT de) - All Rights Reserved * // ************************************************************************** #ifndef RESOURCES_H_INCLUDED diff --git a/lib/return_codes.h b/lib/return_codes.h index c5f8fd15..34ae0527 100644 --- a/lib/return_codes.h +++ b/lib/return_codes.h @@ -1,7 +1,7 @@ // ************************************************************************** // * 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) ZenJu (zhnmju123 AT gmx DOT de) - All Rights Reserved * +// * Copyright (C) ZenJu (zenju AT gmx DOT de) - All Rights Reserved * // ************************************************************************** #ifndef RETURN_CODES_H_INCLUDED diff --git a/lib/shadow.cpp b/lib/shadow.cpp index ba4e1f5e..5a5b9cef 100644 --- a/lib/shadow.cpp +++ b/lib/shadow.cpp @@ -1,7 +1,7 @@ // ************************************************************************** // * 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) ZenJu (zhnmju123 AT gmx DOT de) - All Rights Reserved * +// * Copyright (C) ZenJu (zenju AT gmx DOT de) - All Rights Reserved * // ************************************************************************** #include "shadow.h" @@ -29,7 +29,6 @@ bool runningWOW64() //test if process is running under WOW64 (reference http://m if (isWow64Process(::GetCurrentProcess(), &isWow64)) return isWow64 != FALSE; } - return false; } } @@ -48,7 +47,7 @@ public: backupHandle(nullptr) { //VSS does not support running under WOW64 except for Windows XP and Windows Server 2003 - //(Reference: http://msdn.microsoft.com/en-us/library/aa384627(VS.85).aspx) + //reference: http://msdn.microsoft.com/en-us/library/aa384627(VS.85).aspx if (runningWOW64()) throw FileError(_("Cannot access Volume Shadow Copy Service.") + L"\n" + _("Please use FreeFileSync 64-bit version to create shadow copies on this system.")); diff --git a/lib/shadow.h b/lib/shadow.h index 5335e95d..bb834a41 100644 --- a/lib/shadow.h +++ b/lib/shadow.h @@ -1,7 +1,7 @@ // ************************************************************************** // * 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) ZenJu (zhnmju123 AT gmx DOT de) - All Rights Reserved * +// * Copyright (C) ZenJu (zenju AT gmx DOT de) - All Rights Reserved * // ************************************************************************** #ifndef SHADOW_H_INCLUDED @@ -15,7 +15,7 @@ namespace shadow { -class ShadowCopy //buffer access to Windows Volume Shadow Copy Service +class ShadowCopy //take and buffer Windows Volume Shadow Copy snapshots as needed { public: ShadowCopy() {} diff --git a/lib/soft_filter.h b/lib/soft_filter.h index 1ad55ea9..b9fb2fd4 100644 --- a/lib/soft_filter.h +++ b/lib/soft_filter.h @@ -1,7 +1,7 @@ // ************************************************************************** // * 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) ZenJu (zhnmju123 AT gmx DOT de) - All Rights Reserved * +// * Copyright (C) ZenJu (zenju AT gmx DOT de) - All Rights Reserved * // ************************************************************************** #ifndef SOFT_FILTER_H_INCLUDED diff --git a/lib/status_handler.cpp b/lib/status_handler.cpp index d9655c48..a7286c39 100644 --- a/lib/status_handler.cpp +++ b/lib/status_handler.cpp @@ -1,7 +1,7 @@ // ************************************************************************** // * 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) ZenJu (zhnmju123 AT gmx DOT de) - All Rights Reserved * +// * Copyright (C) ZenJu (zenju AT gmx DOT de) - All Rights Reserved * // ************************************************************************** #include "status_handler.h" diff --git a/lib/status_handler.h b/lib/status_handler.h index ca7af298..129d5ae9 100644 --- a/lib/status_handler.h +++ b/lib/status_handler.h @@ -1,7 +1,7 @@ // ************************************************************************** // * 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) ZenJu (zhnmju123 AT gmx DOT de) - All Rights Reserved * +// * Copyright (C) ZenJu (zenju AT gmx DOT de) - All Rights Reserved * // ************************************************************************** #ifndef STATUSHANDLER_H_INCLUDED diff --git a/lib/status_handler_impl.h b/lib/status_handler_impl.h index 10890dbe..16466556 100644 --- a/lib/status_handler_impl.h +++ b/lib/status_handler_impl.h @@ -1,7 +1,7 @@ // ************************************************************************** // * 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) ZenJu (zhnmju123 AT gmx DOT de) - All Rights Reserved * +// * Copyright (C) ZenJu (zenju AT gmx DOT de) - All Rights Reserved * // ************************************************************************** #ifndef STATUSHANDLER_IMPL_H_INCLUDED diff --git a/lib/versioning.cpp b/lib/versioning.cpp new file mode 100644 index 00000000..a285bb70 --- /dev/null +++ b/lib/versioning.cpp @@ -0,0 +1,398 @@ +#include "versioning.h" +#include <map> +#include <zen/file_handling.h> +#include <zen/file_traverser.h> +#include <zen/string_tools.h> + +using namespace zen; + + +namespace +{ +Zstring getExtension(const Zstring& relativeName) //including "." if extension is existing, returns empty string otherwise +{ + auto iterSep = find_last(relativeName.begin(), relativeName.end(), FILE_NAME_SEPARATOR); + auto iterName = iterSep != relativeName.end() ? iterSep + 1 : relativeName.begin(); //find beginning of short name + auto iterDot = find_last(iterName, relativeName.end(), Zstr('.')); //equal to relativeName.end() if file has no extension!! + return Zstring(&*iterDot, relativeName.end() - iterDot); +}; +} + +bool impl::isMatchingVersion(const Zstring& shortname, const Zstring& shortnameVersion) //e.g. ("Sample.txt", "Sample.txt 2012-05-15 131513.txt") +{ + auto iter = shortnameVersion.begin(); + auto last = shortnameVersion.end(); + + auto nextDigit = [&]() -> bool + { + if (iter == last || !isDigit(*iter)) + return false; + ++iter; + return true; + }; + auto nextDigits = [&](size_t count) -> bool + { + while (count-- > 0) + if (!nextDigit()) + return false; + return true; + }; + auto nextChar = [&](Zchar c) -> bool + { + if (iter == last || *iter != c) + return false; + ++iter; + return true; + }; + auto nextStringI = [&](const Zstring& str) -> bool //windows: ignore case! + { + if (last - iter < static_cast<ptrdiff_t>(str.size()) || !EqualFilename()(str, Zstring(&*iter, str.size()))) + return false; + iter += str.size(); + return true; + }; + + return nextStringI(shortname) && //versioned file starts with original name + nextChar(Zstr(' ')) && //validate timestamp: e.g. "2012-05-15 131513"; Regex: \d{4}-\d{2}-\d{2} \d{6} + nextDigits(4) && //YYYY + nextChar(Zstr('-')) && // + nextDigits(2) && //MM + nextChar(Zstr('-')) && // + nextDigits(2) && //DD + nextChar(Zstr(' ')) && // + nextDigits(6) && //HHMMSS + nextStringI(getExtension(shortname)) && + iter == last; +} + + +namespace +{ +template <class Function> +void moveItemToVersioning(const Zstring& sourceObj, //throw FileError + const Zstring& relativeName, + const Zstring& versioningDirectory, + const Zstring& timestamp, + Function moveObj) //move source -> target; allowed to throw FileError +{ + assert(!startsWith(relativeName, FILE_NAME_SEPARATOR)); + assert(endsWith(sourceObj, relativeName)); //usually, yes, but we might relax this in the future + + //assemble time-stamped version name + const Zstring targetObj = appendSeparator(versioningDirectory) + relativeName + Zstr(' ') + timestamp + getExtension(relativeName); + assert(impl::isMatchingVersion(afterLast(relativeName, FILE_NAME_SEPARATOR), afterLast(targetObj, FILE_NAME_SEPARATOR))); //paranoid? no! + + try + { + moveObj(sourceObj, targetObj); //throw FileError + } + catch (FileError&) //expected to fail if target directory is not yet existing! + { + if (!somethingExists(sourceObj)) //no source at all is not an error (however a directory as source when a file is expected, *is* an error!) + return; //object *not* processed + + //create intermediate directories if missing + const Zstring targetDir = beforeLast(targetObj, FILE_NAME_SEPARATOR); + if (!dirExists(targetDir)) //->(minor) file system race condition! + { + makeDirectory(targetDir); //throw FileError + moveObj(sourceObj, targetObj); //throw FileError -> this should work now! + } + else + throw; + } +} + + +//move source to target across volumes; prerequisite: all super-directories of target exist +//if target already contains some files/dirs they are seen as remnants of a previous incomplete move +void moveFile(const Zstring& sourceFile, const Zstring& targetFile, CallbackCopyFile& callback) //throw FileError +{ + //first try to move directly without copying + try + { + renameFile(sourceFile, targetFile); //throw FileError, ErrorDifferentVolume, ErrorTargetExisting + return; //great, we get away cheaply! + } + //if moving failed treat as error (except when it tried to move to a different volume: in this case we will copy the file) + catch (const ErrorDifferentVolume&) {} + catch (const ErrorTargetExisting&) {} + + //create target + if (!fileExists(targetFile)) //check even if ErrorTargetExisting: me may have clashed with another item type of the same name!!! + { + //file is on a different volume: let's copy it + if (symlinkExists(sourceFile)) + copySymlink(sourceFile, targetFile, false); //throw FileError; don't copy filesystem permissions + else + copyFile(sourceFile, targetFile, false, true, &callback); //throw FileError - permissions "false", transactional copy "true" + } + + //delete source + removeFile(sourceFile); //throw FileError; newly copied file is NOT deleted if exception is thrown here! +} + + +void moveDirSymlink(const Zstring& sourceLink, const Zstring& targetLink) //throw FileError +{ + //first try to move directly without copying + try + { + renameFile(sourceLink, targetLink); //throw FileError, ErrorDifferentVolume, ErrorTargetExisting + return; //great, we get away cheaply! + } + //if moving failed treat as error (except when it tried to move to a different volume: in this case we will copy the file) + catch (const ErrorDifferentVolume&) {} + catch (const ErrorTargetExisting&) {} + + //create target + if (!symlinkExists(targetLink)) //check even if ErrorTargetExisting: me may have clashed with another item type of the same name!!! + { + //link is on a different volume: let's copy it + copySymlink(sourceLink, targetLink, false); //throw FileError; don't copy filesystem permissions + } + + //delete source + removeDirectory(sourceLink); //throw FileError; newly copied link is NOT deleted if exception is thrown here! +} + + +struct CopyCallbackImpl : public CallbackCopyFile +{ + CopyCallbackImpl(CallbackMoveFile& callback) : callback_(callback) {} + +private: + virtual void deleteTargetFile(const Zstring& targetFile) { assert(!somethingExists(targetFile)); } + virtual void updateCopyStatus(Int64 bytesDelta) { callback_.updateStatus(bytesDelta); } + + CallbackMoveFile& callback_; +}; + + +class TraverseFilesOneLevel : public TraverseCallback +{ +public: + TraverseFilesOneLevel(std::vector<Zstring>& files, std::vector<Zstring>& dirs) : files_(files), dirs_(dirs) {} + +private: + virtual void onFile(const Zchar* shortName, const Zstring& fullName, const FileInfo& details) + { + files_.push_back(shortName); + } + + virtual HandleLink onSymlink(const Zchar* shortName, const Zstring& fullName, const SymlinkInfo& details) + { + if (details.dirLink) + dirs_.push_back(shortName); + else + files_.push_back(shortName); + return LINK_SKIP; + } + + virtual std::shared_ptr<TraverseCallback> onDir(const Zchar* shortName, const Zstring& fullName) + { + dirs_.push_back(shortName); + return nullptr; //DON'T traverse into subdirs; moveDirectory works recursively! + } + + virtual HandleError onError(const std::wstring& msg) { throw FileError(msg); } + + std::vector<Zstring>& files_; + std::vector<Zstring>& dirs_; +}; + + +struct RemoveCallbackImpl : public CallbackRemoveDir +{ + RemoveCallbackImpl(CallbackMoveFile& callback) : callback_(callback) {} + +private: + virtual void notifyFileDeletion(const Zstring& filename) { callback_.updateStatus(0); } + virtual void notifyDirDeletion (const Zstring& dirname ) { callback_.updateStatus(0); } + + CallbackMoveFile& callback_; +}; +} + + +void FileVersioner::revisionFile(const Zstring& sourceFile, const Zstring& relativeName, CallbackMoveFile& callback) //throw FileError +{ + moveItemToVersioning(sourceFile, //throw FileError + relativeName, + versioningDirectory_, + timeStamp_, + [&](const Zstring& source, const Zstring& target) + { + callback.onBeforeFileMove(source, target); + + CopyCallbackImpl copyCallback(callback); + moveFile(source, target, copyCallback); //throw FileError + callback.objectProcessed(); + }); + + fileRelnames.push_back(relativeName); +} + + +void FileVersioner::revisionDir(const Zstring& sourceDir, const Zstring& relativeName, CallbackMoveFile& callback) //throw FileError +{ + //note: we cannot support "throw exception if target already exists": If we did, we would have to do a full cleanup + //removing all newly created directories in case of an exception so that subsequent tries would not fail with "target already existing". + //However an exception may also happen during final deletion of source folder, in which case cleanup effectively leads to data loss! + + //create target + if (symlinkExists(sourceDir)) //on Linux there is just one type of symlinks, and since we do revision file symlinks, we should revision dir symlinks as well! + { + moveItemToVersioning(sourceDir, //throw FileError + relativeName, + versioningDirectory_, + timeStamp_, + [&](const Zstring& source, const Zstring& target) + { + callback.onBeforeDirMove(source, target); + moveDirSymlink(source, target); //throw FileError + callback.objectProcessed(); + }); + + fileRelnames.push_back(relativeName); + } + else + { + assert(!startsWith(relativeName, FILE_NAME_SEPARATOR)); + assert(endsWith(sourceDir, relativeName)); + const Zstring targetDir = appendSeparator(versioningDirectory_) + relativeName; + + callback.onBeforeDirMove(sourceDir, targetDir); + + //makeDirectory(targetDir); //FileError -> create only when needed in moveFileToVersioning(); avoids empty directories + + //traverse source directory one level + std::vector<Zstring> fileList; //list of *short* names + std::vector<Zstring> dirList; // + try + { + TraverseFilesOneLevel tol(fileList, dirList); //throw FileError + traverseFolder(sourceDir, tol); // + } + catch (FileError&) + { + if (!somethingExists(sourceDir)) //no source at all is not an error (however a file as source when a directory is expected, *is* an error!) + return; //object *not* processed + throw; + } + + const Zstring sourceDirPf = appendSeparator(sourceDir); + const Zstring relnamePf = appendSeparator(relativeName); + + //move files + std::for_each(fileList.begin(), fileList.end(), + [&](const Zstring& shortname) + { + revisionFile(sourceDirPf + shortname, //throw FileError + relnamePf + shortname, + callback); + }); + + //move directories + std::for_each(dirList.begin(), dirList.end(), + [&](const Zstring& shortname) + { + revisionDir(sourceDirPf + shortname, //throw FileError + relnamePf + shortname, + callback); + }); + + //delete source + RemoveCallbackImpl removeCallback(callback); + removeDirectory(sourceDir, &removeCallback); //throw FileError + + callback.objectProcessed(); + } +} + + +namespace +{ +class TraverseVersionsOneLevel : public TraverseCallback +{ +public: + TraverseVersionsOneLevel(std::vector<Zstring>& files, std::function<void()> updateUI) : files_(files), updateUI_(updateUI) {} + +private: + virtual void onFile(const Zchar* shortName, const Zstring& fullName, const FileInfo& details) { files_.push_back(shortName); updateUI_(); } + virtual HandleLink onSymlink(const Zchar* shortName, const Zstring& fullName, const SymlinkInfo& details) { files_.push_back(shortName); updateUI_(); return LINK_SKIP; } + virtual std::shared_ptr<TraverseCallback> onDir(const Zchar* shortName, const Zstring& fullName) { updateUI_(); return nullptr; } //DON'T traverse into subdirs + virtual HandleError onError(const std::wstring& msg) { throw FileError(msg); } + + std::vector<Zstring>& files_; + std::function<void()> updateUI_; +}; +} + + +void FileVersioner::limitVersions(std::function<void()> updateUI) //throw FileError +{ + if (versionCountLimit_ < 0) //no limit! + return; + + //buffer map "directory |-> list of immediate child file and symlink short names" + std::map<Zstring, std::vector<Zstring>, LessFilename> dirBuffer; + + auto getVersionsBuffered = [&](const Zstring& dirname) -> const std::vector<Zstring>& + { + auto iter = dirBuffer.find(dirname); + if (iter != dirBuffer.end()) + return iter->second; + + std::vector<Zstring> fileShortNames; + TraverseVersionsOneLevel tol(fileShortNames, updateUI); //throw FileError + traverseFolder(dirname, tol); + + auto& newEntry = dirBuffer[dirname]; //transactional behavior!!! + newEntry.swap(fileShortNames); //-> until C++11 emplace is available + + return newEntry; + }; + + std::for_each(fileRelnames.begin(), fileRelnames.end(), + [&](const Zstring& relativeName) //e.g. "subdir\Sample.txt" + { + const Zstring fullname = appendSeparator(versioningDirectory_) + relativeName; //e.g. "D:\Revisions\subdir\Sample.txt" + const Zstring parentDir = beforeLast(fullname, FILE_NAME_SEPARATOR); //e.g. "D:\Revisions\subdir" + const Zstring shortname = afterLast(relativeName, FILE_NAME_SEPARATOR); //e.g. "Sample.txt"; returns the whole string if seperator not found + + const std::vector<Zstring>& allVersions = getVersionsBuffered(parentDir); + + //filter out only those versions that match the given relative name + std::vector<Zstring> matches; //e.g. "Sample.txt 2012-05-15 131513.txt" + + std::copy_if(allVersions.begin(), allVersions.end(), std::back_inserter(matches), + [&](const Zstring& shortnameVer) { return impl::isMatchingVersion(shortname, shortnameVer); }); + + //take advantage of version naming convention to find oldest versions + if (matches.size() <= static_cast<size_t>(versionCountLimit_)) + return; + std::nth_element(matches.begin(), matches.end() - versionCountLimit_, matches.end(), LessFilename()); //windows: ignore case! + + //delete obsolete versions + std::for_each(matches.begin(), matches.end() - versionCountLimit_, + [&](const Zstring& shortnameVer) + { + updateUI(); + const Zstring fullnameVer = parentDir + FILE_NAME_SEPARATOR + shortnameVer; + try + { + removeFile(fullnameVer); //throw FileError + } + catch (FileError&) + { +#ifdef FFS_WIN //if it's a directory symlink: + if (symlinkExists(fullnameVer) && dirExists(fullnameVer)) + removeDirectory(fullnameVer); //throw FileError + else +#endif + throw; + } + }); + }); +} diff --git a/lib/versioning.h b/lib/versioning.h new file mode 100644 index 00000000..36721edb --- /dev/null +++ b/lib/versioning.h @@ -0,0 +1,85 @@ +// ************************************************************************** +// * 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) ZenJu (zenju AT gmx DOT de) - All Rights Reserved * +// ************************************************************************** + +#ifndef VERSIONING_HEADER_8760247652438056 +#define VERSIONING_HEADER_8760247652438056 + +#include <vector> +#include <functional> +#include <zen/time.h> +#include <zen/zstring.h> +#include <zen/int64.h> +#include <zen/file_error.h> + +namespace zen +{ +struct CallbackMoveFile; + +//e.g. move C:\Source\subdir\Sample.txt -> D:\Revisions\subdir\Sample.txt 2012-05-15 131513.txt +//scheme: <revisions directory>\<relpath>\<filename>.<ext> YYYY-MM-DD HHMMSS.<ext> +/* + - ignores missing source files/dirs + - creates missing intermediate directories + - does not create empty directories + - handles symlinks + - ignores already existing target files/dirs (support retry) + => (unlikely) risk of data loss: race-condition if two FFS instances start at the very same second and process the same filename!! +*/ + +class FileVersioner +{ +public: + FileVersioner(const Zstring& versioningDirectory, //throw FileError + const TimeComp& timeStamp, + int versionCountLimit) : //max versions per file; < 0 := no limit + versioningDirectory_(versioningDirectory), + timeStamp_(formatTime<Zstring>(Zstr("%Y-%m-%d %H%M%S"), timeStamp)), //e.g. "2012-05-15 131513" + versionCountLimit_(versionCountLimit) + { + if (timeStamp_.size() != 17) //formatTime() returns empty string on error; unexpected length: e.g. problem in year 10000! + throw FileError(_("Failure to create time stamp for versioning:") + L" \'" + timeStamp_ + L"\'"); + } + + void revisionFile(const Zstring& sourceFile, const Zstring& relativeName, CallbackMoveFile& callback); //throw FileError + void revisionDir (const Zstring& sourceDir, const Zstring& relativeName, CallbackMoveFile& callback); //throw FileError + + void limitVersions(std::function<void()> updateUI); //throw FileError; call when done revisioning! + +private: + const Zstring versioningDirectory_; + const Zstring timeStamp_; + const int versionCountLimit_; + + std::vector<Zstring> fileRelnames; //store list of revisioned files and symlinks (relativeName) for limitVersions() +}; + + +struct CallbackMoveFile +{ + virtual ~CallbackMoveFile() {} //see CallbackCopyFile for limitations when throwing exceptions! + + virtual void onBeforeFileMove(const Zstring& fileFrom, const Zstring& fileTo) = 0; //one call before each (planned) move + virtual void onBeforeDirMove (const Zstring& dirFrom, const Zstring& dirTo ) = 0; // + virtual void objectProcessed() = 0; //one call after each completed move (count objects total) + + //called frequently if move has to revert to copy + delete: + virtual void updateStatus(Int64 bytesDelta) = 0; +}; + + + + + + + + +namespace impl //declare for unit tests: +{ +bool isMatchingVersion(const Zstring& shortname, const Zstring& shortnameVersion); +} +} + +#endif //VERSIONING_HEADER_8760247652438056 diff --git a/lib/xml_base.cpp b/lib/xml_base.cpp index db33059c..9aa069c7 100644 --- a/lib/xml_base.cpp +++ b/lib/xml_base.cpp @@ -1,7 +1,7 @@ // ************************************************************************** // * 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) ZenJu (zhnmju123 AT gmx DOT de) - All Rights Reserved * +// * Copyright (C) ZenJu (zenju AT gmx DOT de) - All Rights Reserved * // ************************************************************************** #include "xml_base.h" diff --git a/lib/xml_base.h b/lib/xml_base.h index b81b406d..5c0ec3c3 100644 --- a/lib/xml_base.h +++ b/lib/xml_base.h @@ -1,7 +1,7 @@ // ************************************************************************** // * 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) ZenJu (zhnmju123 AT gmx DOT de) - All Rights Reserved * +// * Copyright (C) ZenJu (zenju AT gmx DOT de) - All Rights Reserved * // ************************************************************************** #ifndef XMLBASE_H_INCLUDED |