summaryrefslogtreecommitdiff
path: root/lib
diff options
context:
space:
mode:
Diffstat (limited to 'lib')
-rw-r--r--lib/ShadowCopy/LockFile.cpp2
-rw-r--r--lib/ShadowCopy/Shadow_Server2003.vcxproj4
-rw-r--r--lib/ShadowCopy/Shadow_Windows7.vcxproj4
-rw-r--r--lib/ShadowCopy/Shadow_XP.vcxproj4
-rw-r--r--lib/ShadowCopy/dll_main.cpp2
-rw-r--r--lib/ShadowCopy/shadow.cpp2
-rw-r--r--lib/ShadowCopy/shadow.h2
-rw-r--r--lib/Thumbnail/dll_main.cpp2
-rw-r--r--lib/Thumbnail/thumbnail.cpp2
-rw-r--r--lib/Thumbnail/thumbnail.h2
-rw-r--r--lib/binary.cpp2
-rw-r--r--lib/binary.h9
-rw-r--r--lib/db_file.cpp14
-rw-r--r--lib/db_file.h2
-rw-r--r--lib/dir_exist_async.h2
-rw-r--r--lib/dir_lock.cpp4
-rw-r--r--lib/dir_lock.h2
-rw-r--r--lib/error_log.h4
-rw-r--r--lib/ffs_paths.h2
-rw-r--r--lib/generate_logfile.h28
-rw-r--r--lib/hard_filter.cpp4
-rw-r--r--lib/hard_filter.h2
-rw-r--r--lib/help_provider.h2
-rw-r--r--lib/icon_buffer.cpp2
-rw-r--r--lib/icon_buffer.h2
-rw-r--r--lib/localization.cpp4
-rw-r--r--lib/localization.h2
-rw-r--r--lib/norm_filter.h2
-rw-r--r--lib/parallel_scan.cpp8
-rw-r--r--lib/parallel_scan.h8
-rw-r--r--lib/parse_lng.h2
-rw-r--r--lib/parse_plural.h2
-rw-r--r--lib/perf_check.cpp8
-rw-r--r--lib/perf_check.h4
-rw-r--r--lib/process_xml.cpp189
-rw-r--r--lib/process_xml.h36
-rw-r--r--lib/resolve_path.cpp295
-rw-r--r--lib/resolve_path.h21
-rw-r--r--lib/resources.cpp3
-rw-r--r--lib/resources.h2
-rw-r--r--lib/return_codes.h2
-rw-r--r--lib/shadow.cpp5
-rw-r--r--lib/shadow.h4
-rw-r--r--lib/soft_filter.h2
-rw-r--r--lib/status_handler.cpp2
-rw-r--r--lib/status_handler.h2
-rw-r--r--lib/status_handler_impl.h2
-rw-r--r--lib/versioning.cpp398
-rw-r--r--lib/versioning.h85
-rw-r--r--lib/xml_base.cpp2
-rw-r--r--lib/xml_base.h2
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
bgstack15