summaryrefslogtreecommitdiff
path: root/zen
diff options
context:
space:
mode:
authorDaniel Wilhelm <daniel@wili.li>2014-04-18 17:24:09 +0200
committerDaniel Wilhelm <daniel@wili.li>2014-04-18 17:24:09 +0200
commit110fc5dee14fc7988f631a158e50d283446aba7a (patch)
tree7c19dfd3bdb8c4636409ec80a38c70499ac006db /zen
parent5.14 (diff)
downloadFreeFileSync-110fc5dee14fc7988f631a158e50d283446aba7a.tar.gz
FreeFileSync-110fc5dee14fc7988f631a158e50d283446aba7a.tar.bz2
FreeFileSync-110fc5dee14fc7988f631a158e50d283446aba7a.zip
5.15
Diffstat (limited to 'zen')
-rw-r--r--zen/FindFilePlus/find_file_plus.cpp117
-rw-r--r--zen/IFileOperation/FileOperation_Vista.vcxproj35
-rw-r--r--zen/IFileOperation/file_op.cpp28
-rw-r--r--zen/async_task.h70
-rw-r--r--zen/debug_minidump.cpp4
-rw-r--r--zen/debug_minidump.h4
-rw-r--r--zen/dir_watcher.cpp4
-rw-r--r--zen/file_handling.cpp21
-rw-r--r--zen/file_id.cpp34
-rw-r--r--zen/file_id.h12
-rw-r--r--zen/file_io.cpp2
-rw-r--r--zen/file_traverser.cpp4
-rw-r--r--zen/int64.h8
-rw-r--r--zen/long_path_prefix.h20
-rw-r--r--zen/osx_string.h2
-rw-r--r--zen/osx_throw_exception.h4
-rw-r--r--zen/scope_guard.h2
-rw-r--r--zen/stl_tools.h13
-rw-r--r--zen/string_base.h13
19 files changed, 269 insertions, 128 deletions
diff --git a/zen/FindFilePlus/find_file_plus.cpp b/zen/FindFilePlus/find_file_plus.cpp
index ec56b0bc..fdabc46f 100644
--- a/zen/FindFilePlus/find_file_plus.cpp
+++ b/zen/FindFilePlus/find_file_plus.cpp
@@ -8,9 +8,7 @@
#include "init_dll_binding.h"
//#include <windows.h> //these two don't play nice with each other
#include "load_dll.h"
-#include <zen/scope_guard.h>
#include <new>
-//#include <cstdio>
using namespace dll;
using namespace findplus;
@@ -56,15 +54,18 @@ typedef struct _RTL_RELATIVE_NAME_U
PVOID /*PRTLP_CURDIR_REF*/ CurDirRef;
} RTL_RELATIVE_NAME_U, *PRTL_RELATIVE_NAME_U;
-typedef BOOLEAN (NTAPI* RtlDosPathNameToNtPathName_UFunc)(PCWSTR, //__in dosFileName,
- PUNICODE_STRING, //__out ntFileName,
- PCWSTR*, //__out_optFilePart,
- PRTL_RELATIVE_NAME_U); //__out_opt relativeName
+typedef BOOLEAN (NTAPI* RtlDosPathNameToNtPathName_UFunc)(PCWSTR dosFileName, //__in
+ PUNICODE_STRING ntFileName, //__out
+ PCWSTR* filePart, //__out
+ PRTL_RELATIVE_NAME_U relativeName); //__out
-typedef BOOLEAN (NTAPI* RtlDosPathNameToRelativeNtPathName_UFunc)(PCWSTR, //__in dosFileName,
- PUNICODE_STRING, //__out ntFileName,
- PCWSTR*, //__out_optFilePart,
- PRTL_RELATIVE_NAME_U); //__out_opt relativeName
+typedef BOOLEAN (NTAPI* RtlDosPathNameToRelativeNtPathName_UFunc)(PCWSTR dosFileName, //__in
+ PUNICODE_STRING ntFileName, //__out
+ PCWSTR* filePart, //__out
+ PRTL_RELATIVE_NAME_U relativeName); //__out
+
+typedef BOOLEAN (NTAPI* RtlCreateUnicodeStringFunc)(PUNICODE_STRING DestinationString, //_Out_
+ PCWSTR SourceString); //_In_
typedef VOID (NTAPI* RtlFreeUnicodeStringFunc)(PUNICODE_STRING); //__inout unicodeString
@@ -76,6 +77,7 @@ const SysDllFun<NtOpenFileFunc> ntOpenFile (L"ntdll.d
const SysDllFun<NtCloseFunc> ntClose (L"ntdll.dll", "NtClose");
const SysDllFun<NtQueryDirectoryFileFunc> ntQueryDirectoryFile (L"ntdll.dll", "NtQueryDirectoryFile");
const SysDllFun<RtlNtStatusToDosErrorFunc> rtlNtStatusToDosError (L"ntdll.dll", "RtlNtStatusToDosError");
+const SysDllFun<RtlCreateUnicodeStringFunc> rtlCreateUnicodeString (L"ntdll.dll", "RtlCreateUnicodeString");
const SysDllFun<RtlFreeUnicodeStringFunc> rtlFreeUnicodeString (L"ntdll.dll", "RtlFreeUnicodeString");
const SysDllFun<RtlDosPathNameToNtPathName_UFunc> rtlDosPathNameToNtPathName_U(SysDllFun<RtlDosPathNameToRelativeNtPathName_UFunc>(L"ntdll.dll", "RtlDosPathNameToRelativeNtPathName_U") ?
SysDllFun<RtlDosPathNameToRelativeNtPathName_UFunc>(L"ntdll.dll", "RtlDosPathNameToRelativeNtPathName_U") : //use the newer version if available
@@ -93,11 +95,12 @@ bool findplus::initDllBinding() //evaluate in ::DllMain() when attaching process
//http://msdn.microsoft.com/en-us/library/ff563638(v=VS.85).aspx
//verify dynamic dll binding
- return ntOpenFile &&
- ntClose &&
- ntQueryDirectoryFile &&
- rtlNtStatusToDosError &&
- rtlFreeUnicodeString &&
+ return ntOpenFile &&
+ ntClose &&
+ ntQueryDirectoryFile &&
+ rtlNtStatusToDosError &&
+ rtlCreateUnicodeString &&
+ rtlFreeUnicodeString &&
rtlDosPathNameToNtPathName_U;
//this may become handy some time: nt status code STATUS_ORDINAL_NOT_FOUND maps to win32 code ERROR_INVALID_ORDINAL
@@ -128,43 +131,89 @@ private:
};
+//a simple scope guard without <utility>, <type_traits>, <cassert> dependencies:
+template <typename F>
+class ScopeGuardLean
+{
+public:
+ explicit ScopeGuardLean(F fun) : dismissed_(false), fun_(fun) {}
+ ScopeGuardLean(ScopeGuardLean&& other) : dismissed_(other.dismissed_), fun_(std::move(other.fun_)) { other.dismiss(); }
+
+ void dismiss() { dismissed_ = true; }
+
+ ~ScopeGuardLean()
+ {
+ if (!dismissed_)
+ try { fun_(); }
+ catch (...) {}
+ }
+
+private:
+ ScopeGuardLean (const ScopeGuardLean&); // = delete
+ ScopeGuardLean& operator=(const ScopeGuardLean&); //
+
+ bool dismissed_;
+ F fun_;
+};
+
+template <class F> inline
+ScopeGuardLean<F> makeGuard(F fun) { return ScopeGuardLean<F>(fun); }
+
+
FileSearcher::FileSearcher(const wchar_t* dirname) :
+ dirnameNt(), //[!]
hDir(nullptr),
nextEntryOffset(0)
{
- dirnameNt.Buffer = nullptr;
- dirnameNt.Length = 0;
- dirnameNt.MaximumLength = 0;
-
- zen::ScopeGuard guardConstructor = zen::makeGuard([&] { this->~FileSearcher(); });
+ auto guardConstructor = makeGuard([&] { this->~FileSearcher(); });
//--------------------------------------------------------------------------------------------------------------
//convert dosFileName, e.g. C:\Users or \\?\C:\Users to ntFileName \??\C:\Users
//in contrast to ::FindFirstFile() implementation we don't evaluate the relativeName,
//however tests indicate ntFileName is *always* filled with an absolute name, even if dosFileName is relative
+ PCWSTR filePart = nullptr;
+ RTL_RELATIVE_NAME_U relativeName = {};
+
//NOTE: RtlDosPathNameToNtPathName_U may be used on all XP/Win7/Win8 for compatibility
// RtlDosPathNameToNtPathName_U: used by Windows XP available with OS version 3.51 (Windows NT) and higher
// RtlDosPathNameToRelativeNtPathName_U: used by Win7/Win8 available with OS version 5.2 (Windows Server 2003) and higher
- if (!rtlDosPathNameToNtPathName_U(dirname, //__in dosFileName,
- &dirnameNt, //__out ntFileName,
- nullptr, //__out_optFilePart,
- nullptr)) //__out_opt relativeName - empty if dosFileName is absolute
+ if (!rtlDosPathNameToNtPathName_U(dirname, //__in dosFileName,
+ &dirnameNt, //__out ntFileName,
+ &filePart, //__out FilePart - points into ntFileName
+ &relativeName)) //__out relativeName - points into ntFileName; empty if dosFileName is absolute
throw NtFileError(STATUS_OBJECT_PATH_NOT_FOUND); //translates to ERROR_PATH_NOT_FOUND, same behavior like ::FindFirstFileEx()
+ //note 1: internally it distinguishes between "quick path" == \\?\ and "slow path" handling!
+ //http://doxygen.reactos.org/d9/d6e/lib_2rtl_2path_8c_a11c87ad0f7752999b0b8972af6165d7a.html#a11c87ad0f7752999b0b8972af6165d7a
+ //note 2: without \\?\, i.e. slow path handling it calls RtlGetFullPathName_Ustr() which removes trailing spaces!!!
+ //http://doxygen.reactos.org/d9/d6e/lib_2rtl_2path_8c_a8624b864678ca64b031f5fc273e022af.html#a8624b864678ca64b031f5fc273e022af
+ //FindFirstFile() gets lucky because it passes "<dirname>\*" which never has trailing space chars! >:(
OBJECT_ATTRIBUTES objAttr = {};
- InitializeObjectAttributes(&objAttr, //[out] POBJECT_ATTRIBUTES initializedAttributes,
- &dirnameNt, //[in] PUNICODE_STRING objectName,
- OBJ_CASE_INSENSITIVE, //[in] ULONG attributes,
- nullptr, //[in] HANDLE rootDirectory,
- nullptr); //[in, optional] PSECURITY_DESCRIPTOR securityDescriptor
+ if (relativeName.RelativeName.Length == 0) //absolute name
+ {
+ InitializeObjectAttributes(&objAttr, //[out] POBJECT_ATTRIBUTES initializedAttributes,
+ &dirnameNt, //[in] PUNICODE_STRING objectName,
+ OBJ_CASE_INSENSITIVE, //[in] ULONG attributes,
+ nullptr, //[in] HANDLE rootDirectory,
+ nullptr); //[in, optional] PSECURITY_DESCRIPTOR securityDescriptor
+ }
+ else //relative name (it seems we alternatively could also use dirnameNt here?)
+ {
+ InitializeObjectAttributes(&objAttr, //[out] POBJECT_ATTRIBUTES initializedAttributes,
+ &relativeName.RelativeName, //[in] PUNICODE_STRING objectName,
+ OBJ_CASE_INSENSITIVE, //[in] ULONG attributes,
+ relativeName.ContainingDirectory, //[in] HANDLE rootDirectory,
+ nullptr); //[in, optional] PSECURITY_DESCRIPTOR securityDescriptor
+ }
+
{
IO_STATUS_BLOCK status = {};
- NTSTATUS rv = ntOpenFile(&hDir, //__out PHANDLE FileHandle,
+ NTSTATUS rv = ntOpenFile(&hDir, //__out PHANDLE FileHandle,
FILE_LIST_DIRECTORY | SYNCHRONIZE, //__in ACCESS_MASK desiredAccess, - 100001 used by ::FindFirstFile() on all XP/Win7/Win8
- &objAttr, //__in POBJECT_ATTRIBUTES objectAttributes,
- &status, //__out PIO_STATUS_BLOCK ioStatusBlock,
+ &objAttr, //__in POBJECT_ATTRIBUTES objectAttributes,
+ &status, //__out PIO_STATUS_BLOCK ioStatusBlock,
FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, //__in ULONG shareAccess, - 7 on Win7/Win8, 3 on XP
FILE_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT | FILE_OPEN_FOR_BACKUP_INTENT); //__in ULONG openOptions - 4021 used on all XP/Win7/Win8
if (!NT_SUCCESS(rv))
@@ -184,7 +233,7 @@ FileSearcher::~FileSearcher()
if (dirnameNt.Buffer)
rtlFreeUnicodeString(&dirnameNt); //cleanup identical to ::FindFirstFile()
- //note that most of this function seems inlined by the linker, so that its assembly looks equivalent to "RtlFreeHeap(GetProcessHeap(), 0, ntPathName.Buffer)"
+ //note that most of this function seems inlined by the linker, so that its assembly looks equivalent to "RtlFreeHeap(RtlGetProcessHeap(), 0, ntPathName.Buffer)"
}
@@ -364,7 +413,7 @@ FindHandle findplus::openDir(const wchar_t* dirname)
setWin32Error(rtlNtStatusToDosError(e.ntError));
return nullptr;
}
- catch (const std::bad_alloc&) //not unlikely in this context! => handle!
+ catch (const std::bad_alloc&) //not unlikely in file sync context! => handle!
{
setWin32Error(rtlNtStatusToDosError(STATUS_NO_MEMORY));
return nullptr;
diff --git a/zen/IFileOperation/FileOperation_Vista.vcxproj b/zen/IFileOperation/FileOperation_Vista.vcxproj
index 73bfd56a..4694a3a5 100644
--- a/zen/IFileOperation/FileOperation_Vista.vcxproj
+++ b/zen/IFileOperation/FileOperation_Vista.vcxproj
@@ -88,7 +88,7 @@
</BuildLog>
<ClCompile>
<Optimization>Disabled</Optimization>
- <PreprocessorDefinitions>_DEBUG;_WINDOWS;_USRDLL;FILE_OP_DLL_EXPORTS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <PreprocessorDefinitions>WXINTL_NO_GETTEXT_MACRO;FFS_WIN;_DEBUG;_WINDOWS;_USRDLL;FILE_OP_DLL_EXPORTS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<MinimalRebuild>true</MinimalRebuild>
<BasicRuntimeChecks>EnableFastChecks</BasicRuntimeChecks>
<RuntimeLibrary>MultiThreadedDebugDLL</RuntimeLibrary>
@@ -97,7 +97,7 @@
<WarningLevel>Level4</WarningLevel>
<SuppressStartupBanner>true</SuppressStartupBanner>
<DebugInformationFormat>EditAndContinue</DebugInformationFormat>
- <DisableSpecificWarnings>4100;4996</DisableSpecificWarnings>
+ <DisableSpecificWarnings>4100;4996;4512</DisableSpecificWarnings>
<AdditionalIncludeDirectories>../..;C:\Program Files\C++\boost</AdditionalIncludeDirectories>
<SmallerTypeCheck>true</SmallerTypeCheck>
</ClCompile>
@@ -124,7 +124,7 @@
</Midl>
<ClCompile>
<Optimization>Disabled</Optimization>
- <PreprocessorDefinitions>_DEBUG;_WINDOWS;_USRDLL;FILE_OP_DLL_EXPORTS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <PreprocessorDefinitions>WXINTL_NO_GETTEXT_MACRO;FFS_WIN;_DEBUG;_WINDOWS;_USRDLL;FILE_OP_DLL_EXPORTS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<MinimalRebuild>true</MinimalRebuild>
<BasicRuntimeChecks>EnableFastChecks</BasicRuntimeChecks>
<RuntimeLibrary>MultiThreadedDebugDLL</RuntimeLibrary>
@@ -133,7 +133,7 @@
<WarningLevel>Level4</WarningLevel>
<SuppressStartupBanner>true</SuppressStartupBanner>
<DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
- <DisableSpecificWarnings>4100;4996</DisableSpecificWarnings>
+ <DisableSpecificWarnings>4100;4996;4512</DisableSpecificWarnings>
<AdditionalIncludeDirectories>../..;C:\Program Files\C++\boost</AdditionalIncludeDirectories>
<SmallerTypeCheck>true</SmallerTypeCheck>
</ClCompile>
@@ -158,7 +158,7 @@
<ClCompile>
<Optimization>MaxSpeed</Optimization>
<IntrinsicFunctions>true</IntrinsicFunctions>
- <PreprocessorDefinitions>NDEBUG;_WINDOWS;_USRDLL;FILE_OP_DLL_EXPORTS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <PreprocessorDefinitions>WXINTL_NO_GETTEXT_MACRO;FFS_WIN;NDEBUG;_WINDOWS;_USRDLL;FILE_OP_DLL_EXPORTS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>
<FunctionLevelLinking>true</FunctionLevelLinking>
<PrecompiledHeader>
@@ -167,7 +167,7 @@
<SuppressStartupBanner>true</SuppressStartupBanner>
<DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
<FavorSizeOrSpeed>Speed</FavorSizeOrSpeed>
- <DisableSpecificWarnings>4100;4996</DisableSpecificWarnings>
+ <DisableSpecificWarnings>4100;4996;4512</DisableSpecificWarnings>
<AdditionalIncludeDirectories>../..;C:\Program Files\C++\boost</AdditionalIncludeDirectories>
</ClCompile>
<Link>
@@ -196,7 +196,7 @@
<ClCompile>
<Optimization>MaxSpeed</Optimization>
<IntrinsicFunctions>true</IntrinsicFunctions>
- <PreprocessorDefinitions>NDEBUG;_WINDOWS;_USRDLL;FILE_OP_DLL_EXPORTS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <PreprocessorDefinitions>WXINTL_NO_GETTEXT_MACRO;FFS_WIN;NDEBUG;_WINDOWS;_USRDLL;FILE_OP_DLL_EXPORTS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>
<FunctionLevelLinking>true</FunctionLevelLinking>
<PrecompiledHeader>
@@ -205,7 +205,7 @@
<SuppressStartupBanner>true</SuppressStartupBanner>
<DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
<FavorSizeOrSpeed>Speed</FavorSizeOrSpeed>
- <DisableSpecificWarnings>4100;4996</DisableSpecificWarnings>
+ <DisableSpecificWarnings>4100;4996;4512</DisableSpecificWarnings>
<AdditionalIncludeDirectories>../..;C:\Program Files\C++\boost</AdditionalIncludeDirectories>
</ClCompile>
<Link>
@@ -226,20 +226,11 @@
</ItemDefinitionGroup>
<ItemGroup>
<ClCompile Include="..\debug_memory_leaks.cpp" />
- <ClCompile Include="dll_main.cpp">
- <PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
- </PrecompiledHeader>
- <CompileAsManaged Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">false</CompileAsManaged>
- <PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
- </PrecompiledHeader>
- <CompileAsManaged Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">false</CompileAsManaged>
- <PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
- </PrecompiledHeader>
- <CompileAsManaged Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">false</CompileAsManaged>
- <PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
- </PrecompiledHeader>
- <CompileAsManaged Condition="'$(Configuration)|$(Platform)'=='Release|x64'">false</CompileAsManaged>
- </ClCompile>
+ <ClCompile Include="..\dst_hack.cpp" />
+ <ClCompile Include="..\file_handling.cpp" />
+ <ClCompile Include="..\file_traverser.cpp" />
+ <ClCompile Include="..\privilege.cpp" />
+ <ClCompile Include="..\zstring.cpp" />
<ClCompile Include="file_op.cpp" />
</ItemGroup>
<ItemGroup>
diff --git a/zen/IFileOperation/file_op.cpp b/zen/IFileOperation/file_op.cpp
index b3990ee0..8816b502 100644
--- a/zen/IFileOperation/file_op.cpp
+++ b/zen/IFileOperation/file_op.cpp
@@ -14,6 +14,7 @@
#include <zen/com_error.h>
#include <zen/scope_guard.h>
#include <zen/stl_tools.h>
+#include <zen/file_handling.h>
#include <boost/thread/tss.hpp>
@@ -98,12 +99,18 @@ public:
if (psiItem)
{
LPWSTR itemPath = nullptr;
- HRESULT hr = psiItem->GetDisplayName(SIGDN_FILESYSPATH, &itemPath);
- if (FAILED(hr))
- return hr;
- ZEN_ON_SCOPE_EXIT(::CoTaskMemFree(itemPath));
-
- currentItem = itemPath;
+ if (SUCCEEDED(psiItem->GetDisplayName(SIGDN_FILESYSPATH, &itemPath))) //will fail for long file paths > MAX_PATH!
+ {
+ ZEN_ON_SCOPE_EXIT(::CoTaskMemFree(itemPath));
+ currentItem = itemPath;
+ }
+ else if (SUCCEEDED(psiItem->GetDisplayName(SIGDN_NORMALDISPLAY, &itemPath))) //short name only; should work even for long file paths!
+ {
+ ZEN_ON_SCOPE_EXIT(::CoTaskMemFree(itemPath));
+ currentItem = itemPath;
+ }
+ else
+ currentItem = L"<unknown file>"; //give some indication that file name determination failed (rather than leaving the name empty!)
}
//"Returns S_OK if successful, or an error value otherwise. In the case of an error value, the delete operation
//and all subsequent operations pending from the call to IFileOperation are canceled."
@@ -222,7 +229,12 @@ void moveToRecycleBin(const wchar_t* fileNames[], //throw ComError
{
if (hr == HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND) || //file not existing anymore
hr == HRESULT_FROM_WIN32(ERROR_PATH_NOT_FOUND))
- continue;
+ {
+ //make sure the file really is not there: Win32 by default strips trailing spaces, so we might end up here in error!
+ //on the other hand, shell layer does not support \\?\ prefix to prevent this!
+ if (!somethingExists(fileNames[i]))
+ continue;
+ }
throw ComError(std::wstring(L"Error calling \"SHCreateItemFromParsingName\" for file:\n") + L"\'" + fileNames[i] + L"\'.", hr);
}
@@ -231,7 +243,7 @@ void moveToRecycleBin(const wchar_t* fileNames[], //throw ComError
++operationCount;
}
- if (operationCount == 0) //calling PerformOperations() without anything to do would yielt E_UNEXPECTED
+ if (operationCount == 0) //calling PerformOperations() without anything to do would yield E_UNEXPECTED
return;
//perform planned operations
diff --git a/zen/async_task.h b/zen/async_task.h
new file mode 100644
index 00000000..b4123b5d
--- /dev/null
+++ b/zen/async_task.h
@@ -0,0 +1,70 @@
+// **************************************************************************
+// * 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 ASYNC_JOB_839147839170432143214321
+#define ASYNC_JOB_839147839170432143214321
+
+#include <list>
+#include <functional>
+#include <zen/thread.h>
+#include <zen/scope_guard.h>
+
+namespace zen
+{
+//run a job in an async thread, but process result on GUI event loop
+class AsyncTasks
+{
+public:
+ AsyncTasks() : inRecursion(false) {}
+
+ template <class Fun, class Fun2>
+ void add(Fun doAsync, Fun2 evalOnGui)
+ //equivalent to "evalOnGui(doAsync())"
+ // -> doAsync: the usual thread-safety requirements apply!
+ // -> evalOnGui: no thread-safety concerns, but must only reference variables with greater-equal lifetime than the AsyncTask instance!
+ {
+ tasks.push_back(zen::async([=]() -> std::function<void()>
+ {
+ auto result = doAsync();
+ return [=]{ evalOnGui(result); };
+ }));
+ }
+
+ template <class Fun, class Fun2>
+ void add2(Fun doAsync, Fun2 evalOnGui) //for doAsync returning void
+ {
+ tasks.push_back(zen::async([=]() -> std::function<void()> { doAsync(); return [=]{ evalOnGui(); }; }));
+ }
+
+ void evalResults() //call from gui thread repreatedly
+ {
+ if (!inRecursion) //prevent implicit recursion, e.g. if we're called from an idle event and spawn another one via the callback below
+ {
+ inRecursion = true;
+ ZEN_ON_SCOPE_EXIT(inRecursion = false);
+
+ tasks.remove_if([](boost::unique_future<std::function<void()>>& ft) -> bool
+ {
+ if (ft.is_ready())
+ {
+ (ft.get())();
+ return true;
+ }
+ return false;
+ });
+ }
+ }
+
+ bool empty() const { return tasks.empty(); }
+
+private:
+ bool inRecursion;
+ std::list<boost::unique_future<std::function<void()>>> tasks;
+};
+
+}
+
+#endif //ASYNC_JOB_839147839170432143214321
diff --git a/zen/debug_minidump.cpp b/zen/debug_minidump.cpp
index c229b4aa..1b625015 100644
--- a/zen/debug_minidump.cpp
+++ b/zen/debug_minidump.cpp
@@ -55,7 +55,9 @@ void debug_tools::writeMinidump()
{
::RaiseException(EXCEPTION_BREAKPOINT, 0, 0, nullptr);
}
- __except (writeDumpOnException(GetExceptionInformation()), EXCEPTION_CONTINUE_EXECUTION) {}
+ __except (writeDumpOnException(GetExceptionInformation()), EXCEPTION_EXECUTE_HANDLER) {}
+ //don't use EXCEPTION_CONTINUE_EXECUTION: although used in most minidump examples this resulted in an infinite loop in tests
+ //although it really should not: http://msdn.microsoft.com/en-us/library/c34eyfac.aspx
}
diff --git a/zen/debug_minidump.h b/zen/debug_minidump.h
index 2ef43039..e2605038 100644
--- a/zen/debug_minidump.h
+++ b/zen/debug_minidump.h
@@ -21,11 +21,11 @@ Minidumps http://msdn.microsoft.com/en-us/library/windows/desktop/ee416349(v=vs.
----------------------------------------------------------------------------------------
1. Compile "debug_minidump.cpp"
2. Compile "release" build with:
- - C/C++ -> General: Debug Information Format: "Program Database" (/Zi).
- - C/C++ -> Optimization: Omit Frame Pointers: No (/Oy-) - avoid call stack mess up!
- Linker -> Debugging: Generate Debug Info: Yes (/DEBUG)
- Linker -> Optimization: References: Yes (/OPT:REF).
- Linker -> Optimization: Enable COMDAT Folding: Yes (/OPT:ICF).
+ - C/C++ -> General: Debug Information Format: "Program Database" (/Zi).
+ - C/C++ -> Optimization: Omit Frame Pointers: No (/Oy-) - avoid call stack mess up!
Optional:
- C/C++ -> Optimization: Disabled (/Od)
*/
diff --git a/zen/dir_watcher.cpp b/zen/dir_watcher.cpp
index 0b34f890..6c6c0929 100644
--- a/zen/dir_watcher.cpp
+++ b/zen/dir_watcher.cpp
@@ -188,6 +188,8 @@ public:
ZEN_ON_SCOPE_EXIT(::CloseHandle(overlapped.hEvent));
+ DWORD bytesReturned = 0; //should not be needed for async calls, still pass it to help broken drivers
+
//asynchronous variant: runs on this thread's APC queue!
if (!::ReadDirectoryChangesW(hDir, // __in HANDLE hDirectory,
&buffer[0], // __out LPVOID lpBuffer,
@@ -197,7 +199,7 @@ public:
FILE_NOTIFY_CHANGE_DIR_NAME |
FILE_NOTIFY_CHANGE_SIZE |
FILE_NOTIFY_CHANGE_LAST_WRITE, // __in DWORD dwNotifyFilter,
- nullptr, // __out_opt LPDWORD lpBytesReturned,
+ &bytesReturned, // __out_opt LPDWORD lpBytesReturned,
&overlapped, // __inout_opt LPOVERLAPPED lpOverlapped,
nullptr)) // __in_opt LPOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine
return shared_->reportError(replaceCpy(_("Cannot monitor directory %x."), L"%x", fmtFileName(dirnamePf)) + L" (ReadDirectoryChangesW)" L"\n\n" + getLastErrorFormatted(), ::GetLastError());
diff --git a/zen/file_handling.cpp b/zen/file_handling.cpp
index 3565700a..b529720f 100644
--- a/zen/file_handling.cpp
+++ b/zen/file_handling.cpp
@@ -35,12 +35,12 @@
#elif defined FFS_MAC
#include <sys/mount.h> //statfs
-#include <utime.h>
+//#include <utime.h>
#endif
#if defined FFS_LINUX || defined FFS_MAC
#include <sys/stat.h>
-//#include <sys/time.h>
+#include <sys/time.h> //lutimes
#endif
using namespace zen;
@@ -933,15 +933,18 @@ void zen::setFileTime(const Zstring& filename, const Int64& modTime, ProcSymlink
}
#endif
-#elif defined FFS_LINUX
- struct ::timespec newTimes[2] = {};
- newTimes[0].tv_nsec = UTIME_OMIT; //omit access time
- newTimes[1].tv_sec = to<time_t>(modTime); //modification time (seconds)
+#elif defined FFS_LINUX || defined FFS_MAC
+ //sigh, we can't use utimensat on NTFS volumes on Ubuntu: silent failure!!! what morons are programming this shit???
- if (::utimensat(AT_FDCWD, filename.c_str(), newTimes, procSl == SYMLINK_DIRECT ? AT_SYMLINK_NOFOLLOW : 0) != 0)
- throw FileError(replaceCpy(_("Cannot write modification time of %x."), L"%x", fmtFileName(filename)) + L"\n\n" + getLastErrorFormatted());
+ // struct ::timespec newTimes[2] = {};
+ // newTimes[0].tv_nsec = UTIME_OMIT; //omit access time
+ // newTimes[1].tv_sec = to<time_t>(modTime); //modification time (seconds)
+ //
+ // if (::utimensat(AT_FDCWD, filename.c_str(), newTimes, procSl == SYMLINK_DIRECT ? AT_SYMLINK_NOFOLLOW : 0) != 0)
+ // throw FileError(replaceCpy(_("Cannot write modification time of %x."), L"%x", fmtFileName(filename)) + L"\n\n" + getLastErrorFormatted());
+
+ //=> fallback to "retarded-idiot version"! -- DarkByte
-#elif defined FFS_MAC
struct ::timeval newTimes[2] = {};
newTimes[0].tv_sec = ::time(nullptr); //access time (seconds)
newTimes[1].tv_sec = to<time_t>(modTime); //modification time (seconds)
diff --git a/zen/file_id.cpp b/zen/file_id.cpp
index 7e0fa81b..8c66d1c9 100644
--- a/zen/file_id.cpp
+++ b/zen/file_id.cpp
@@ -19,9 +19,7 @@
zen::FileId zen::getFileID(const Zstring& filename)
{
#ifdef FFS_WIN
- //WARNING: CreateFile() is SLOW, while GetFileInformationByHandle() is cheap!
- //http://msdn.microsoft.com/en-us/library/aa363788(VS.85).aspx
-
+ //WARNING: CreateFile() is SLOW, while GetFileInformationByHandle() is cheap! http://msdn.microsoft.com/en-us/library/aa363788(VS.85).aspx
//privilege SE_BACKUP_NAME doesn't seem to be required here at all
const HANDLE hFile = ::CreateFile(zen::applyLongPathPrefix(filename).c_str(),
@@ -49,17 +47,19 @@ zen::FileId zen::getFileID(const Zstring& filename)
return zen::FileId();
}
-
-bool zen::samePhysicalFile(const Zstring& file1, const Zstring& file2)
-{
- if (EqualFilename()(file1, file2)) //quick check
- return true;
-
- const auto id1 = getFileID(file1);
- const auto id2 = getFileID(file2);
-
- if (id1 == zen::FileId() || id2 == zen::FileId())
- return false;
-
- return id1 == id2;
-}
+//test whether two distinct paths point to the same file or directory:
+// true: paths point to same files/dirs
+// false: error occurred OR point to different files/dirs
+//bool zen::samePhysicalFile(const Zstring& file1, const Zstring& file2)
+//{
+// if (EqualFilename()(file1, file2)) //quick check
+// return true;
+//
+// const auto id1 = getFileID(file1);
+// const auto id2 = getFileID(file2);
+//
+// if (id1 == zen::FileId() || id2 == zen::FileId())
+// return false;
+//
+// return id1 == id2;
+//}
diff --git a/zen/file_id.h b/zen/file_id.h
index 9f73a29b..0ff6d7ec 100644
--- a/zen/file_id.h
+++ b/zen/file_id.h
@@ -4,12 +4,11 @@
// * Copyright (C) Zenju (zenju AT gmx DOT de) - All Rights Reserved *
// **************************************************************************
-#ifndef FILEID_H_INCLUDED
-#define FILEID_H_INCLUDED
+#ifndef FILEID_H_INCLUDED_32q87634289562345
+#define FILEID_H_INCLUDED_32q87634289562345
#include "file_id_def.h"
#include "zstring.h"
-#include <string>
//unique file identifier
@@ -18,11 +17,6 @@ namespace zen
//get unique file id (symbolic link handling: opens the link!!!)
//returns initial FileId() on error!
FileId getFileID(const Zstring& filename);
-
-//test whether two distinct paths point to the same file or directory:
-// true: paths point to same files/dirs
-// false: error occurred OR point to different files/dirs
-bool samePhysicalFile(const Zstring& file1, const Zstring& file2);
}
-#endif // FILEID_H_INCLUDED
+#endif //FILEID_H_INCLUDED_32q87634289562345
diff --git a/zen/file_io.cpp b/zen/file_io.cpp
index 6581dfbe..4961cac9 100644
--- a/zen/file_io.cpp
+++ b/zen/file_io.cpp
@@ -291,7 +291,7 @@ FileOutput::~FileOutput()
void FileOutput::write(const void* buffer, size_t bytesToWrite) //throw FileError
{
#ifdef FFS_WIN
- DWORD bytesWritten = 0;
+ DWORD bytesWritten = 0; //this parameter is NOT optional: http://blogs.msdn.com/b/oldnewthing/archive/2013/04/04/10407417.aspx
if (!::WriteFile(fileHandle, //__in HANDLE hFile,
buffer, //__out LPVOID lpBuffer,
static_cast<DWORD>(bytesToWrite), //__in DWORD nNumberOfBytesToWrite,
diff --git a/zen/file_traverser.cpp b/zen/file_traverser.cpp
index 7093c44a..84bd6c64 100644
--- a/zen/file_traverser.cpp
+++ b/zen/file_traverser.cpp
@@ -566,8 +566,8 @@ private:
#ifdef FFS_MAC
//some file system abstraction layers fail to properly return decomposed UTF8: http://developer.apple.com/library/mac/#qa/qa1173/_index.html
//so we need to do it ourselves; perf: ~600 ns per conversion
- //note: it's not sufficient to apply this in z_impl::compareFilenamesNoCase: if UTF8 forms differ, FFS assumes a rename in case sensitivity and
- // will try to propagate the rename => this won't work if target drive reports a particular UTF8 form only!
+ //note: it's not sufficient to apply this in z_impl::compareFilenamesNoCase: if UTF8 forms differ, FFS assumes a rename in case sensitivity and
+ // will try to propagate the rename => this won't work if target drive reports a particular UTF8 form only!
if (CFStringRef cfStr = osx::createCFString(shortName))
{
ZEN_ON_SCOPE_EXIT(::CFRelease(cfStr));
diff --git a/zen/int64.h b/zen/int64.h
index 3e967df8..a760d5ab 100644
--- a/zen/int64.h
+++ b/zen/int64.h
@@ -52,11 +52,11 @@ public:
Int64() : value(0) {}
Int64(const Int64& rhs) : value(rhs.value) {}
template <class T>
- Int64(T rhs, typename EnableIf<IsSignedInt<T>::value && sizeof(T) <= sizeof(std::int64_t)>::Type* = nullptr) :
+ Int64(T rhs, typename EnableIf<IsSignedInt<T>::value&& sizeof(T) <= sizeof(std::int64_t)>::Type* = nullptr) :
value(static_cast<std::int64_t>(rhs)) {}
//unsafe explicit but checked conversion for all other integer types
- template <class T> explicit Int64(T rhs, typename EnableIf<!(IsSignedInt<T>::value && sizeof(T) <= sizeof(std::int64_t))>::Type* = nullptr) :
+ template <class T> explicit Int64(T rhs, typename EnableIf<!(IsSignedInt<T>::value&& sizeof(T) <= sizeof(std::int64_t))>::Type* = nullptr) :
value(static_cast<std::int64_t>(rhs)) { checkRange<std::int64_t>(rhs); }
Int64& operator=(const Int64& rhs) { value = rhs.value; return *this; }
@@ -131,11 +131,11 @@ public:
UInt64() : value(0) {}
UInt64(const UInt64& rhs) : value(rhs.value) {}
template <class T>
- UInt64(T rhs, typename EnableIf<IsUnsignedInt<T>::value && sizeof(T) <= sizeof(std::uint64_t)>::Type* = nullptr) :
+ UInt64(T rhs, typename EnableIf<IsUnsignedInt<T>::value&& sizeof(T) <= sizeof(std::uint64_t)>::Type* = nullptr) :
value(static_cast<std::uint64_t>(rhs)) {}
//unsafe explicit but checked conversion for all other integer types
- template <class T> explicit UInt64(T rhs, typename EnableIf<!(IsUnsignedInt<T>::value && sizeof(T) <= sizeof(std::uint64_t))>::Type* = nullptr) :
+ template <class T> explicit UInt64(T rhs, typename EnableIf<!(IsUnsignedInt<T>::value&& sizeof(T) <= sizeof(std::uint64_t))>::Type* = nullptr) :
value(static_cast<std::uint64_t>(rhs)) { checkRange<std::uint64_t>(rhs); }
UInt64& operator=(const UInt64& rhs) { value = rhs.value; return *this; }
diff --git a/zen/long_path_prefix.h b/zen/long_path_prefix.h
index 80b5453e..c3d705e2 100644
--- a/zen/long_path_prefix.h
+++ b/zen/long_path_prefix.h
@@ -51,20 +51,22 @@ Zstring removeLongPathPrefix(const Zstring& path); //throw()
const Zstring LONG_PATH_PREFIX = L"\\\\?\\";
const Zstring LONG_PATH_PREFIX_UNC = L"\\\\?\\UNC";
-template <size_t max_path> inline
+template <size_t maxPath> inline
Zstring applyLongPathPrefixImpl(const Zstring& path)
{
assert(!path.empty()); //nicely check almost all WinAPI accesses!
assert(!zen::isWhiteSpace(path[0]));
- if (path.length() >= max_path && //maximum allowed path length without prefix is (MAX_PATH - 1)
- !zen::startsWith(path, LONG_PATH_PREFIX))
- {
- if (zen::startsWith(path, L"\\\\")) //UNC-name, e.g. \\zenju-pc\Users
- return LONG_PATH_PREFIX_UNC + zen::afterFirst(path, L'\\'); //convert to \\?\UNC\zenju-pc\Users
- else
- return LONG_PATH_PREFIX + path; //prepend \\?\ prefix
- }
+ if (path.length() >= maxPath || //maximum allowed path length without prefix is (MAX_PATH - 1)
+ endsWith(path, L' ') || //by default all Win32 APIs trim trailing spaces and period, unless long path prefix is supplied!
+ endsWith(path, L'.')) //
+ if (!startsWith(path, LONG_PATH_PREFIX))
+ {
+ if (startsWith(path, L"\\\\")) //UNC-name, e.g. \\zenju-pc\Users
+ return LONG_PATH_PREFIX_UNC + afterFirst(path, L'\\'); //convert to \\?\UNC\zenju-pc\Users
+ else
+ return LONG_PATH_PREFIX + path; //prepend \\?\ prefix
+ }
return path; //fallback
}
diff --git a/zen/osx_string.h b/zen/osx_string.h
index a5c0849e..ce8b1062 100644
--- a/zen/osx_string.h
+++ b/zen/osx_string.h
@@ -35,7 +35,7 @@ Zstring cfStringToZstring(const CFStringRef& cfStr)
{
if (cfStr)
{
- //perf: try to get away cheap:
+ //perf: try to get away cheap:
if (const char* utf8Str = ::CFStringGetCStringPtr(cfStr, kCFStringEncodingUTF8))
return utf8Str;
diff --git a/zen/osx_throw_exception.h b/zen/osx_throw_exception.h
index cb458974..31592854 100644
--- a/zen/osx_throw_exception.h
+++ b/zen/osx_throw_exception.h
@@ -35,9 +35,9 @@ inline
void throwOsxError(NSException* e) //throw OsxError
{
std::string msg;
- if (const char* name = [[e name ] cStringUsingEncoding:NSUTF8StringEncoding]) //"const char*" NOT owned by us!
+if (const char* name = [[e name ] cStringUsingEncoding:NSUTF8StringEncoding]) //"const char*" NOT owned by us!
msg += name;
- if (const char* descr = [[e reason] cStringUsingEncoding:NSUTF8StringEncoding])
+if (const char* descr = [[e reason] cStringUsingEncoding:NSUTF8StringEncoding])
{
msg += "\n";
msg += descr;
diff --git a/zen/scope_guard.h b/zen/scope_guard.h
index ca05d39d..cb28904f 100644
--- a/zen/scope_guard.h
+++ b/zen/scope_guard.h
@@ -8,6 +8,8 @@
#define ZEN_SCOPEGUARD_8971632487321434
#include <cassert>
+//#include <type_traits> //std::decay
+//#include <utility>
//best of Zen, Loki and C++11
diff --git a/zen/stl_tools.h b/zen/stl_tools.h
index 52f9f916..07fc31d7 100644
--- a/zen/stl_tools.h
+++ b/zen/stl_tools.h
@@ -175,12 +175,13 @@ template <class K, class V> class hash_map : public std::unordered_map<K, V> {};
#endif
//as long as variadic templates are not available in MSVC
-template<class T> inline std::unique_ptr<T> make_unique() { return std::unique_ptr<T>(new T); }
-template<class T, class Arg1> inline std::unique_ptr<T> make_unique(Arg1&& arg1) { return std::unique_ptr<T>(new T(std::forward<Arg1>(arg1))); }
-template<class T, class Arg1, class Arg2> inline std::unique_ptr<T> make_unique(Arg1&& arg1, Arg2&& arg2) { return std::unique_ptr<T>(new T(std::forward<Arg1>(arg1), std::forward<Arg2>(arg2))); }
-template<class T, class Arg1, class Arg2, class Arg3> inline std::unique_ptr<T> make_unique(Arg1&& arg1, Arg2&& arg2, Arg3&& arg3) { return std::unique_ptr<T>(new T(std::forward<Arg1>(arg1), std::forward<Arg2>(arg2), std::forward<Arg3>(arg3))); }
-template<class T, class Arg1, class Arg2, class Arg3, class Arg4> inline std::unique_ptr<T> make_unique(Arg1&& arg1, Arg2&& arg2, Arg3&& arg3, Arg4&& arg4) { return std::unique_ptr<T>(new T(std::forward<Arg1>(arg1), std::forward<Arg2>(arg2), std::forward<Arg3>(arg3), std::forward<Arg4>(arg4))); }
-template<class T, class Arg1, class Arg2, class Arg3, class Arg4, class Arg5> inline std::unique_ptr<T> make_unique(Arg1&& arg1, Arg2&& arg2, Arg3&& arg3, Arg4&& arg4, Arg5&& arg5) { return std::unique_ptr<T>(new T(std::forward<Arg1>(arg1), std::forward<Arg2>(arg2), std::forward<Arg3>(arg3), std::forward<Arg4>(arg4), std::forward<Arg5>(arg5))); }
+template<class T> inline std::unique_ptr<T> make_unique() { return std::unique_ptr<T>(new T); }
+template<class T, class Arg1> inline std::unique_ptr<T> make_unique(Arg1&& arg1) { return std::unique_ptr<T>(new T(std::forward<Arg1>(arg1))); }
+template<class T, class Arg1, class Arg2> inline std::unique_ptr<T> make_unique(Arg1&& arg1, Arg2&& arg2) { return std::unique_ptr<T>(new T(std::forward<Arg1>(arg1), std::forward<Arg2>(arg2))); }
+template<class T, class Arg1, class Arg2, class Arg3> inline std::unique_ptr<T> make_unique(Arg1&& arg1, Arg2&& arg2, Arg3&& arg3) { return std::unique_ptr<T>(new T(std::forward<Arg1>(arg1), std::forward<Arg2>(arg2), std::forward<Arg3>(arg3))); }
+template<class T, class Arg1, class Arg2, class Arg3, class Arg4> inline std::unique_ptr<T> make_unique(Arg1&& arg1, Arg2&& arg2, Arg3&& arg3, Arg4&& arg4) { return std::unique_ptr<T>(new T(std::forward<Arg1>(arg1), std::forward<Arg2>(arg2), std::forward<Arg3>(arg3), std::forward<Arg4>(arg4))); }
+template<class T, class Arg1, class Arg2, class Arg3, class Arg4, class Arg5> inline std::unique_ptr<T> make_unique(Arg1&& arg1, Arg2&& arg2, Arg3&& arg3, Arg4&& arg4, Arg5&& arg5) { return std::unique_ptr<T>(new T(std::forward<Arg1>(arg1), std::forward<Arg2>(arg2), std::forward<Arg3>(arg3), std::forward<Arg4>(arg4), std::forward<Arg5>(arg5))); }
+template<class T, class Arg1, class Arg2, class Arg3, class Arg4, class Arg5, class Arg6> inline std::unique_ptr<T> make_unique(Arg1&& arg1, Arg2&& arg2, Arg3&& arg3, Arg4&& arg4, Arg5&& arg5, Arg6&& arg6) { return std::unique_ptr<T>(new T(std::forward<Arg1>(arg1), std::forward<Arg2>(arg2), std::forward<Arg3>(arg3), std::forward<Arg4>(arg4), std::forward<Arg5>(arg5), std::forward<Arg6>(arg6))); }
//template<typename T, typename ...Args> inline
//std::unique_ptr<T> make_unique(Args&& ...args)
diff --git a/zen/string_base.h b/zen/string_base.h
index e4e21716..e38fab94 100644
--- a/zen/string_base.h
+++ b/zen/string_base.h
@@ -209,6 +209,8 @@ public:
typedef Char& reference;
typedef const Char& const_reference;
typedef Char value_type;
+
+ Zbase(const_iterator first, const_iterator last);
Char* begin();
Char* end ();
const Char* begin() const;
@@ -338,6 +340,17 @@ Zbase<Char, SP, AP>::Zbase(const Char* source, size_t sourceLen)
}
+template <class Char, template <class, class> class SP, class AP>
+Zbase<Char, SP, AP>::Zbase(const_iterator first, const_iterator last)
+{
+ assert(first <= last);
+ const size_t sourceLen = last - first;
+ rawStr = this->create(sourceLen);
+ std::copy(first, last, rawStr);
+ rawStr[sourceLen] = 0;
+}
+
+
template <class Char, template <class, class> class SP, class AP> inline
Zbase<Char, SP, AP>::Zbase(const Zbase<Char, SP, AP>& source)
{
bgstack15