diff options
Diffstat (limited to 'zen')
-rw-r--r-- | zen/FindFilePlus/find_file_plus.cpp | 117 | ||||
-rw-r--r-- | zen/IFileOperation/FileOperation_Vista.vcxproj | 35 | ||||
-rw-r--r-- | zen/IFileOperation/file_op.cpp | 28 | ||||
-rw-r--r-- | zen/async_task.h | 70 | ||||
-rw-r--r-- | zen/debug_minidump.cpp | 4 | ||||
-rw-r--r-- | zen/debug_minidump.h | 4 | ||||
-rw-r--r-- | zen/dir_watcher.cpp | 4 | ||||
-rw-r--r-- | zen/file_handling.cpp | 21 | ||||
-rw-r--r-- | zen/file_id.cpp | 34 | ||||
-rw-r--r-- | zen/file_id.h | 12 | ||||
-rw-r--r-- | zen/file_io.cpp | 2 | ||||
-rw-r--r-- | zen/file_traverser.cpp | 4 | ||||
-rw-r--r-- | zen/int64.h | 8 | ||||
-rw-r--r-- | zen/long_path_prefix.h | 20 | ||||
-rw-r--r-- | zen/osx_string.h | 2 | ||||
-rw-r--r-- | zen/osx_throw_exception.h | 4 | ||||
-rw-r--r-- | zen/scope_guard.h | 2 | ||||
-rw-r--r-- | zen/stl_tools.h | 13 | ||||
-rw-r--r-- | zen/string_base.h | 13 |
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) { |