diff options
author | Daniel Wilhelm <daniel@wili.li> | 2014-04-18 17:31:23 +0200 |
---|---|---|
committer | Daniel Wilhelm <daniel@wili.li> | 2014-04-18 17:31:23 +0200 |
commit | 851b6f99c1248c8ec8e33322a3179c1d82fdd515 (patch) | |
tree | 5b9abf4c4e648ea48ed4873e3c4bf1b225c64daf /zen | |
parent | 6.1 (diff) | |
download | FreeFileSync-851b6f99c1248c8ec8e33322a3179c1d82fdd515.tar.gz FreeFileSync-851b6f99c1248c8ec8e33322a3179c1d82fdd515.tar.bz2 FreeFileSync-851b6f99c1248c8ec8e33322a3179c1d82fdd515.zip |
6.2
Diffstat (limited to 'zen')
30 files changed, 149 insertions, 2824 deletions
diff --git a/zen/FindFilePlus/FindFilePlus.vcxproj b/zen/FindFilePlus/FindFilePlus.vcxproj deleted file mode 100644 index eb5c672e..00000000 --- a/zen/FindFilePlus/FindFilePlus.vcxproj +++ /dev/null @@ -1,173 +0,0 @@ -<?xml version="1.0" encoding="utf-8"?> -<Project DefaultTargets="Build" ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> - <ItemGroup Label="ProjectConfigurations"> - <ProjectConfiguration Include="Debug|Win32"> - <Configuration>Debug</Configuration> - <Platform>Win32</Platform> - </ProjectConfiguration> - <ProjectConfiguration Include="Debug|x64"> - <Configuration>Debug</Configuration> - <Platform>x64</Platform> - </ProjectConfiguration> - <ProjectConfiguration Include="Release|Win32"> - <Configuration>Release</Configuration> - <Platform>Win32</Platform> - </ProjectConfiguration> - <ProjectConfiguration Include="Release|x64"> - <Configuration>Release</Configuration> - <Platform>x64</Platform> - </ProjectConfiguration> - </ItemGroup> - <PropertyGroup Label="Globals"> - <ProjectGuid>{814047ED-7701-494D-BBAF-AFEDF43EDC4E}</ProjectGuid> - <RootNamespace>ShadowDll</RootNamespace> - <Keyword>Win32Proj</Keyword> - </PropertyGroup> - <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" /> - <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration"> - <ConfigurationType>DynamicLibrary</ConfigurationType> - <CharacterSet>Unicode</CharacterSet> - <WholeProgramOptimization>true</WholeProgramOptimization> - <PlatformToolset>v120_xp</PlatformToolset> - </PropertyGroup> - <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration"> - <ConfigurationType>DynamicLibrary</ConfigurationType> - <CharacterSet>Unicode</CharacterSet> - <PlatformToolset>v120_xp</PlatformToolset> - </PropertyGroup> - <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration"> - <ConfigurationType>DynamicLibrary</ConfigurationType> - <CharacterSet>Unicode</CharacterSet> - <WholeProgramOptimization>true</WholeProgramOptimization> - <PlatformToolset>v120_xp</PlatformToolset> - </PropertyGroup> - <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration"> - <ConfigurationType>DynamicLibrary</ConfigurationType> - <CharacterSet>Unicode</CharacterSet> - <PlatformToolset>v120_xp</PlatformToolset> - </PropertyGroup> - <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" /> - <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="PropertySheets"> - <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" /> - </ImportGroup> - <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="PropertySheets"> - <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" /> - </ImportGroup> - <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="PropertySheets"> - <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" /> - </ImportGroup> - <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="PropertySheets"> - <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" /> - </ImportGroup> - <PropertyGroup> - <_ProjectFileVersion>10.0.30319.1</_ProjectFileVersion> - <OutDir Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">..\..\FreeFileSync\Build\Bin\</OutDir> - <IntDir Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">..\..\FreeFileSync\Obj\$(ProjectName)_VCPP_$(PlatformName)_$(Configuration)\</IntDir> - <OutDir Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">..\..\FreeFileSync\Build\Bin\</OutDir> - <IntDir Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">..\..\FreeFileSync\Obj\$(ProjectName)_VCPP_$(PlatformName)_$(Configuration)\</IntDir> - <OutDir Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">..\..\FreeFileSync\Build\Bin\</OutDir> - <IntDir Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">..\..\FreeFileSync\Obj\$(ProjectName)_VCPP_$(PlatformName)_$(Configuration)\</IntDir> - <LinkIncremental Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">false</LinkIncremental> - <OutDir Condition="'$(Configuration)|$(Platform)'=='Release|x64'">..\..\FreeFileSync\Build\Bin\</OutDir> - <IntDir Condition="'$(Configuration)|$(Platform)'=='Release|x64'">..\..\FreeFileSync\Obj\$(ProjectName)_VCPP_$(PlatformName)_$(Configuration)\</IntDir> - <LinkIncremental Condition="'$(Configuration)|$(Platform)'=='Release|x64'">false</LinkIncremental> - <TargetName Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">$(ProjectName)_$(Platform)</TargetName> - <TargetName Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">$(ProjectName)_$(Platform)</TargetName> - <TargetName Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">$(ProjectName)_$(Platform)</TargetName> - <TargetName Condition="'$(Configuration)|$(Platform)'=='Release|x64'">$(ProjectName)_$(Platform)</TargetName> - <IncludePath Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">C:\Data\C++\WinDDK\inc\ddk;C:\Data\C++\WinDDK\inc\api;C:\Data\C++\WinDDK\inc\crt;$(WindowsSdkDir)\include;$(VCInstallDir)include</IncludePath> - <IncludePath Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">C:\Data\C++\WinDDK\inc\ddk;C:\Data\C++\WinDDK\inc\api;C:\Data\C++\WinDDK\inc\crt;$(WindowsSdkDir)\include;$(VCInstallDir)include</IncludePath> - <IncludePath Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">C:\Data\C++\WinDDK\inc\ddk;C:\Data\C++\WinDDK\inc\api;C:\Data\C++\WinDDK\inc\crt;$(WindowsSdkDir)\include;$(VCInstallDir)include</IncludePath> - <IncludePath Condition="'$(Configuration)|$(Platform)'=='Release|x64'">C:\Data\C++\WinDDK\inc\ddk;C:\Data\C++\WinDDK\inc\api;C:\Data\C++\WinDDK\inc\crt;$(WindowsSdkDir)\include;$(VCInstallDir)include</IncludePath> - </PropertyGroup> - <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'"> - <ClCompile> - <Optimization>Disabled</Optimization> - <PreprocessorDefinitions>_X86_;_DEBUG;_WINDOWS;_USRDLL;FIND_FILE_PLUS_DLL_EXPORTS;%(PreprocessorDefinitions)</PreprocessorDefinitions> - <BasicRuntimeChecks>EnableFastChecks</BasicRuntimeChecks> - <RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary> - <WarningLevel>Level4</WarningLevel> - <DisableSpecificWarnings>4100;4996;4512</DisableSpecificWarnings> - <AdditionalIncludeDirectories>C:\Data\Projects;</AdditionalIncludeDirectories> - <SmallerTypeCheck>true</SmallerTypeCheck> - <MultiProcessorCompilation>true</MultiProcessorCompilation> - <EnableEnhancedInstructionSet>NoExtensions</EnableEnhancedInstructionSet> - </ClCompile> - <Link> - <OutputFile>$(OutDir)$(TargetName)$(TargetExt)</OutputFile> - <GenerateDebugInformation>true</GenerateDebugInformation> - <SubSystem>Windows</SubSystem> - <ImportLibrary>$(IntDir)$(TargetName).lib</ImportLibrary> - </Link> - </ItemDefinitionGroup> - <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'"> - <ClCompile> - <Optimization>Disabled</Optimization> - <PreprocessorDefinitions>_AMD64_;_DEBUG;_WINDOWS;_USRDLL;FIND_FILE_PLUS_DLL_EXPORTS;%(PreprocessorDefinitions)</PreprocessorDefinitions> - <BasicRuntimeChecks>EnableFastChecks</BasicRuntimeChecks> - <RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary> - <WarningLevel>Level4</WarningLevel> - <DisableSpecificWarnings>4100;4996;4512</DisableSpecificWarnings> - <AdditionalIncludeDirectories>C:\Data\Projects;</AdditionalIncludeDirectories> - <SmallerTypeCheck>true</SmallerTypeCheck> - <MultiProcessorCompilation>true</MultiProcessorCompilation> - </ClCompile> - <Link> - <OutputFile>$(OutDir)$(TargetName)$(TargetExt)</OutputFile> - <GenerateDebugInformation>true</GenerateDebugInformation> - <SubSystem>Windows</SubSystem> - <ImportLibrary>$(IntDir)$(TargetName).lib</ImportLibrary> - </Link> - </ItemDefinitionGroup> - <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'"> - <ClCompile> - <Optimization>MaxSpeed</Optimization> - <PreprocessorDefinitions>_X86_;NDEBUG;_WINDOWS;_USRDLL;FIND_FILE_PLUS_DLL_EXPORTS;%(PreprocessorDefinitions)</PreprocessorDefinitions> - <RuntimeLibrary>MultiThreaded</RuntimeLibrary> - <WarningLevel>Level4</WarningLevel> - <DebugInformationFormat>ProgramDatabase</DebugInformationFormat> - <DisableSpecificWarnings>4100;4996;4512</DisableSpecificWarnings> - <FavorSizeOrSpeed>Speed</FavorSizeOrSpeed> - <AdditionalIncludeDirectories>C:\Data\Projects;</AdditionalIncludeDirectories> - <MultiProcessorCompilation>true</MultiProcessorCompilation> - <EnableEnhancedInstructionSet>NoExtensions</EnableEnhancedInstructionSet> - </ClCompile> - <Link> - <OutputFile>$(OutDir)$(TargetName)$(TargetExt)</OutputFile> - <GenerateDebugInformation>true</GenerateDebugInformation> - <SubSystem>Windows</SubSystem> - <LinkTimeCodeGeneration>UseLinkTimeCodeGeneration</LinkTimeCodeGeneration> - <ImportLibrary>$(IntDir)$(TargetName).lib</ImportLibrary> - </Link> - </ItemDefinitionGroup> - <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'"> - <ClCompile> - <Optimization>MaxSpeed</Optimization> - <PreprocessorDefinitions>_AMD64_;NDEBUG;_WINDOWS;_USRDLL;FIND_FILE_PLUS_DLL_EXPORTS;%(PreprocessorDefinitions)</PreprocessorDefinitions> - <RuntimeLibrary>MultiThreaded</RuntimeLibrary> - <WarningLevel>Level4</WarningLevel> - <DisableSpecificWarnings>4100;4996;4512</DisableSpecificWarnings> - <FavorSizeOrSpeed>Speed</FavorSizeOrSpeed> - <AdditionalIncludeDirectories>C:\Data\Projects;</AdditionalIncludeDirectories> - <MultiProcessorCompilation>true</MultiProcessorCompilation> - </ClCompile> - <Link> - <OutputFile>$(OutDir)$(TargetName)$(TargetExt)</OutputFile> - <GenerateDebugInformation>true</GenerateDebugInformation> - <SubSystem>Windows</SubSystem> - <LinkTimeCodeGeneration>UseLinkTimeCodeGeneration</LinkTimeCodeGeneration> - <ImportLibrary>$(IntDir)$(TargetName).lib</ImportLibrary> - </Link> - </ItemDefinitionGroup> - <ItemGroup> - <ClCompile Include="..\debug_memory_leaks.cpp" /> - <ClCompile Include="dll_main.cpp" /> - <ClCompile Include="find_file_plus.cpp" /> - <ClCompile Include="load_dll.cpp" /> - </ItemGroup> - <ItemGroup> - <ClInclude Include="find_file_plus.h" /> - <ClInclude Include="load_dll.h" /> - </ItemGroup> - <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" /> -</Project>
\ No newline at end of file diff --git a/zen/FindFilePlus/dll_main.cpp b/zen/FindFilePlus/dll_main.cpp deleted file mode 100644 index caa5930d..00000000 --- a/zen/FindFilePlus/dll_main.cpp +++ /dev/null @@ -1,66 +0,0 @@ -// ************************************************************************** -// * 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 * -// ************************************************************************** - -#define WIN32_LEAN_AND_MEAN -#include <zen/win.h> - -#include "init_dll_binding.h" - -/* -http://www.microsoft.com/whdc/driver/kernel/DLL_bestprac.mspx -"DllMain is called while the loader-lock is held. [...] You cannot call any function in -DllMain that directly or indirectly tries to acquire the loader lock. Otherwise, you will -introduce the possibility that your application deadlocks or crashes." - -it's even worse: http://msdn.microsoft.com/en-us/library/windows/desktop/ms682583(v=vs.85).aspx -"If your DLL is linked with the C run-time library (CRT), the entry point provided by the CRT calls the constructors -and destructors for global and static C++ objects. Therefore, these restrictions for DllMain also apply to constructors -and destructors and any code that is called from them." - -Example: http://blog.barthe.ph/2009/07/30/no-stdlib-in-dllmai/ - -Empirical study on DLL initialization order -------------------------------------------- -I. statically linked DLL: - DLL, static object constructors - DLL, DllMain(): DLL_PROCESS_ATTACH - main thread, static object constructors - main thread, enter main() - DLL, DllMain(): DLL_THREAD_ATTACH - DLL, DllMain(): DLL_THREAD_DETACH - main thread, exit main() - main thread, static object destructors - DLL, DllMain(): DLL_PROCESS_DETACH - DLL, static object destructors - -II. dynamically linked DLL (living in main()): - main thread, static object constructors - main thread, main(): LoadLibrary - DLL, static object constructors - DLL, DllMain(): DLL_PROCESS_ATTACH - main thread, main(): FreeLibrary - DLL, DllMain(): DLL_PROCESS_DETACH - DLL, static object destructors - main thread, static object destructors -*/ - -//optional: add init/teardown logic here -BOOL APIENTRY DllMain(HINSTANCE hinstDLL, - DWORD fdwReason, - LPVOID lpvReserved) -{ - switch (fdwReason) - { - case DLL_PROCESS_ATTACH: - if (!findplus::initDllBinding()) - return false; - case DLL_PROCESS_DETACH: - case DLL_THREAD_ATTACH: - case DLL_THREAD_DETACH: - break; - } - return true; -} diff --git a/zen/FindFilePlus/find_file_plus.cpp b/zen/FindFilePlus/find_file_plus.cpp deleted file mode 100644 index 247b916c..00000000 --- a/zen/FindFilePlus/find_file_plus.cpp +++ /dev/null @@ -1,452 +0,0 @@ -// ************************************************************************** -// * 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 * -// ************************************************************************** - -#include "find_file_plus.h" -#include "init_dll_binding.h" -//#include <windows.h> //these two don't play nice with each other -#include "load_dll.h" -#include <new> - -using namespace dll; -using namespace findplus; - - -namespace -{ -struct NtFileError //exception class -{ - NtFileError(NTSTATUS errorCode) : ntError(errorCode) {} - NTSTATUS ntError; -}; - - -//-------------------------------------------------------------------------------------------------------------- -typedef NTSTATUS (NTAPI* NtOpenFileFunc)(PHANDLE fileHandle, - ACCESS_MASK desiredAccess, - POBJECT_ATTRIBUTES objectAttributes, - PIO_STATUS_BLOCK ioStatusBlock, - ULONG shareAccess, - ULONG openOptions); - -typedef NTSTATUS (NTAPI* NtCloseFunc)(HANDLE handle); - -typedef NTSTATUS (NTAPI* NtQueryDirectoryFileFunc)(HANDLE fileHandle, - HANDLE event, - PIO_APC_ROUTINE apcRoutine, - PVOID apcContext, - PIO_STATUS_BLOCK ioStatusBlock, - PVOID fileInformation, - ULONG length, - FILE_INFORMATION_CLASS fileInformationClass, - BOOLEAN ReturnSingleEntry, - PUNICODE_STRING fileMask, - BOOLEAN restartScan); - -typedef ULONG (NTAPI* RtlNtStatusToDosErrorFunc)(NTSTATUS /*__in status*/); - -typedef struct _RTL_RELATIVE_NAME_U -{ - UNICODE_STRING RelativeName; - HANDLE ContainingDirectory; - PVOID /*PRTLP_CURDIR_REF*/ CurDirRef; -} RTL_RELATIVE_NAME_U, *PRTL_RELATIVE_NAME_U; - -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 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 - -//-------------------------------------------------------------------------------------------------------------- - -//it seems we cannot use any of the ntoskrnl.lib files in WinDDK as they produce access violations -//fortunately dynamic binding works fine: -const SysDllFun<NtOpenFileFunc> ntOpenFile (L"ntdll.dll", "NtOpenFile"); -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 - SysDllFun<RtlDosPathNameToNtPathName_UFunc>(L"ntdll.dll", "RtlDosPathNameToNtPathName_U")); //fallback for XP -//global constants only -> preserve thread safety! -} - - -bool findplus::initDllBinding() //evaluate in ::DllMain() when attaching process -{ - //NT/ZwXxx Routines - //http://msdn.microsoft.com/en-us/library/ff567122(v=VS.85).aspx - - //Run-Time Library (RTL) Routines - //http://msdn.microsoft.com/en-us/library/ff563638(v=VS.85).aspx - - //verify dynamic dll binding - 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 -} - - -class findplus::FileSearcher -{ -public: - FileSearcher(const wchar_t* dirname); //throw NtFileError - ~FileSearcher(); - - bool readDir(FileInformation& output); //throw NtFileError; returns false if "no more files" - -private: - template <class QueryPolicy> bool readDirImpl(FileInformation& output); //throw NtFileError - - UNICODE_STRING dirnameNt; //it seems hDir implicitly keeps a reference to this, at least ::FindFirstFile() does no cleanup before ::FindClose()! - HANDLE hDir; - - ULONG nextEntryOffset; //!= 0 if entry is waiting in buffer - //::FindNextFileW() uses 0x1000 = 4096 = sizeof(FILE_BOTH_DIR_INFORMATION) + sizeof(TCHAR) * 2000 - //=> let's use the same, even if our header is 16 byte larger; maybe there is some packet size advantage for networks? Note that larger buffers seem to degrade performance. - static const ULONG BUFFER_SIZE = 4096; - LONGLONG buffer[BUFFER_SIZE / sizeof(LONGLONG)]; //buffer needs to be aligned at LONGLONG boundary - - static_assert(BUFFER_SIZE % sizeof(LONGLONG) == 0, "ups, our buffer is trimmed!"); -}; - - -//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) -{ - 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, - &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 = {}; - 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, - 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, - 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)) - throw NtFileError(rv); - } - - guardConstructor.dismiss(); -} - - -inline -FileSearcher::~FileSearcher() -{ - //cleanup in reverse order - if (hDir) - ntClose(hDir); - - 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(RtlGetProcessHeap(), 0, ntPathName.Buffer)" -} - - -namespace -{ -/* -Common C-style policy handling directory traversal: - -struct QueryPolicy -{ - typedef ... RawFileInfo; - static const FILE_INFORMATION_CLASS fileInformationClass = ...; - static void extractFileId(const RawFileInfo& rawInfo, FileInformation& fileInfo); -}; -*/ - -struct DirQueryDefault //as implemented in Win32 FindFirstFile()/FindNextFile() -{ - typedef FILE_BOTH_DIR_INFORMATION RawFileInfo; - static const FILE_INFORMATION_CLASS fileInformationClass = FileBothDirectoryInformation; - static void extractFileId(const RawFileInfo& rawInfo, FileInformation& fileInfo) { fileInfo.fileId.QuadPart = 0; } -}; - -struct DirQueryFileId -{ - typedef FILE_ID_BOTH_DIR_INFORMATION RawFileInfo; - static const FILE_INFORMATION_CLASS fileInformationClass = FileIdBothDirectoryInformation; - static void extractFileId(const RawFileInfo& rawInfo, FileInformation& fileInfo) - { - fileInfo.fileId.QuadPart = rawInfo.FileId.QuadPart; //may be 0 even in this context, e.g. for mapped FTP drive! - static_assert(sizeof(fileInfo.fileId) == sizeof(rawInfo.FileId), "dang!"); - } -}; -} - - -inline -bool FileSearcher::readDir(FileInformation& output) { return readDirImpl<DirQueryFileId>(output); } //throw NtFileError - - -template <class QueryPolicy> -bool FileSearcher::readDirImpl(FileInformation& output) //throw NtFileError; returns false if "no more files" -{ - //although FILE_ID_FULL_DIR_INFORMATION should suffice for our purposes, there are problems on Windows XP for certain directories, e.g. "\\Vboxsvr\build" - //making NtQueryDirectoryFile() return with STATUS_INVALID_PARAMETER while other directories, e.g. "C:\" work fine for some reason - //FILE_ID_BOTH_DIR_INFORMATION on the other hand works on XP/Win7/Win8 - //performance: there is no noticeable difference between FILE_ID_BOTH_DIR_INFORMATION and FILE_ID_FULL_DIR_INFORMATION - - /* corresponding first access in ::FindFirstFileW() - - NTSTATUS rv = ntQueryDirectoryFile(hDir, //__in HANDLE fileHandle, - nullptr, //__in_opt HANDLE event, - nullptr, //__in_opt PIO_APC_ROUTINE apcRoutine, - nullptr, //__in_opt PVOID apcContext, - &status, //__out PIO_STATUS_BLOCK ioStatusBlock, - &buffer, //__out_bcount(Length) PVOID fileInformation, - BUFFER_SIZE, //__in ULONG length, ::FindFirstFileW() on all XP/Win7/Win8 uses sizeof(FILE_BOTH_DIR_INFORMATION) + sizeof(TCHAR) * MAX_PATH == 0x268 - FileIdBothDirectoryInformation, //__in FILE_INFORMATION_CLASS fileInformationClass - all XP/Win7/Win8 use "FileBothDirectoryInformation" - true, //__in BOOLEAN returnSingleEntry, - nullptr, //__in_opt PUNICODE_STRING mask, - false); //__in BOOLEAN restartScan - */ - - //analog to ::FindNextFileW() with performance optimized access (in contrast to first access in ::FindFirstFileW()) - if (nextEntryOffset == 0) - { - IO_STATUS_BLOCK status = {}; - NTSTATUS rv = ntQueryDirectoryFile(hDir, //__in HANDLE fileHandle, - nullptr, //__in_opt HANDLE event, - nullptr, //__in_opt PIO_APC_ROUTINE apcRoutine, - nullptr, //__in_opt PVOID apcContext, - &status, //__out PIO_STATUS_BLOCK ioStatusBlock, - &buffer, //__out_bcount(Length) PVOID fileInformation, - BUFFER_SIZE, //__in ULONG length, ::FindNextFileW() on all XP/Win7/Win8 uses sizeof(FILE_BOTH_DIR_INFORMATION) + sizeof(TCHAR) * 2000 == 0x1000 - QueryPolicy::fileInformationClass, //__in FILE_INFORMATION_CLASS fileInformationClass - all XP/Win7/Win8 use "FileBothDirectoryInformation" - false, //__in BOOLEAN returnSingleEntry, - nullptr, //__in_opt PUNICODE_STRING mask, - false); //__in BOOLEAN restartScan - if (!NT_SUCCESS(rv)) - { - /* - fallback to default directory query method, if FileIdBothDirectoryInformation is not properly implemented - this is required for NetDrive mounted Webdav, e.g. www.box.net and NT4, 2000 remote drives, et al. - - NT status code | Win32 error code - --------------------------------|------------------------ - STATUS_INVALID_LEVEL | ERROR_INVALID_LEVEL - STATUS_NOT_SUPPORTED | ERROR_NOT_SUPPORTED - STATUS_UNEXPECTED_NETWORK_ERROR | ERROR_UNEXP_NET_ERR -> traverse network drive hosted by Win98 - STATUS_INVALID_PARAMETER | ERROR_INVALID_PARAMETER - STATUS_INVALID_NETWORK_RESPONSE | ERROR_BAD_NET_RESP - STATUS_INVALID_INFO_CLASS | ERROR_INVALID_PARAMETER - STATUS_UNSUCCESSFUL | ERROR_GEN_FAILURE - STATUS_ACCESS_VIOLATION | ERROR_NOACCESS ->FileIdBothDirectoryInformation on XP accessing UDF - STATUS_NO_SUCH_FILE | ERROR_FILE_NOT_FOUND - - rv == STATUS_NO_SUCH_FILE: - failure to find a file on first call returns STATUS_NO_SUCH_FILE, while subsequent accesses return STATUS_NO_MORE_FILES - note: not all directories contain ".", ".." entries! E.g. a drive's root directory or NetDrive + ftp.gnu.org\CRYPTO.README" - -> addon: this is NOT a directory, it looks like one in NetDrive, but it's a file in Opera - STATUS_NO_SUCH_FILE is abused by some citrix shares instead of "STATUS_INVALID_PARAMETER" so we treat it as such! - => since the directory is "truly empty" a fallback won't hurt - */ - if (rv == STATUS_NO_MORE_FILES) //perf: don't throw an exception in this common case! => 8% perf boost for FFS comparison phase! - return false; - - if (rv == STATUS_NOT_SUPPORTED || - rv == STATUS_INVALID_LEVEL || - rv == STATUS_NO_SUCH_FILE || //[!] - rv == STATUS_UNEXPECTED_NETWORK_ERROR || - rv == STATUS_INVALID_PARAMETER || - rv == STATUS_INVALID_NETWORK_RESPONSE || - rv == STATUS_INVALID_INFO_CLASS || - //rv == STATUS_NOT_IMPLEMENTED || -> first confirm that these codes - //rv == STATUS_INVALID_DEVICE_REQUEST || -> are in fact used! - rv == STATUS_UNSUCCESSFUL || - rv == STATUS_ACCESS_VIOLATION) - rv = STATUS_NOT_SUPPORTED; - - throw NtFileError(rv); //throws STATUS_NO_MORE_FILES when finished - } - - // for (NTSTATUS i = 0xC0000000L; i != -1; ++i) - // { - // if (rtlNtStatusToDosError(i) == 59) //ERROR_UNEXP_NET_ERR - // __debugbreak(); //__asm int 3; - // } - - if (status.Information == 0) //except for the first call to call ::NtQueryDirectoryFile(): - throw NtFileError(STATUS_BUFFER_OVERFLOW); //if buffer size is too small, return value is STATUS_SUCCESS and Information == 0 -> we don't expect this! - } - - typedef typename QueryPolicy::RawFileInfo RawFileInfo; - const RawFileInfo& dirInfo = *reinterpret_cast<RawFileInfo*>(reinterpret_cast<char*>(buffer) + nextEntryOffset); - - if (dirInfo.NextEntryOffset == 0) - nextEntryOffset = 0; //our offset is relative to the beginning of the buffer - else - nextEntryOffset += dirInfo.NextEntryOffset; - - - auto toFileTime = [](const LARGE_INTEGER& rawTime) -> FILETIME - { - FILETIME tmp = { rawTime.LowPart, rawTime.HighPart }; - return tmp; - }; - - QueryPolicy::extractFileId(dirInfo, output); - - output.creationTime = toFileTime(dirInfo.CreationTime); - output.lastWriteTime = toFileTime(dirInfo.LastWriteTime); //the similar field "ChangeTime" refers to changes to metadata in addition to write accesses - output.fileSize.QuadPart = dirInfo.EndOfFile.QuadPart; - output.fileAttributes = dirInfo.FileAttributes; - output.shortNameLength = dirInfo.FileNameLength / sizeof(TCHAR); //FileNameLength is in bytes! - - if (dirInfo.FileAttributes & FILE_ATTRIBUTE_REPARSE_POINT) //analog to FindFirstFile(), confirmed for Win XP and Win 7 - output.reparseTag = dirInfo.EaSize; // - else - output.reparseTag = 0; - - if (dirInfo.FileNameLength + sizeof(TCHAR) > sizeof(output.shortName)) //this may actually happen if ::NtQueryDirectoryFile() decides to return a - throw NtFileError(STATUS_BUFFER_OVERFLOW); //short name of length MAX_PATH + 1, 0-termination is not required! - - ::memcpy(output.shortName, dirInfo.FileName, dirInfo.FileNameLength); - output.shortName[output.shortNameLength] = 0; //NOTE: FILE_ID_BOTH_DIR_INFORMATION::FileName in general is NOT 0-terminated! It is on XP/Win7, but NOT on Win8! - - static_assert(sizeof(output.creationTime) == sizeof(dirInfo.CreationTime), "dang!"); - static_assert(sizeof(output.lastWriteTime) == sizeof(dirInfo.LastWriteTime), "dang!"); - static_assert(sizeof(output.fileSize) == sizeof(dirInfo.EndOfFile), "dang!"); - static_assert(sizeof(output.fileAttributes) == sizeof(dirInfo.FileAttributes), "dang!"); - return true; -} - - -FindHandle findplus::openDir(const wchar_t* dirname) -{ - try - { - return new FileSearcher(dirname); //throw NtFileError, std::bad_alloc - } - catch (const NtFileError& e) - { - setWin32Error(rtlNtStatusToDosError(e.ntError)); - return nullptr; - } - catch (const std::bad_alloc&) //not unlikely in file sync context! => handle! - { - setWin32Error(rtlNtStatusToDosError(STATUS_NO_MEMORY)); - return nullptr; - } -} - - -bool findplus::readDir(FindHandle hnd, FileInformation& output) -{ - try - { - if (!hnd->readDir(output)) //throw NtFileError - { - setWin32Error(rtlNtStatusToDosError(STATUS_NO_MORE_FILES)); - return false; - } - return true; - } - catch (const NtFileError& e) - { - setWin32Error(rtlNtStatusToDosError(e.ntError)); - return false; - } -} - - -void findplus::closeDir(FindHandle hnd) -{ - delete hnd; -} diff --git a/zen/FindFilePlus/find_file_plus.h b/zen/FindFilePlus/find_file_plus.h deleted file mode 100644 index a26bdeb3..00000000 --- a/zen/FindFilePlus/find_file_plus.h +++ /dev/null @@ -1,92 +0,0 @@ -// ************************************************************************** -// * 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 FIND_FIRST_FILE_PLUS_HEADER_087483434 -#define FIND_FIRST_FILE_PLUS_HEADER_087483434 - -#ifdef FIND_FILE_PLUS_DLL_EXPORTS -#define DLL_FUNCTION_DECLARATION extern "C" __declspec(dllexport) -#else -#define DLL_FUNCTION_DECLARATION extern "C" __declspec(dllimport) -#endif - - -#ifdef FIND_FILE_PLUS_DLL_EXPORTS -#include <Ntifs.h> //driver level headers must be included *before* windows api headers! -#endif -#include <windef.h> // -#undef min -#undef max - -#include <zen/build_info.h> - -namespace findplus -{ -/*-------------- - |declarations| - --------------*/ - -struct FileInformation -{ - FILETIME creationTime; - FILETIME lastWriteTime; - ULARGE_INTEGER fileSize; - ULARGE_INTEGER fileId; //optional: may be 0 if not supported - DWORD fileAttributes; - DWORD reparseTag; //set if "fileAttributes & FILE_ATTRIBUTE_REPARSE_POINT" - DWORD shortNameLength; - WCHAR shortName[MAX_PATH + 1]; //shortName is 0-terminated -}; //no need for #pragma pack -> all members are perfectly 4, 8 byte aligned! - -class FileSearcher; -typedef FileSearcher* FindHandle; - -DLL_FUNCTION_DECLARATION -FindHandle openDir(const wchar_t* dirname); //returns nullptr on error, call ::GetLastError() -//note: do NOT place an asterisk at end, e.g. C:\SomeDir\*, as you would do for ::FindFirstFile() - -DLL_FUNCTION_DECLARATION -bool readDir(FindHandle hnd, FileInformation& output); //returns false on error or if there are no more files; ::GetLastError() returns ERROR_NO_MORE_FILES in this case -/* -warning: may also return with ERROR_NOT_SUPPORTED if "FileIdBothDirectoryInformation" is not supported! We need a fallback: - - sometimes it's *not* sufficient to use fallback for NtQueryDirectoryFile() alone, we need to reset "hDir", since it may be fucked up by some poor file system layer implementation: - - Samba before v3.0.22 (Mar 30, 2006) seems to have a bug which sucessfully returns 128 elements via NtQueryDirectoryFile() and FileIdBothDirectoryInformation, - then fails with STATUS_INVALID_LEVEL. Fallback to FileBothDirectoryInformation will return STATUS_NO_MORE_FILES, even if there *are* more files - - NtQueryDirectoryFile() may *not* respect "restartScan" for some weird Win2000 file system drivers, so we cannot rely on this as a replacement for a "hDir" reset - - Windows 7 Remote Desktop sharing does not work unless "hDir" is reset! - => let's assume worst case in general and do a reset! - perf note: implementing this reset at a folder level is possible, but a huge perf-killer (additional open/close handle), therefore fallback must apply to a complete folder (sub-)tree! - => caller needs to handle this and implement FindFirstFile()/FindNextFile() fallback! -*/ - -DLL_FUNCTION_DECLARATION -void closeDir(FindHandle hnd); - -/*---------- - |typedefs| - ----------*/ -typedef FindHandle (*FunType_openDir )(const wchar_t* dirname); -typedef bool (*FunType_readDir )(FindHandle hnd, FileInformation& dirInfo); -typedef void (*FunType_closeDir)(FindHandle hnd); - -/*-------------- - |symbol names| - --------------*/ -//const pointers ensure internal linkage -const char funName_openDir [] = "openDir"; -const char funName_readDir [] = "readDir"; -const char funName_closeDir[] = "closeDir"; - -/*--------------- - |library names| - ---------------*/ -inline const wchar_t* getDllName() { return zen::is64BitBuild ? L"FindFilePlus_x64.dll" : L"FindFilePlus_Win32.dll"; } -} - -#undef DLL_FUNCTION_DECLARATION - -#endif //FIND_FIRST_FILE_PLUS_HEADER_087483434 diff --git a/zen/FindFilePlus/init_dll_binding.h b/zen/FindFilePlus/init_dll_binding.h deleted file mode 100644 index 44591ab4..00000000 --- a/zen/FindFilePlus/init_dll_binding.h +++ /dev/null @@ -1,16 +0,0 @@ -// ************************************************************************** -// * 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 INIT_DLL_BINDING_HEADER_ß018356031467832145 -#define INIT_DLL_BINDING_HEADER_ß018356031467832145 - -namespace findplus -{ -//load and check dll binding at startup -bool initDllBinding(); //evaluate in ::DllMain() when attaching process -} - -#endif //INIT_DLL_BINDING_HEADER_ß018356031467832145 diff --git a/zen/FindFilePlus/load_dll.cpp b/zen/FindFilePlus/load_dll.cpp deleted file mode 100644 index c9396f6d..00000000 --- a/zen/FindFilePlus/load_dll.cpp +++ /dev/null @@ -1,23 +0,0 @@ -// ************************************************************************** -// * 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 * -// ************************************************************************** - -#include "load_dll.h" -#define WIN32_LEAN_AND_MEAN -#include <zen/win.h> - -void* /*FARPROC*/ dll::loadSymbol(const wchar_t* libraryName, const char* functionName) -{ - return ::GetProcAddress(::GetModuleHandle(libraryName), functionName); - //cleanup neither required nor allowed (::FreeLibrary()) - -} -//note: void* and FARPROC function pointer have same binary size on Windows - - -void dll::setWin32Error(unsigned long lastError) -{ - ::SetLastError(lastError); -} diff --git a/zen/FindFilePlus/load_dll.h b/zen/FindFilePlus/load_dll.h deleted file mode 100644 index d661c4b9..00000000 --- a/zen/FindFilePlus/load_dll.h +++ /dev/null @@ -1,45 +0,0 @@ -// ************************************************************************** -// * 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 LOAD_DLL_HEADER_0312463214872163832174 -#define LOAD_DLL_HEADER_0312463214872163832174 - -namespace dll -{ -void setWin32Error(unsigned long lastError); - -//NOTE: uses ::GetModuleHandle => call for system DLLs only! -template <class Func> -class SysDllFun -{ -public: - SysDllFun(const wchar_t* systemLibrary, const char* functionName) : - fun(reinterpret_cast<Func>(loadSymbol(systemLibrary, functionName))) {} - - operator Func() const { return fun; } - -private: - Func fun; -}; - - - - - - - - - - - - - - - -void* /*FARPROC*/ loadSymbol(const wchar_t* libraryName, const char* functionName); -} - -#endif //LOAD_DLL_HEADER_0312463214872163832174 diff --git a/zen/IFileOperation/FileOperation.vcxproj b/zen/IFileOperation/FileOperation.vcxproj deleted file mode 100644 index 3f6923f3..00000000 --- a/zen/IFileOperation/FileOperation.vcxproj +++ /dev/null @@ -1,179 +0,0 @@ -<?xml version="1.0" encoding="utf-8"?> -<Project DefaultTargets="Build" ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> - <ItemGroup Label="ProjectConfigurations"> - <ProjectConfiguration Include="Debug|Win32"> - <Configuration>Debug</Configuration> - <Platform>Win32</Platform> - </ProjectConfiguration> - <ProjectConfiguration Include="Debug|x64"> - <Configuration>Debug</Configuration> - <Platform>x64</Platform> - </ProjectConfiguration> - <ProjectConfiguration Include="Release|Win32"> - <Configuration>Release</Configuration> - <Platform>Win32</Platform> - </ProjectConfiguration> - <ProjectConfiguration Include="Release|x64"> - <Configuration>Release</Configuration> - <Platform>x64</Platform> - </ProjectConfiguration> - </ItemGroup> - <PropertyGroup Label="Globals"> - <ProjectName>FileOperation</ProjectName> - <ProjectGuid>{F6D3A51C-15EF-4710-BB67-3FCE9C0B5D92}</ProjectGuid> - <RootNamespace>ShadowDll</RootNamespace> - <Keyword>Win32Proj</Keyword> - </PropertyGroup> - <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" /> - <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration"> - <ConfigurationType>DynamicLibrary</ConfigurationType> - <CharacterSet>Unicode</CharacterSet> - <WholeProgramOptimization>true</WholeProgramOptimization> - <PlatformToolset>v120_xp</PlatformToolset> - </PropertyGroup> - <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration"> - <ConfigurationType>DynamicLibrary</ConfigurationType> - <CharacterSet>Unicode</CharacterSet> - <PlatformToolset>v120_xp</PlatformToolset> - </PropertyGroup> - <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration"> - <ConfigurationType>DynamicLibrary</ConfigurationType> - <CharacterSet>Unicode</CharacterSet> - <WholeProgramOptimization>true</WholeProgramOptimization> - <PlatformToolset>v120_xp</PlatformToolset> - </PropertyGroup> - <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration"> - <ConfigurationType>DynamicLibrary</ConfigurationType> - <CharacterSet>Unicode</CharacterSet> - <PlatformToolset>v120_xp</PlatformToolset> - </PropertyGroup> - <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" /> - <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="PropertySheets"> - <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" /> - </ImportGroup> - <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="PropertySheets"> - <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" /> - </ImportGroup> - <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="PropertySheets"> - <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" /> - </ImportGroup> - <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="PropertySheets"> - <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" /> - </ImportGroup> - <PropertyGroup> - <_ProjectFileVersion>10.0.30319.1</_ProjectFileVersion> - <OutDir Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">..\..\FreeFileSync\Build\Bin\</OutDir> - <IntDir Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">..\..\FreeFileSync\Obj\$(ProjectName)_VCPP_$(PlatformName)_$(Configuration)\</IntDir> - <OutDir Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">..\..\FreeFileSync\Build\Bin\</OutDir> - <IntDir Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">..\..\FreeFileSync\Obj\$(ProjectName)_VCPP_$(PlatformName)_$(Configuration)\</IntDir> - <OutDir Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">..\..\FreeFileSync\Build\Bin\</OutDir> - <IntDir Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">..\..\FreeFileSync\Obj\$(ProjectName)_VCPP_$(PlatformName)_$(Configuration)\</IntDir> - <LinkIncremental Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">false</LinkIncremental> - <OutDir Condition="'$(Configuration)|$(Platform)'=='Release|x64'">..\..\FreeFileSync\Build\Bin\</OutDir> - <IntDir Condition="'$(Configuration)|$(Platform)'=='Release|x64'">..\..\FreeFileSync\Obj\$(ProjectName)_VCPP_$(PlatformName)_$(Configuration)\</IntDir> - <LinkIncremental Condition="'$(Configuration)|$(Platform)'=='Release|x64'">false</LinkIncremental> - <TargetName Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">$(ProjectName)_$(Platform)</TargetName> - <TargetName Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">$(ProjectName)_$(Platform)</TargetName> - <TargetName Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">$(ProjectName)_$(Platform)</TargetName> - <TargetName Condition="'$(Configuration)|$(Platform)'=='Release|x64'">$(ProjectName)_$(Platform)</TargetName> - </PropertyGroup> - <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'"> - <ClCompile> - <Optimization>Disabled</Optimization> - <PreprocessorDefinitions>WXINTL_NO_GETTEXT_MACRO;ZEN_WIN;_DEBUG;_WINDOWS;_USRDLL;FILE_OP_DLL_EXPORTS;%(PreprocessorDefinitions)</PreprocessorDefinitions> - <BasicRuntimeChecks>EnableFastChecks</BasicRuntimeChecks> - <RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary> - <WarningLevel>Level4</WarningLevel> - <DisableSpecificWarnings>4100;4996;4512</DisableSpecificWarnings> - <AdditionalIncludeDirectories>C:\Data\Projects;C:\Data\C++\boost</AdditionalIncludeDirectories> - <SmallerTypeCheck>true</SmallerTypeCheck> - <ForcedIncludeFiles>zen/warn_static.h</ForcedIncludeFiles> - <MultiProcessorCompilation>true</MultiProcessorCompilation> - <EnableEnhancedInstructionSet>NoExtensions</EnableEnhancedInstructionSet> - </ClCompile> - <Link> - <OutputFile>$(OutDir)$(TargetName)$(TargetExt)</OutputFile> - <GenerateDebugInformation>true</GenerateDebugInformation> - <SubSystem>Windows</SubSystem> - <AdditionalLibraryDirectories>C:\Data\C++\Boost\stage\lib</AdditionalLibraryDirectories> - <ImportLibrary>$(IntDir)$(TargetName).lib</ImportLibrary> - </Link> - </ItemDefinitionGroup> - <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'"> - <ClCompile> - <Optimization>Disabled</Optimization> - <PreprocessorDefinitions>WXINTL_NO_GETTEXT_MACRO;ZEN_WIN;_DEBUG;_WINDOWS;_USRDLL;FILE_OP_DLL_EXPORTS;%(PreprocessorDefinitions)</PreprocessorDefinitions> - <BasicRuntimeChecks>EnableFastChecks</BasicRuntimeChecks> - <RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary> - <WarningLevel>Level4</WarningLevel> - <DisableSpecificWarnings>4100;4996;4512</DisableSpecificWarnings> - <AdditionalIncludeDirectories>C:\Data\Projects;C:\Data\C++\boost</AdditionalIncludeDirectories> - <SmallerTypeCheck>true</SmallerTypeCheck> - <ForcedIncludeFiles>zen/warn_static.h</ForcedIncludeFiles> - <MultiProcessorCompilation>true</MultiProcessorCompilation> - </ClCompile> - <Link> - <OutputFile>$(OutDir)$(TargetName)$(TargetExt)</OutputFile> - <GenerateDebugInformation>true</GenerateDebugInformation> - <SubSystem>Windows</SubSystem> - <AdditionalLibraryDirectories>C:\Data\C++\Boost\stage_x64\lib</AdditionalLibraryDirectories> - <ImportLibrary>$(IntDir)$(TargetName).lib</ImportLibrary> - </Link> - </ItemDefinitionGroup> - <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'"> - <ClCompile> - <Optimization>MaxSpeed</Optimization> - <PreprocessorDefinitions>WXINTL_NO_GETTEXT_MACRO;ZEN_WIN;NDEBUG;_WINDOWS;_USRDLL;FILE_OP_DLL_EXPORTS;%(PreprocessorDefinitions)</PreprocessorDefinitions> - <RuntimeLibrary>MultiThreaded</RuntimeLibrary> - <WarningLevel>Level4</WarningLevel> - <FavorSizeOrSpeed>Speed</FavorSizeOrSpeed> - <DisableSpecificWarnings>4100;4996;4512</DisableSpecificWarnings> - <AdditionalIncludeDirectories>C:\Data\Projects;C:\Data\C++\boost</AdditionalIncludeDirectories> - <ForcedIncludeFiles>zen/warn_static.h</ForcedIncludeFiles> - <MultiProcessorCompilation>true</MultiProcessorCompilation> - <EnableEnhancedInstructionSet>NoExtensions</EnableEnhancedInstructionSet> - </ClCompile> - <Link> - <OutputFile>$(OutDir)$(TargetName)$(TargetExt)</OutputFile> - <GenerateDebugInformation>true</GenerateDebugInformation> - <SubSystem>Windows</SubSystem> - <LinkTimeCodeGeneration>UseLinkTimeCodeGeneration</LinkTimeCodeGeneration> - <AdditionalLibraryDirectories>C:\Data\C++\Boost\stage\lib</AdditionalLibraryDirectories> - <ImportLibrary>$(IntDir)$(TargetName).lib</ImportLibrary> - </Link> - </ItemDefinitionGroup> - <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'"> - <ClCompile> - <Optimization>MaxSpeed</Optimization> - <PreprocessorDefinitions>WXINTL_NO_GETTEXT_MACRO;ZEN_WIN;NDEBUG;_WINDOWS;_USRDLL;FILE_OP_DLL_EXPORTS;%(PreprocessorDefinitions)</PreprocessorDefinitions> - <RuntimeLibrary>MultiThreaded</RuntimeLibrary> - <WarningLevel>Level4</WarningLevel> - <FavorSizeOrSpeed>Speed</FavorSizeOrSpeed> - <DisableSpecificWarnings>4100;4996;4512</DisableSpecificWarnings> - <AdditionalIncludeDirectories>C:\Data\Projects;C:\Data\C++\boost</AdditionalIncludeDirectories> - <ForcedIncludeFiles>zen/warn_static.h</ForcedIncludeFiles> - <MultiProcessorCompilation>true</MultiProcessorCompilation> - </ClCompile> - <Link> - <OutputFile>$(OutDir)$(TargetName)$(TargetExt)</OutputFile> - <GenerateDebugInformation>true</GenerateDebugInformation> - <SubSystem>Windows</SubSystem> - <LinkTimeCodeGeneration>UseLinkTimeCodeGeneration</LinkTimeCodeGeneration> - <AdditionalLibraryDirectories>C:\Data\C++\Boost\stage_x64\lib</AdditionalLibraryDirectories> - <ImportLibrary>$(IntDir)$(TargetName).lib</ImportLibrary> - </Link> - </ItemDefinitionGroup> - <ItemGroup> - <ClCompile Include="..\debug_memory_leaks.cpp" /> - <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> - <ClInclude Include="file_op.h" /> - </ItemGroup> - <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" /> -</Project>
\ No newline at end of file diff --git a/zen/IFileOperation/file_op.cpp b/zen/IFileOperation/file_op.cpp deleted file mode 100644 index 27a2565b..00000000 --- a/zen/IFileOperation/file_op.cpp +++ /dev/null @@ -1,541 +0,0 @@ -// ************************************************************************** -// * 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 * -// ************************************************************************** - -#include "file_op.h" -#include <algorithm> -#include <string> -#include <vector> - -#define WIN32_LEAN_AND_MEAN -#include <zen/com_ptr.h> -#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> - -#include <RestartManager.h> -#pragma comment(lib, "Rstrtmgr.lib") - -#define STRICT_TYPED_ITEMIDS //better type safety for IDLists -#include <Shlobj.h> -#include <shobjidl.h> -#include <shellapi.h> //shell constants such as FO_* values - -using namespace zen; - - -namespace -{ -std::vector<std::wstring> getLockingProcesses(const wchar_t* filename); //throw SysError - - -class RecyclerProgressCallback : public IFileOperationProgressSink -{ - //Sample implementation: %ProgramFiles%\Microsoft SDKs\Windows\v7.1\Samples\winui\shell\appplatform\FileOperationProgressSink - - ~RecyclerProgressCallback() {} //private: do not allow stack usage "thanks" to IUnknown lifetime management! - -public: - RecyclerProgressCallback(fileop::RecyclerCallback callback, void* sink) : - cancellationRequested(false), - callback_(callback), - sink_(sink), - refCount(1) {} - - //IUnknown: reference implementation according to: http://msdn.microsoft.com/en-us/library/office/cc839627.aspx - virtual ULONG STDMETHODCALLTYPE AddRef() - { - return ::InterlockedIncrement(&refCount); - } - - virtual ULONG STDMETHODCALLTYPE Release() - { - ULONG newRefCount = ::InterlockedDecrement(&refCount); - if (newRefCount == 0) //race condition caveat: do NOT check refCount, which might have changed already! - delete this; - return newRefCount; - } - - virtual HRESULT STDMETHODCALLTYPE QueryInterface(REFIID riid, void __RPC_FAR* __RPC_FAR* ppvObject) - { - if (!ppvObject) - return E_INVALIDARG; - - if (riid == IID_IUnknown || riid == IID_IFileOperationProgressSink) - { - *ppvObject = this; - AddRef(); - return S_OK; - } - *ppvObject = NULL; - return E_NOINTERFACE; - } - - //IFileOperationProgressSink - virtual HRESULT STDMETHODCALLTYPE StartOperations() { return S_OK; } - virtual HRESULT STDMETHODCALLTYPE FinishOperations(HRESULT hrResult) { return S_OK; } - virtual HRESULT STDMETHODCALLTYPE PreRenameItem (DWORD dwFlags, __RPC__in_opt IShellItem* psiItem, __RPC__in_opt_string LPCWSTR pszNewName) { return S_OK; } - virtual HRESULT STDMETHODCALLTYPE PostRenameItem (DWORD dwFlags, __RPC__in_opt IShellItem* psiItem, __RPC__in_string LPCWSTR pszNewName, HRESULT hrRename, __RPC__in_opt IShellItem* psiNewlyCreated) { return S_OK; } - virtual HRESULT STDMETHODCALLTYPE PreMoveItem (DWORD dwFlags, __RPC__in_opt IShellItem* psiItem, __RPC__in_opt IShellItem* psiDestinationFolder, __RPC__in_opt_string LPCWSTR pszNewName) { return S_OK; } - virtual HRESULT STDMETHODCALLTYPE PostMoveItem (DWORD dwFlags, __RPC__in_opt IShellItem* psiItem, __RPC__in_opt IShellItem* psiDestinationFolder, __RPC__in_opt_string LPCWSTR pszNewName, HRESULT hrMove, __RPC__in_opt IShellItem* psiNewlyCreated) { return S_OK; } - virtual HRESULT STDMETHODCALLTYPE PreCopyItem (DWORD dwFlags, __RPC__in_opt IShellItem* psiItem, __RPC__in_opt IShellItem* psiDestinationFolder, __RPC__in_opt_string LPCWSTR pszNewName) { return S_OK; } - virtual HRESULT STDMETHODCALLTYPE PostCopyItem (DWORD dwFlags, __RPC__in_opt IShellItem* psiItem, __RPC__in_opt IShellItem* psiDestinationFolder, __RPC__in_opt_string LPCWSTR pszNewName, HRESULT hrCopy, __RPC__in_opt IShellItem* psiNewlyCreated) { return S_OK; } - virtual HRESULT STDMETHODCALLTYPE PreNewItem (DWORD dwFlags, __RPC__in_opt IShellItem* psiDestinationFolder, __RPC__in_opt_string LPCWSTR pszNewName) { return S_OK; } - virtual HRESULT STDMETHODCALLTYPE PostNewItem (DWORD dwFlags, __RPC__in_opt IShellItem* psiDestinationFolder, __RPC__in_opt_string LPCWSTR pszNewName, __RPC__in_opt_string LPCWSTR pszTemplateName, DWORD dwFileAttributes, HRESULT hrNew, __RPC__in_opt IShellItem* psiNewItem) { return S_OK; } - - virtual HRESULT STDMETHODCALLTYPE PreDeleteItem(DWORD dwFlags, __RPC__in_opt IShellItem* psiItem) - { - if (psiItem) - { - LPWSTR itemPath = nullptr; - 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." - return cancellationRequested ? HRESULT_FROM_WIN32(ERROR_CANCELLED) : S_OK; - } - - virtual HRESULT STDMETHODCALLTYPE PostDeleteItem(DWORD dwFlags, - __RPC__in_opt IShellItem* psiItem, - HRESULT hrDelete, - __RPC__in_opt IShellItem* psiNewlyCreated) - { - if (FAILED(hrDelete)) - lastError = make_unique<std::pair<std::wstring, HRESULT>>(currentItem, hrDelete); - - currentItem.clear(); - //"Returns S_OK if successful, or an error value otherwise. In the case of an error value, - //all subsequent operations pending from the call to IFileOperation are canceled." - return cancellationRequested ? HRESULT_FROM_WIN32(ERROR_CANCELLED) : S_OK; - } - - virtual HRESULT STDMETHODCALLTYPE UpdateProgress(UINT iWorkTotal, UINT iWorkSoFar) - { - if (callback_) - try - { - if (!callback_(currentItem.c_str(), sink_)) //should not throw! - cancellationRequested = true; - } - catch (...) { return E_UNEXPECTED; } - //"If this method succeeds, it returns S_OK. Otherwise, it returns an HRESULT error code." - //-> this probably means, we cannot rely on returning a custom error code here and have IFileOperation::PerformOperations() fail with same - //=> defer cancellation to PreDeleteItem()/PostDeleteItem() - return S_OK; - } - virtual HRESULT STDMETHODCALLTYPE ResetTimer () { return S_OK; } - virtual HRESULT STDMETHODCALLTYPE PauseTimer () { return S_OK; } - virtual HRESULT STDMETHODCALLTYPE ResumeTimer() { return S_OK; } - - //call after IFileOperation::PerformOperations() - const std::pair<std::wstring, HRESULT>* getLastError() const { return lastError.get(); } //(file path, error code) - -private: - std::wstring currentItem; - bool cancellationRequested; - - std::unique_ptr<std::pair<std::wstring, HRESULT>> lastError; - - //file_op user callback - fileop::RecyclerCallback callback_; - void* sink_; - - //support IUnknown - LONG refCount; -}; - - -void moveToRecycleBin(const wchar_t* fileNames[], //throw SysError - size_t fileCount, - fileop::RecyclerCallback callback, - void* sink) -{ - ComPtr<IFileOperation> fileOp; - ZEN_COM_CHECK(::CoCreateInstance(CLSID_FileOperation, //throw SysError - nullptr, - CLSCTX_ALL, - IID_PPV_ARGS(fileOp.init()))); - - // Set the operation flags. Turn off all UI from being shown to the user during the - // operation. This includes error, confirmation and progress dialogs. - ZEN_COM_CHECK(fileOp->SetOperationFlags(FOF_ALLOWUNDO | - FOF_NOCONFIRMATION | - FOF_SILENT | //no progress dialog box - FOF_NOERRORUI | - FOFX_EARLYFAILURE | - //without FOFX_EARLYFAILURE, IFileOperationProgressSink::PostDeleteItem() will always report success, even if deletion failed!!? WTF!? - //PerformOperations() will still succeed but set the uselessly generic GetAnyOperationsAborted() instead :((( - //=> always set FOFX_EARLYFAILURE since we prefer good error messages over "doing as much as possible" - //luckily for FreeFileSync we don't expect failures on individual files anyway: FreeFileSync moves files to be - //deleted to a temporary folder first, so there is no reason why a second move (the recycling itself) should fail - FOF_NO_CONNECTED_ELEMENTS)); - //use FOFX_RECYCLEONDELETE when Windows 8 is available!? - - ComPtr<RecyclerProgressCallback> opProgress; - *opProgress.init() = new (std::nothrow) RecyclerProgressCallback(callback, sink); - if (!opProgress) - throw SysError(formatComError(L"Error creating RecyclerProgressCallback.", E_OUTOFMEMORY)); - - DWORD callbackID = 0; - ZEN_COM_CHECK(fileOp->Advise(opProgress.get(), &callbackID)); - ZEN_ON_SCOPE_EXIT(fileOp->Unadvise(callbackID)); //RecyclerProgressCallback might outlive current scope, so cut access to "callback, sink" - - int operationCount = 0; - - for (size_t i = 0; i < fileCount; ++i) - { - //SHCreateItemFromParsingName() physically checks file existence => callback - if (callback) - { - bool continueExecution = false; - try - { - continueExecution = callback(fileNames[i], sink); //should not throw! - } - catch (...) { throw SysError(formatComError(L"Unexpected exception in callback.", E_UNEXPECTED)); } - - if (!continueExecution) - throw SysError(formatComError(L"Operation cancelled.", HRESULT_FROM_WIN32(ERROR_CANCELLED))); - } - - //create file/folder item object - ComPtr<IShellItem> psiFile; - HRESULT hr = ::SHCreateItemFromParsingName(fileNames[i], - nullptr, - IID_PPV_ARGS(psiFile.init())); - if (FAILED(hr)) - { - if (hr == HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND) || //file not existing anymore - hr == HRESULT_FROM_WIN32(ERROR_PATH_NOT_FOUND)) - { - //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 SysError(formatComError(std::wstring(L"Error calling \"SHCreateItemFromParsingName\" for file:\n") + L"\"" + fileNames[i] + L"\".", hr)); - } - - ZEN_COM_CHECK(fileOp->DeleteItem(psiFile.get(), nullptr)); - - ++operationCount; - } - - if (operationCount == 0) //calling PerformOperations() without anything to do would yield E_UNEXPECTED - return; - - //perform planned operations - try - { - ZEN_COM_CHECK(fileOp->PerformOperations()); - } - catch (const SysError&) - { - //first let's check if we have more detailed error information available - if (const std::pair<std::wstring, HRESULT>* lastError = opProgress->getLastError()) - { - std::vector<std::wstring> processes; //create an even better error message if we detect a locking issue: - try { processes = getLockingProcesses(lastError->first.c_str()); /*throw SysError*/ } - catch (const SysError&) {} - - if (!processes.empty()) - { - std::wstring errorMsg = L"The file \"" + lastError->first + L"\" is locked by another process:"; - std::for_each(processes.begin(), processes.end(), [&](const std::wstring& proc) { errorMsg += L'\n'; errorMsg += proc; }); - throw SysError(errorMsg); //message is descriptive enough, no need to evaluate HRESULT! - } - throw SysError(formatComError(std::wstring(L"Error during \"PerformOperations\" for file:\n") + L"\"" + lastError->first + L"\".", lastError->second)); - } - throw; - } - - //if FOF_NOERRORUI without FOFX_EARLYFAILURE is set, PerformOperations() can return with success despite errors, but sets the following "aborted" flag instead - BOOL pfAnyOperationsAborted = FALSE; - ZEN_COM_CHECK(fileOp->GetAnyOperationsAborted(&pfAnyOperationsAborted)); - - if (pfAnyOperationsAborted == TRUE) - throw SysError(L"Operation did not complete successfully."); -} - - -void copyFile(const wchar_t* sourceFile, //throw SysError - const wchar_t* targetFile) -{ - ComPtr<IFileOperation> fileOp; - ZEN_COM_CHECK(::CoCreateInstance(CLSID_FileOperation, //throw SysError - nullptr, - CLSCTX_ALL, - IID_PPV_ARGS(fileOp.init()))); - - // Set the operation flags. Turn off all UI - // from being shown to the user during the - // operation. This includes error, confirmation - // and progress dialogs. - ZEN_COM_CHECK(fileOp->SetOperationFlags(FOF_NOCONFIRMATION | //throw SysError - FOF_SILENT | - FOFX_EARLYFAILURE | - FOF_NOERRORUI)); - //create source object - ComPtr<IShellItem> psiSourceFile; - { - HRESULT hr = ::SHCreateItemFromParsingName(sourceFile, - nullptr, - IID_PPV_ARGS(psiSourceFile.init())); - if (FAILED(hr)) - throw SysError(formatComError(std::wstring(L"Error calling \"SHCreateItemFromParsingName\" for file:\n") + L"\"" + sourceFile + L"\".", hr)); - } - - const size_t pos = std::wstring(targetFile).find_last_of(L'\\'); - if (pos == std::wstring::npos) - throw SysError(L"Target filename does not contain a path separator."); - - const std::wstring targetFolder(targetFile, pos); - const std::wstring targetFileNameShort = targetFile + pos + 1; - - //create target folder object - ComPtr<IShellItem> psiTargetFolder; - { - HRESULT hr = ::SHCreateItemFromParsingName(targetFolder.c_str(), - nullptr, - IID_PPV_ARGS(psiTargetFolder.init())); - if (FAILED(hr)) - throw SysError(formatComError(std::wstring(L"Error calling \"SHCreateItemFromParsingName\" for folder:\n") + L"\"" + targetFolder + L"\".", hr)); - } - - //schedule file copy operation - ZEN_COM_CHECK(fileOp->CopyItem(psiSourceFile.get(), psiTargetFolder.get(), targetFileNameShort.c_str(), nullptr)); - - //perform actual operations - ZEN_COM_CHECK(fileOp->PerformOperations()); - - //check if errors occured: if FOFX_EARLYFAILURE is not used, PerformOperations() can return with success despite errors! - BOOL pfAnyOperationsAborted = FALSE; - ZEN_COM_CHECK(fileOp->GetAnyOperationsAborted(&pfAnyOperationsAborted)); - - if (pfAnyOperationsAborted == TRUE) - throw SysError(L"Operation did not complete successfully."); -} - - -void getFolderClsid(const wchar_t* dirname, CLSID& pathCLSID) //throw SysError -{ - ComPtr<IShellFolder> desktopFolder; - ZEN_COM_CHECK(::SHGetDesktopFolder(desktopFolder.init())); //throw SysError - - PIDLIST_RELATIVE pidlFolder = nullptr; - ZEN_COM_CHECK(desktopFolder->ParseDisplayName(nullptr, // [in] HWND hwnd, - nullptr, // [in] IBindCtx *pbc, - const_cast<LPWSTR>(dirname), // [in] LPWSTR pszDisplayName, - nullptr, // [out] ULONG *pchEaten, - &pidlFolder, // [out] PIDLIST_RELATIVE* ppidl, - nullptr)); // [in, out] ULONG *pdwAttributes - ZEN_ON_SCOPE_EXIT(::ILFree(pidlFolder)); //older version: ::CoTaskMemFree - - ComPtr<IPersist> persistFolder; - ZEN_COM_CHECK(desktopFolder->BindToObject(pidlFolder, // [in] PCUIDLIST_RELATIVE pidl, - nullptr, // [in] IBindCtx *pbc, - IID_PPV_ARGS(persistFolder.init()))); //throw SysError - - ZEN_COM_CHECK(persistFolder->GetClassID(&pathCLSID)); //throw SysError -} - - -std::vector<std::wstring> getLockingProcesses(const wchar_t* filename) //throw SysError -{ - DWORD sessionHandle = 0; - { - wchar_t sessionKey[CCH_RM_SESSION_KEY + 1] = {}; //fixes two bugs: http://blogs.msdn.com/b/oldnewthing/archive/2012/02/17/10268840.aspx - DWORD rv1 = ::RmStartSession(&sessionHandle, //__out DWORD *pSessionHandle, - 0, //__reserved DWORD dwSessionFlags, - sessionKey); //__out WCHAR strSessionKey[ ] - if (rv1 != ERROR_SUCCESS) - throw SysError(formatSystemError(L"RmStartSession", rv1)); - } - ZEN_ON_SCOPE_EXIT(::RmEndSession(sessionHandle)); - - { - DWORD rv2 = ::RmRegisterResources(sessionHandle, //__in DWORD dwSessionHandle, - 1, //__in UINT nFiles, - &filename, //__in_opt LPCWSTR rgsFilenames[ ], - 0, //__in UINT nApplications, - nullptr, //__in_opt RM_UNIQUE_PROCESS rgApplications[ ], - 0, //__in UINT nServices, - nullptr); //__in_opt LPCWSTR rgsServiceNames[ ] - if (rv2 != ERROR_SUCCESS) - throw SysError(formatSystemError(L"RmRegisterResources", rv2)); - } - - std::vector<RM_PROCESS_INFO> procInfo; - { - UINT procInfoSize = 0; - UINT procInfoSizeNeeded = 0; - DWORD rebootReasons = 0; - DWORD rv3 = ::RmGetList(sessionHandle, &procInfoSizeNeeded, &procInfoSize, nullptr, &rebootReasons); //get procInfoSizeNeeded - if (rv3 == ERROR_SUCCESS) - return std::vector<std::wstring>(); - if (rv3 != ERROR_MORE_DATA) - throw SysError(formatSystemError(L"RmGetList", rv3)); - //C:\pagefile.sys fails with ERROR_SHARING_VIOLATION! - - if (procInfoSizeNeeded == 0) - return std::vector<std::wstring>(); - - procInfoSize = procInfoSizeNeeded; - procInfo.resize(procInfoSizeNeeded); - - rv3 = ::RmGetList(sessionHandle, //__in DWORD dwSessionHandle, - &procInfoSizeNeeded, //__out UINT *pnProcInfoNeeded, - &procInfoSize, //__inout UINT *pnProcInfo, - &procInfo[0], //__inout_opt RM_PROCESS_INFO rgAffectedApps[ ], - &rebootReasons); //__out LPDWORD lpdwRebootReasons - if (rv3 != ERROR_SUCCESS) - throw SysError(formatSystemError(L"RmGetList", rv3)); - procInfo.resize(procInfoSize); - } - - std::vector<std::wstring> output; - for (auto iter = procInfo.begin(); iter != procInfo.end(); ++iter) - { - std::wstring processName = iter->strAppName; - - //try to get process path - HANDLE hProcess = ::OpenProcess(PROCESS_QUERY_LIMITED_INFORMATION, //__in DWORD dwDesiredAccess, - false, //__in BOOL bInheritHandle, - iter->Process.dwProcessId); //__in DWORD dwProcessId - if (hProcess) - { - ZEN_ON_SCOPE_EXIT(::CloseHandle(hProcess)); - - FILETIME creationTime = {}; - FILETIME exitTime = {}; - FILETIME kernelTime = {}; - FILETIME userTime = {}; - if (::GetProcessTimes(hProcess, //__in HANDLE hProcess, - &creationTime, //__out LPFILETIME lpCreationTime, - &exitTime, //__out LPFILETIME lpExitTime, - &kernelTime, //__out LPFILETIME lpKernelTime, - &userTime)) //__out LPFILETIME lpUserTime - if (::CompareFileTime(&iter->Process.ProcessStartTime, &creationTime) == 0) - { - DWORD bufferSize = MAX_PATH; - std::vector<wchar_t> buffer(bufferSize); - if (::QueryFullProcessImageName(hProcess, //__in HANDLE hProcess, - 0, //__in DWORD dwFlags, - &buffer[0], //__out LPTSTR lpExeName, - &bufferSize)) //__inout PDWORD lpdwSize - if (bufferSize < buffer.size()) - processName += std::wstring(L", ") + L"\"" + &buffer[0] + L"\""; - } - } - output.push_back(processName); - } - return output; -} - - -boost::thread_specific_ptr<std::wstring> lastErrorMessage; //use "thread_local" in C++11 -} - - -bool fileop::moveToRecycleBin(const wchar_t* fileNames[], - size_t fileCount, - RecyclerCallback callback, - void* sink) -{ - try - { - ::moveToRecycleBin(fileNames, fileCount, callback, sink); //throw SysError - return true; - } - catch (const SysError& e) - { - lastErrorMessage.reset(new std::wstring(e.toString())); - return false; - } -} - - -bool fileop::copyFile(const wchar_t* sourceFile, - const wchar_t* targetFile) -{ - try - { - ::copyFile(sourceFile, targetFile); //throw SysError - return true; - } - catch (const SysError& e) - { - lastErrorMessage.reset(new std::wstring(e.toString())); - return false; - } -} - - -bool fileop::checkRecycler(const wchar_t* dirname, bool& isRecycler) -{ - try - { - CLSID clsid = {}; - getFolderClsid(dirname, clsid); //throw SysError - isRecycler = ::IsEqualCLSID(clsid, CLSID_RecycleBin) == TRUE; //silence perf warning - return true; - } - catch (const SysError& e) - { - lastErrorMessage.reset(new std::wstring(e.toString())); - return false; - } -} - - -const wchar_t* fileop::getLastError() -{ - return !lastErrorMessage.get() ? L"" : lastErrorMessage->c_str(); -} - - -bool fileop::getLockingProcesses(const wchar_t* filename, const wchar_t*& procList) -{ - try - { - std::vector<std::wstring> processes = ::getLockingProcesses(filename); //throw SysError - - std::wstring buffer; - std::for_each(processes.begin(), processes.end(), [&](const std::wstring& proc) { buffer += proc; buffer += L'\n'; }); - if (!processes.empty()) - buffer.resize(buffer.size() - 1); //remove last line break - - auto tmp = new wchar_t [buffer.size() + 1]; //bad_alloc ? - ::wmemcpy(tmp, buffer.c_str(), buffer.size() + 1); //include 0-termination - procList = tmp; //ownership passed - - return true; - } - catch (const SysError& e) - { - lastErrorMessage.reset(new std::wstring(e.toString())); - return false; - } -} - - -void fileop::freeString(const wchar_t* str) -{ - delete [] str; -} diff --git a/zen/IFileOperation/file_op.h b/zen/IFileOperation/file_op.h deleted file mode 100644 index 2f5d6f30..00000000 --- a/zen/IFileOperation/file_op.h +++ /dev/null @@ -1,87 +0,0 @@ -// ************************************************************************** -// * 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 RECYCLER_DLL_H -#define RECYCLER_DLL_H - -#ifdef FILE_OP_DLL_EXPORTS -#define DLL_FUNCTION_DECLARATION extern "C" __declspec(dllexport) -#else -#define DLL_FUNCTION_DECLARATION extern "C" __declspec(dllimport) -#endif - -#include <zen/build_info.h> - - -namespace fileop -{ -/*-------------- - |declarations| - --------------*/ - -//COM needs to be initialized before calling any of these functions! CoInitializeEx/CoUninitialize -//minimum OS: Windows Vista or later - -//return false to abort operation -typedef bool (*RecyclerCallback)(const wchar_t* filename, //current item; may be empty string! - void* sink); //virtual function mechanism is not guaranteed to be compatible between different compilers, therefore we go the C-way - -DLL_FUNCTION_DECLARATION -bool moveToRecycleBin(const wchar_t* fileNames[], - size_t fileCount, //size of fileNames array - RecyclerCallback callback, //optional - void* sink); // - -DLL_FUNCTION_DECLARATION -bool copyFile(const wchar_t* sourceFile, - const wchar_t* targetFile); - -DLL_FUNCTION_DECLARATION -bool checkRecycler(const wchar_t* dirname, bool& isRecycler); //returns false on error - -DLL_FUNCTION_DECLARATION -bool getLockingProcesses(const wchar_t* filename, const wchar_t*& procList); //get list of processes as single string, call freeString(procList) after use! - -DLL_FUNCTION_DECLARATION -void freeString(const wchar_t* str); - -//get last error message if any of the functions above fail -DLL_FUNCTION_DECLARATION -const wchar_t* getLastError(); //no nullptr check required! - -/*---------- - |typedefs| - ----------*/ -typedef bool (*FunType_moveToRecycleBin)(const wchar_t* fileNames[], - size_t fileCount, - RecyclerCallback callback, - void* sink); -typedef bool (*FunType_copyFile)(const wchar_t* sourceFile, const wchar_t* targetFile); -typedef bool (*FunType_checkRecycler)(const wchar_t* dirname, bool& isRecycler); -typedef bool (*FunType_getLockingProcesses)(const wchar_t* filename, const wchar_t*& procList); -typedef void (*FunType_freeString)(const wchar_t* str); -typedef const wchar_t* (*FunType_getLastError)(); - -/*-------------- - |symbol names| - --------------*/ -//(use const pointers to ensure internal linkage) -const char funName_moveToRecycleBin [] = "moveToRecycleBin"; -const char funName_copyFile [] = "copyFile"; -const char funName_checkRecycler [] = "checkRecycler"; -const char funName_getLockingProcesses[] = "getLockingProcesses"; -const char funName_freeString [] = "freeString"; -const char funName_getLastError [] = "getLastError"; - -/*--------------- - |library names| - ---------------*/ -inline const wchar_t* getDllName() { return zen::is64BitBuild ? L"FileOperation_x64.dll" : L"FileOperation_Win32.dll"; } -} - -#undef DLL_FUNCTION_DECLARATION - -#endif //RECYCLER_DLL_H diff --git a/zen/base64.h b/zen/base64.h deleted file mode 100644 index ae896e70..00000000 --- a/zen/base64.h +++ /dev/null @@ -1,157 +0,0 @@ -// ************************************************************************** -// * 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 BASE64_HEADER_08473021856321840873021487213453214 -#define BASE64_HEADER_08473021856321840873021487213453214 - -#ifndef NDEBUG //no release build dependencies! -#include <iterator> -#include <cassert> -#endif - -namespace zen -{ -//http://en.wikipedia.org/wiki/Base64 -/* -Usage: - const std::string input = "Sample text"; - std::string output; - zen::encodeBase64(input.begin(), input.end(), std::back_inserter(output)); - //output contains "U2FtcGxlIHRleHQ=" -*/ -template <class InputIterator, class OutputIterator> -OutputIterator encodeBase64(InputIterator first, InputIterator last, OutputIterator result); //nothrow! - -template <class InputIterator, class OutputIterator> -OutputIterator decodeBase64(InputIterator first, InputIterator last, OutputIterator result); //nothrow! - - - - - - - - - - - - -//------------------------- implementation ------------------------------- -namespace implementation -{ -//64 chars for base64 encoding + padding char -const char ENCODING_MIME[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/="; -const signed char DECODING_MIME[] = -{ - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 62, -1, -1, -1, 63, - 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, -1, -1, -1, 64, -1, -1, - -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, - 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, -1, -1, -1, -1, -1, - -1, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, - 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, -1, -1, -1, -1, -1 -}; -const unsigned char INDEX_PAD = 64; //"=" -} - - -//http://en.wikipedia.org/wiki/Base64 -template <class InputIterator, class OutputIterator> inline -OutputIterator encodeBase64(InputIterator first, InputIterator last, OutputIterator result) -{ - using namespace implementation; - static_assert(sizeof(typename std::iterator_traits<InputIterator>::value_type) == 1, ""); - static_assert(sizeof(ENCODING_MIME) == 65 + 1, ""); - - while (first != last) - { - const unsigned char a = static_cast<unsigned char>(*first++); - *result++ = ENCODING_MIME[a >> 2]; - - if (first == last) - { - *result++ = ENCODING_MIME[((a & 0x3) << 4)]; - *result++ = ENCODING_MIME[INDEX_PAD]; - *result++ = ENCODING_MIME[INDEX_PAD]; - break; - } - const unsigned char b = static_cast<unsigned char>(*first++); - *result++ = ENCODING_MIME[((a & 0x3) << 4) | (b >> 4)]; - - if (first == last) - { - *result++ = ENCODING_MIME[((b & 0xf) << 2)]; - *result++ = ENCODING_MIME[INDEX_PAD]; - break; - } - const unsigned char c = static_cast<unsigned char>(*first++); - *result++ = ENCODING_MIME[((b & 0xf) << 2) | (c >> 6)]; - *result++ = ENCODING_MIME[c & 0x3f]; - } - - return result; -} - - -template <class InputIterator, class OutputIterator> inline -OutputIterator decodeBase64(InputIterator first, InputIterator last, OutputIterator result) -{ - using namespace implementation; - static_assert(sizeof(typename std::iterator_traits<InputIterator>::value_type) == 1, ""); - static_assert(sizeof(DECODING_MIME) == 128, ""); - - const unsigned char INDEX_END = INDEX_PAD + 1; - - auto readIndex = [&]() -> unsigned char //return index within [0, 64] or INDEX_END if end of input - { - while (true) - { - if (first == last) - return INDEX_END; - - const unsigned char ch = static_cast<unsigned char>(*first++); - if (ch < 128) //we're in lower ASCII table half - { - const int index = implementation::DECODING_MIME[ch]; - if (0 <= index && index <= static_cast<int>(INDEX_PAD)) //skip all unknown characters (including carriage return, line-break, tab) - return index; - } - } - }; - - for (;;) - { - const unsigned char index1 = readIndex(); - const unsigned char index2 = readIndex(); - if (index1 >= INDEX_PAD || index2 >= INDEX_PAD) - { - assert(index1 == INDEX_END && index2 == INDEX_END); - break; - } - *result++ = static_cast<char>((index1 << 2) | (index2 >> 4)); - - const unsigned char index3 = readIndex(); - if (index3 >= INDEX_PAD) //padding - { - assert(index3 == INDEX_PAD); - break; - } - *result++ = static_cast<char>(((index2 & 0xf) << 4) | (index3 >> 2)); - - const unsigned char index4 = readIndex(); - if (index4 >= INDEX_PAD) //padding - { - assert(index4 == INDEX_PAD); - break; - } - *result++ = static_cast<char>(((index3 & 0x3) << 6) | index4); - } - return result; -} -} - -#endif //BASE64_HEADER_08473021856321840873021487213453214 diff --git a/zen/com_error.h b/zen/com_error.h deleted file mode 100644 index 5eb7611d..00000000 --- a/zen/com_error.h +++ /dev/null @@ -1,227 +0,0 @@ -// ************************************************************************** -// * 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 COM_ERROR_HEADER_88425703425254 -#define COM_ERROR_HEADER_88425703425254 - -#include <cstdio> -#include "sys_error.h" - -namespace zen -{ -std::wstring formatComError(const std::wstring& msg, HRESULT hr); - -//Convenience Macros checking for COM errors: - -#define ZEN_COM_CHECK(func) ZEN_COM_CHECK_IMPL(func, #func) //throw SysError -/* -Example: ZEN_COM_CHECK(backupComp->InitializeForBackup()); - -Equivalent to: -{ - HRESULT hrInternal = backupComp->InitializeForBackup(); - if (FAILED(hrInternal)) - throw SysError(formatComError(L"Error calling \"backupComp->InitializeForBackup()\".", hrInternal)); -} -*/ - -#define ZEN_COM_ASSERT(obj) ZEN_COM_ASSERT_IMPL(obj, #obj) //throw SysError -/* -Example: ZEN_COM_ASSERT(obj); - -Equivalent to: - if (!obj) - throw SysError(formatComError(L"Assertion failed: \"obj\".", E_FAIL)); -*/ - - - - - - -//################# implementation ##################### -namespace impl -{ -inline -std::wstring formatWin32Message(DWORD dwMessageId) //return empty string on error -{ - LPWSTR buffer = nullptr; - if (::FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM | - FORMAT_MESSAGE_MAX_WIDTH_MASK | - FORMAT_MESSAGE_IGNORE_INSERTS | //important: without this flag ::FormatMessage() will fail if message contains placeholders - FORMAT_MESSAGE_ALLOCATE_BUFFER, nullptr, dwMessageId, 0, reinterpret_cast<LPWSTR>(&buffer), 0, nullptr) != 0) - if (buffer) //just to be sure - { - ZEN_ON_SCOPE_EXIT(::LocalFree(buffer)); - return buffer; - } - return std::wstring(); -} - - -inline -std::wstring numberToHexString(long number) -{ - wchar_t buffer[100] = {}; - const int charsWritten = ::swprintf(buffer, 100, L"0x%08x", static_cast<int>(number)); - return charsWritten > 0 ? std::wstring(buffer, charsWritten) : std::wstring(); -} - - -namespace -{ -std::wstring formatFacility(HRESULT hr) -{ - switch (HRESULT_FACILITY(hr)) - { - case FACILITY_XPS: - return L"XPS"; - case FACILITY_WINRM: - return L"Windows Resource Manager"; - case FACILITY_WINDOWSUPDATE: - return L"Windows Update"; - case FACILITY_WINDOWS_DEFENDER: - return L"Windows Defender Component"; - case FACILITY_WINDOWS_CE: - return L"Windows CE"; - case FACILITY_WINDOWS: - return L"Windows Subsystem"; - case FACILITY_USERMODE_VOLMGR: - return L"User Mode Volume Manager"; - case FACILITY_USERMODE_VIRTUALIZATION: - return L"User Mode Virtualization Subsystem"; - case FACILITY_USERMODE_VHD: - return L"User Mode Virtual Hard Disk Support"; - case FACILITY_URT: - return L".NET CLR"; - case FACILITY_UMI: - return L"Ubiquitous Memoryintrospection Service"; - case FACILITY_UI: - return L"UI"; - case FACILITY_TPM_SOFTWARE: - return L"Trusted Platform Module Applications"; - case FACILITY_TPM_SERVICES: - return L"Trusted Platform Module Services"; - case FACILITY_SXS: - return L"Side-by-side Servicing"; - case FACILITY_STORAGE: - return L"OLE Storage"; - case FACILITY_STATE_MANAGEMENT: - return L"State Management Services"; - case FACILITY_SCARD: - return L"Smart-card Subsystem"; - case FACILITY_SHELL: - return L"User Shell"; - case FACILITY_SETUPAPI: - return L"Setup API"; - case FACILITY_SECURITY: - return L"Security API Layer"; - case FACILITY_SDIAG: - return L"System Diagnostics"; - case FACILITY_RPC: - return L"RPC Subsystem"; - case FACILITY_RAS: - return L"RAS"; - case FACILITY_PLA: - return L"Performance Logs and Alerts"; - case FACILITY_OPC: - return L"Open Connectivity Service"; - case FACILITY_WIN32: - return L"Win32"; - case FACILITY_CONTROL: - return L"Control Mechanism"; - case FACILITY_WEBSERVICES: - return L"Web Services"; - case FACILITY_NDIS: - return L"Network Driver Interface"; - case FACILITY_METADIRECTORY: - return L"Microsoft Identity Server"; - case FACILITY_MSMQ: - return L"Microsoft Message Queue"; - case FACILITY_MEDIASERVER: - return L"Windows Media Server"; - case FACILITY_MBN: - return L"MBN"; - case FACILITY_INTERNET: - return L"Wininet"; - case FACILITY_ITF: - return L"COM/OLE Interface Management"; - case FACILITY_USERMODE_HYPERVISOR: - return L"Usermode Hypervisor Components"; - case FACILITY_HTTP: - return L"HTTP Support"; - case FACILITY_GRAPHICS: - return L"Graphics Drivers"; - case FACILITY_FWP: - return L"Firewall Platform"; - case FACILITY_FVE: - return L"Full volume encryption"; - case FACILITY_USERMODE_FILTER_MANAGER: - return L"User Mode Filter Manager"; - case FACILITY_DPLAY: - return L"Direct Play"; - case FACILITY_DISPATCH: - return L"COM Dispatch"; - case FACILITY_DIRECTORYSERVICE: - return L"Active Directory"; - case FACILITY_CONFIGURATION: - return L"Configuration Services"; - case FACILITY_COMPLUS: - return L"COM+"; - case FACILITY_USERMODE_COMMONLOG: - return L"Common Logging Support"; - case FACILITY_CMI: - return L"Configuration Management Infrastructure"; - case FACILITY_CERT: - return L"Certificate"; - case FACILITY_BCD: - return L"Boot Configuration Database"; - case FACILITY_BACKGROUNDCOPY: - return L"Background Copy Control"; - case FACILITY_ACS: - return L"Audit Collection Service"; - case FACILITY_AAF: - return L"Microsoft Agent"; - default: - return L"Unknown"; - } -} -} -} - - -std::wstring formatComError(const std::wstring& msg, long long hr); //not implemented! intentional overload ambiguity to catch usage errors with HRESULT! - - -inline -std::wstring formatComError(const std::wstring& msg, HRESULT hr) -{ - std::wstring output(msg); - output += L"\n"; - - //don't use _com_error(hr).ErrorMessage(): internally this is nothing more than a call to ::FormatMessage() - std::wstring win32Msg = impl::formatWin32Message(hr); - if (!win32Msg.empty()) //empty string on error - output += win32Msg + L"\n" + L"HRESULT: " + impl::numberToHexString(hr); - else - output += L"HRESULT: " + impl::numberToHexString(hr) + L", " + L"Facility: " + impl::formatFacility(hr); - //don't bluntly interpret as Win32 error code HRESULT_CODE(hr), too often misleading! - //http://blogs.msdn.com/b/oldnewthing/archive/2006/11/03/942851.aspx - - return output; -} - - -#define ZEN_COM_CHECK_IMPL(func, txt) \ - { \ - HRESULT hrInternal = func; \ - if (FAILED(hrInternal)) \ - throw zen::SysError(formatComError(std::wstring(L"Error calling \"") + L ## txt + L"\".", hrInternal)); \ - } - -#define ZEN_COM_ASSERT_IMPL(obj, txt) if (!(obj)) throw zen::SysError(formatComError(std::wstring(L"Assertion failed: \"") + L ## txt + L"\".", E_FAIL)); -} -#endif //COM_ERROR_HEADER_88425703425254 diff --git a/zen/com_ptr.h b/zen/com_ptr.h deleted file mode 100644 index 6fb9f2cd..00000000 --- a/zen/com_ptr.h +++ /dev/null @@ -1,120 +0,0 @@ -// ************************************************************************** -// * 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 SMART_COM_PTR_H -#define SMART_COM_PTR_H - -#include <algorithm> -#include "win.h" //includes "windows.h" -> always include before other headers that also might include "windows.h"! -#include <Objbase.h> - -namespace zen -{ -/* -ComPtr: RAII class handling COM objects - -Example: --------- - ComPtr<IUPnPDeviceFinder> devFinder; - if (FAILED(::CoCreateInstance(CLSID_UPnPDeviceFinder, - nullptr, - CLSCTX_ALL, - IID_PPV_ARGS(devFinder.init())))) - return -1; - - ComPtr<IEnumUnknown> devEnum = com_dynamic_cast<IEnumUnknown>(devColl); - if (!devEnum) - return -1; -*/ - -template <class T> -class ComPtr -{ -public: - ComPtr() : ptr(nullptr) {} // - ComPtr(const ComPtr& other) : ptr(other.ptr) { if (ptr) ptr->AddRef(); } //noexcept in C++11 - ComPtr( ComPtr&& tmp ) : ptr(tmp.release()) {} // - ~ComPtr() { if (ptr) ptr->Release(); } //has exception spec of compiler-generated destructor by default - - ComPtr& operator=(const ComPtr& other) { ComPtr(other).swap(*this); return *this; } //noexcept in C++11 - ComPtr& operator=(ComPtr&& tmp) { swap(tmp); return *this; } // - //don't use unifying assignment but save one move-construction in the r-value case instead! - - void swap(ComPtr& rhs) { std::swap(ptr, rhs.ptr); } //noexcept in C++11 - - T** init() //get pointer for use with ::CoCreateInstance() - { - ComPtr<T>().swap(*this); - return &ptr; - } - - T* get() const { return ptr; } - - T* operator->() const { return ptr; } - T& operator* () const { return *ptr; } - - T* release() //noexcept in C++11 - { - T* tmp = ptr; - ptr = nullptr; - return tmp; - } - -private: - T* ptr; - - struct ConversionToBool { int dummy; }; -public: - //use member pointer as implicit conversion to bool (C++ Templates - Vandevoorde/Josuttis; chapter 20) - operator int ConversionToBool::* () const { return ptr != nullptr ? &ConversionToBool::dummy : nullptr; } -}; - - -template <class S, class T> -ComPtr<S> com_dynamic_cast(const ComPtr<T>& other); //noexcept in C++11 - - - - - - - - - - - - - - - - - - - - - - -//################# implementation ############################# - -//we cannot partially specialize std::swap() for a class template and are not allowed to overload it => offer swap in own namespace -template <class T> inline -void swap(zen::ComPtr<T>& lhs, zen::ComPtr<T>& rhs) -{ - lhs.swap(rhs); -} - - -template <class S, class T> inline -ComPtr<S> com_dynamic_cast(const ComPtr<T>& other) //noexcept in C++11 -{ - ComPtr<S> outPtr; - if (other) - other->QueryInterface(IID_PPV_ARGS(outPtr.init())); - return outPtr; -} -} - -#endif //SMART_COM_PTR_H
\ No newline at end of file diff --git a/zen/com_util.h b/zen/com_util.h deleted file mode 100644 index 5189b48e..00000000 --- a/zen/com_util.h +++ /dev/null @@ -1,121 +0,0 @@ -// ************************************************************************** -// * 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 COM_UTILITY_HEADER -#define COM_UTILITY_HEADER - -#include "com_ptr.h" -#include <string> -#include <cassert> - -namespace zen -{ -//get an enumeration interface as a std::vector of bound(!) ComPtr(s) -template <class T, class U> -std::vector<ComPtr<T>> convertEnum(const ComPtr<U>& enumObj); //enumObj: must have the "_NewEnum" property that supports the IEnumUnknown interface - -/* -extract text from com object member function returning a single BSTR: HRESULT ComInterface::MemFun([out] BSTR *pbstr); - Example: ComPtr<...> comObj =...; - std::wstring description = getText(comObj, &IUPnPDevice::get_Description); -*/ -template <class T, class MemFun> -std::wstring getText(ComPtr<T> comObj, MemFun memFun); - - -//RAII class handling BSTR -class Bstring -{ -public: - Bstring(const std::wstring& str) { str_ = ::SysAllocStringLen(str.data(), str.length()); } //string::data() returns unmodified string potentially containing 0-values - ~Bstring() { if (str_) ::SysFreeString(str_); } - - const BSTR get() const { return str_; } - -private: - Bstring(const Bstring&); //not implemented - Bstring& operator=(const Bstring&); // - - BSTR str_; -}; - - - - - - - - - - - - - - - - - - - - - - - - - -//############################ inline implemenatation ################################## -template <class T, class U> inline -std::vector<ComPtr<T>> convertEnum(const ComPtr<U>& enumObj) -{ - std::vector<ComPtr<T>> output; - - if (enumObj) - { - ComPtr<IUnknown> unknown; - enumObj->get__NewEnum(unknown.init()); - ComPtr<IEnumUnknown> enumUnknown = com_dynamic_cast<IEnumUnknown>(unknown); - - assert(enumUnknown); //IEnumUnknown must be supported! - if (enumUnknown) - { - ComPtr<IUnknown> itemTmp; - while (enumUnknown->Next(1, itemTmp.init(), nullptr) == S_OK) //returns S_FALSE == 1 when finished! Don't use SUCCEEDED()!!! - { - ComPtr<T> itemNew = com_dynamic_cast<T>(itemTmp); - if (itemNew) - output.push_back(itemNew); - } - } - } - - return output; -} - - -template <class T, class MemFun> inline -std::wstring getText(ComPtr<T> comObj, MemFun memFun) -{ - std::wstring text; - { - if (!comObj) - return std::wstring(); - - BSTR bstr = nullptr; - if (FAILED((comObj.get()->*memFun)(&bstr))) - return std::wstring(); - - if (bstr) //nullptr means "no text" - { - text = std::wstring(bstr, ::SysStringLen(bstr)); //correctly copy 0-characters - ::SysFreeString(bstr); - } - } - return text; -} -} - - -#endif //COM_UTILITY_HEADER diff --git a/zen/debug_log.h b/zen/debug_log.h deleted file mode 100644 index ad27b66e..00000000 --- a/zen/debug_log.h +++ /dev/null @@ -1,94 +0,0 @@ -// ************************************************************************** -// * 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 DEBUG_LOG_HEADER_017324601673246392184621895740256342 -#define DEBUG_LOG_HEADER_017324601673246392184621895740256342 - -#include <string> -#include <cstdio> -#include <memory> -#include "deprecate.h" -#include "string_tools.h" -#include "time.h" - - -//small macro for writing debug information into a logfile -#define WRITE_LOG(x) globalLogFile().write(__FILE__, __LINE__, x); - -//speed alternative: wxLogDebug(wxT("text")) + DebugView - - -namespace zen -{ -#ifdef ZEN_WIN -const char ZEN_FILE_NAME_SEPARATOR = '\\'; -#elif defined ZEN_LINUX || defined ZEN_MAC -const char ZEN_FILE_NAME_SEPARATOR = '/'; -#endif - -class DebugLog -{ -public: - class LogError {}; - - ZEN_DEPRECATE - DebugLog(const std::string& filePrefix = std::string()) : - filename(filePrefix + "DEBUG_" + formatTime<std::string>("%Y-%m-%d %H%M%S") + ".log"), - rowCount(0), - handle(std::fopen(filename.c_str(), "w")) //Windows: non binary mode: automatically convert "\n" to "\r\n"; Linux: binary is default! - { - if (!handle) - throw LogError(); - } - - ~DebugLog() { std::fclose(handle); } - - void write(const std::string& sourceFile, - int sourceRow, - const std::string& message) - { - const std::string logEntry = "[" + formatTime<std::string>(FORMAT_TIME) + "] " + afterLast(sourceFile, ZEN_FILE_NAME_SEPARATOR) + - " (" + numberTo<std::string>(sourceRow) + "): " + message + "\n"; - - const size_t bytesWritten = ::fwrite(logEntry.c_str(), 1, logEntry.size(), handle); - if (std::ferror(handle) != 0 || bytesWritten != logEntry.size()) - throw LogError(); - - if (std::fflush(handle) != 0) - throw LogError(); - - ++rowCount; - } - - size_t getRows() const { return rowCount; } - - std::string getFileName() const { return filename; } - -private: - std::string filename; - size_t rowCount; - FILE* handle; -}; - - -inline -DebugLog& globalLogFile() -{ - static std::unique_ptr<DebugLog> inst(new DebugLog); //external linkage despite header definition! - - if (inst->getRows() > 50000) //prevent logfile from becoming too big - { - const std::string oldName = inst->getFileName(); - inst.reset(); - std::remove(oldName.c_str()); //unchecked deletion! - inst.reset(new DebugLog); - } - - return *inst; -} -} - -#endif //DEBUG_LOG_HEADER_017324601673246392184621895740256342 diff --git a/zen/debug_memory_leaks.cpp b/zen/debug_memory_leaks.cpp deleted file mode 100644 index 2359b6ef..00000000 --- a/zen/debug_memory_leaks.cpp +++ /dev/null @@ -1,30 +0,0 @@ -// ************************************************************************** -// * 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 * -// ************************************************************************** - -//-----------Memory Leak Detection-------------------------- -//Usage: just include this file into a Visual Studio project - - -#ifdef _DEBUG //When _DEBUG is not defined, calls to _CrtSetDbgFlag are removed during preprocessing. -#define _CRTDBG_MAP_ALLOC // -#include <stdlib.h> //keep this order: "The #include statements must be in the order shown here. If you change the order, the functions you use may not work properly." -#include <crtdbg.h> //overwrites "operator new" ect; no need to include this in every compilation unit! -//http://msdn.microsoft.com/en-us/library/e5ewb1h3(v=vs.80).aspx - -namespace -{ -struct OnStartup -{ - OnStartup() - { - //note: wxWidgets also activates leak detection in "src/common/init.cpp" using a macro that is equivalent to: - int flags = _CrtSetDbgFlag(_CRTDBG_REPORT_FLAG); - _CrtSetDbgFlag(flags | _CRTDBG_ALLOC_MEM_DF | _CRTDBG_LEAK_CHECK_DF); - } - -} dummy; -} -#endif //_DEBUG
\ No newline at end of file diff --git a/zen/debug_minidump.cpp b/zen/debug_minidump.cpp deleted file mode 100644 index 29500ae4..00000000 --- a/zen/debug_minidump.cpp +++ /dev/null @@ -1,143 +0,0 @@ -// ************************************************************************** -// * 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 * -// ************************************************************************** - -#include "debug_minidump.h" -#include <string> -#include <sstream> -#include <cassert> -#include <cstdlib> //malloc(), free() -#include <zen/file_error.h> -#include <zen/scope_guard.h> -#include <zen/time.h> -#include "win.h" //includes "windows.h" -#include "DbgHelp.h" //available for MSC only -#pragma comment(lib, "Dbghelp.lib") - -using namespace zen; - - -namespace -{ -LONG WINAPI writeDumpOnException(EXCEPTION_POINTERS* pExceptionInfo) //blocks showing message boxes on success and error! -{ - assert(false); - - const Zstring filename = L"CrashDump " + formatTime<Zstring>(L"%Y-%m-%d %H%M%S") + L".dmp"; - - { - HANDLE hFile = ::CreateFile(filename.c_str(), GENERIC_READ | GENERIC_WRITE, 0, nullptr, CREATE_NEW, FILE_ATTRIBUTE_NORMAL, nullptr); - if (hFile == INVALID_HANDLE_VALUE) - { - ::MessageBox(nullptr, (replaceCpy<std::wstring>(L"Cannot write file %x.", L"%x", fmtFileName(filename)) + L"\n\n" + formatSystemError(L"CreateFile", ::GetLastError())).c_str(), L"Application Crash", MB_SERVICE_NOTIFICATION | MB_ICONERROR); - std::terminate(); - } - ZEN_ON_SCOPE_EXIT(::CloseHandle(hFile)); - - MINIDUMP_EXCEPTION_INFORMATION exInfo = {}; - exInfo.ThreadId = ::GetCurrentThreadId(); - exInfo.ExceptionPointers = pExceptionInfo; - exInfo.ClientPointers = FALSE; - - MINIDUMP_EXCEPTION_INFORMATION* exceptParam = pExceptionInfo ? &exInfo : nullptr; - - if (!::MiniDumpWriteDump(::GetCurrentProcess (), //__in HANDLE hProcess, - ::GetCurrentProcessId(), //__in DWORD ProcessId, - hFile, //__in HANDLE hFile, - MiniDumpWithDataSegs, //__in MINIDUMP_TYPE DumpType, ->Standard: MiniDumpNormal, Medium: MiniDumpWithDataSegs, Full: MiniDumpWithFullMemory - exceptParam, //__in PMINIDUMP_EXCEPTION_INFORMATION ExceptionParam, - nullptr, //__in PMINIDUMP_USER_STREAM_INFORMATION UserStreamParam, - nullptr)) //__in PMINIDUMP_CALLBACK_INFORMATION CallbackParam - { - ::MessageBox(nullptr, (replaceCpy<std::wstring>(L"Cannot write file %x.", L"%x", fmtFileName(filename)) + L"\n\n" + formatSystemError(L"MiniDumpWriteDump", ::GetLastError())).c_str(), L"Application Crash", MB_SERVICE_NOTIFICATION | MB_ICONERROR); - std::terminate(); - } - } //close file before showing success message - - //attention: the app has not yet officially crashed! => use MB_SERVICE_NOTIFICATION to avoid Win32 GUI callbacks while message box is shown! - ::MessageBox(nullptr, replaceCpy<std::wstring>(L"Crash dump file %x written!", L"%x", fmtFileName(filename)).c_str(), L"Application Crash", MB_SERVICE_NOTIFICATION | MB_ICONERROR); - std::terminate(); - - return EXCEPTION_EXECUTE_HANDLER; -} - -//ensure that a dump-file is written for uncaught exceptions -struct OnStartup { - OnStartup() - { - /*LPTOP_LEVEL_EXCEPTION_FILTER oldFilter = */ ::SetUnhandledExceptionFilter(writeDumpOnException); - //oldFilter == &__CxxUnhandledExceptionFilter() by default! - }} dummy; -} - - -void debug_tools::writeMinidump() -{ - //force exception to catch the state of this thread and hopefully get a valid call stack - __try - { - ::RaiseException(EXCEPTION_BREAKPOINT, 0, 0, nullptr); - } - __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 -} - - -/* -No need to include the "operator new" declarations into every compilation unit: - -[basic.stc.dynamic] -"A C++ program shall provide at most one definition of a replaceable allocation or deallocation function. -Any such function definition replaces the default version provided in the library (17.6.4.6). -The following allocation and deallocation functions (18.6) are implicitly declared in global scope in each translation unit of a program. -void* operator new(std::size_t); -void* operator new[](std::size_t); -void operator delete(void*); -void operator delete[](void*);" -*/ - -namespace -{ -class BadAllocDetailed : public std::bad_alloc -{ -public: - explicit BadAllocDetailed(size_t allocSize) - { - errorMsg = "Memory allocation failed: "; - errorMsg += numberToString(allocSize); - } - - virtual const char* what() const throw() - { - return errorMsg.c_str(); - } - -private: - template <class T> - static std::string numberToString(const T& number) //convert number to string the (slow) C++ way - { - std::ostringstream ss; - ss << number; - return ss.str(); - } - - std::string errorMsg; -}; -} - -void* operator new(size_t size) -{ - if (void* ptr = ::malloc(size)) - return ptr; - - debug_tools::writeMinidump(); - throw ::BadAllocDetailed(size); -} - -void operator delete(void* ptr) { ::free(ptr); } - -void* operator new[](size_t size) { return operator new(size); } -void operator delete[](void* ptr) { operator delete(ptr); } diff --git a/zen/debug_minidump.h b/zen/debug_minidump.h deleted file mode 100644 index 2ef43039..00000000 --- a/zen/debug_minidump.h +++ /dev/null @@ -1,38 +0,0 @@ -// ************************************************************************** -// * 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 DEBUGNEW_H_INCLUDED -#define DEBUGNEW_H_INCLUDED - -#ifndef _MSC_VER -#error currently for use with MSC only -#endif - -/* -Better std::bad_alloc ---------------------- -overwrite "operator new" to automatically write mini dump and get info about bytes requested: -1. Compile "debug_minidump.cpp" - -Minidumps http://msdn.microsoft.com/en-us/library/windows/desktop/ee416349(v=vs.85).aspx ----------------------------------------------------------------------------------------- -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). -Optional: - - C/C++ -> Optimization: Disabled (/Od) -*/ - -namespace debug_tools -{ -void writeMinidump(); -} - -#endif // DEBUGNEW_H_INCLUDED diff --git a/zen/file_handling.cpp b/zen/file_handling.cpp index 563a07ce..e7503dad 100644 --- a/zen/file_handling.cpp +++ b/zen/file_handling.cpp @@ -106,8 +106,23 @@ bool zen::somethingExists(const Zstring& objname) const DWORD attr = ::GetFileAttributes(applyLongPathPrefix(objname).c_str()); if (attr != INVALID_FILE_ATTRIBUTES) return true; - if (::GetLastError() == ERROR_SHARING_VIOLATION) //"C:\pagefile.sys" - return true; + const ErrorCode lastError = getLastError(); + + //handle obscure file permission problem where ::GetFileAttributes() fails with ERROR_ACCESS_DENIED or ERROR_SHARING_VIOLATION + //while parent directory traversal is successful: e.g. "C:\pagefile.sys" + if (lastError != ERROR_PATH_NOT_FOUND && //perf: short circuit for common "not existing" error codes + lastError != ERROR_FILE_NOT_FOUND && // + lastError != ERROR_BAD_NETPATH && // + lastError != ERROR_BAD_NET_NAME) // + { + WIN32_FIND_DATA fileInfo = {}; + const HANDLE searchHandle = ::FindFirstFile(applyLongPathPrefix(objname).c_str(), &fileInfo); + if (searchHandle != INVALID_HANDLE_VALUE) + { + ::FindClose(searchHandle); + return true; + } + } #elif defined ZEN_LINUX || defined ZEN_MAC struct ::stat fileInfo = {}; @@ -238,7 +253,7 @@ bool zen::removeFile(const Zstring& filename) //throw FileError } #endif if (!somethingExists(filename)) //warning: changes global error code!! - return false; //neither file nor any other object (e.g. broken symlink) with that name existing + return false; //neither file nor any other object (e.g. broken symlink) with that name existing - caveat: what if "access is denied"!?!??!?!? //begin of "regular" error reporting const std::wstring errorMsg = replaceCpy(_("Cannot delete file %x."), L"%x", fmtFileName(filename)); @@ -2006,7 +2021,7 @@ void copyFileWindowsDefault(const Zstring& sourceFile, if (lastError == ERROR_PATH_NOT_FOUND) { guardTarget.dismiss(); //not relevant - throw ErrorTargetPathMissing(errorMsg, errorDescr); + throw ErrorTargetPathMissing(errorMsg, errorDescr); //could this also be source path missing!? } try //add more meaningful message diff --git a/zen/file_traverser.cpp b/zen/file_traverser.cpp index 70593d1d..389833f2 100644 --- a/zen/file_traverser.cpp +++ b/zen/file_traverser.cpp @@ -353,8 +353,8 @@ private: typename Trav::DirHandle searchHandle; - if (!tryReportingDirError([&] { Trav::create(dirname, searchHandle); /*throw FileError*/ }, sink)) - return; //ignored error + if (!tryReportingDirError([&] { Trav::create(dirname, searchHandle); /*throw FileError*/ }, sink)) + return; //ignored error ZEN_ON_SCOPE_EXIT(Trav::destroy(searchHandle)); typename Trav::FindData findData = {}; @@ -14,9 +14,11 @@ //minimal layer enabling text translation - without platform/library dependencies! +#ifdef __WXMSW__ //we have wxWidgets #ifndef WXINTL_NO_GETTEXT_MACRO #error WXINTL_NO_GETTEXT_MACRO must be defined to deactivate wxWidgets underscore macro #endif +#endif #define ZEN_TRANS_CONCAT_SUB(X, Y) X ## Y #define _(s) zen::implementation::translate(ZEN_TRANS_CONCAT_SUB(L, s)) diff --git a/zen/read_txt.cpp b/zen/read_txt.cpp deleted file mode 100644 index 23649846..00000000 --- a/zen/read_txt.cpp +++ /dev/null @@ -1,99 +0,0 @@ -// ************************************************************************** -// * 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 * -// ************************************************************************** - -#include "read_txt.h" - -using namespace zen; - - -namespace -{ -warn_static("superfluous method") -std::string detectLineBreak(const Zstring& filename) //throw FileError -{ - //read a (hopefully) significant portion of data - zen::FileInput input(filename); - - std::vector<char> buffer(64 * 1024); - size_t bytesRead = input.read(&buffer[0], buffer.size()); //throw FileError - buffer.resize(bytesRead); - - //detect line break - std::string linebreakChars = "\r\n"; - std::vector<char>::iterator iter = std::find_first_of(buffer.begin(), buffer.end(), - linebreakChars.begin(), linebreakChars.end()); - if (iter != buffer.end()) - { - if (*iter == '\r') - { - ++iter; - if (iter != buffer.end()) - { - - if (*iter == '\n') - return "\r\n"; //Windows - else - return "\r"; //Mac - } - } - else if (*iter == '\n') - return "\n"; //Linux - } - //fallback - return "\n"; -} -} - - -LineExtractor::LineExtractor(const Zstring& filename, const std::string& lineBreak) : //throw FileError - inputStream(filename), bufferLogBegin(buffer.begin()), lineBreak_(lineBreak) -{ - if (lineBreak.empty()) - lineBreak_ = detectLineBreak(filename); //throw FileError -} - - -bool LineExtractor::getLine(std::string& output) //throw FileError -{ - warn_static("don't use lineBreak, but support any of r, n, rn!!!") - for (;;) - { - //check if full line is in buffer - std::vector<char>::iterator iter = std::search(bufferLogBegin, buffer.end(), lineBreak_.begin(), lineBreak_.end()); - if (iter != buffer.end()) - { - output.assign(bufferLogBegin, iter); - bufferLogBegin = iter + lineBreak_.size(); - return true; - } - - buffer.erase(buffer.begin(), bufferLogBegin); - bufferLogBegin = buffer.begin(); - - //if done: cleanup - if (inputStream.eof()) - { - if (buffer.empty()) - return false; - - output.assign(buffer.begin(), buffer.end()); - buffer.clear(); - return true; - } - - //read next block - const size_t BLOCK_SIZE = 512 * 1024; - buffer.resize(buffer.size() + BLOCK_SIZE); - - size_t bytesRead = inputStream.read(&buffer[0] + buffer.size() - BLOCK_SIZE, BLOCK_SIZE); //throw FileError - assert(bytesRead <= BLOCK_SIZE); //promised by FileInput() - - if (bytesRead < BLOCK_SIZE) - buffer.resize(buffer.size() - (BLOCK_SIZE - bytesRead)); - - bufferLogBegin = buffer.begin(); - } -} diff --git a/zen/read_txt.h b/zen/read_txt.h deleted file mode 100644 index 92892716..00000000 --- a/zen/read_txt.h +++ /dev/null @@ -1,32 +0,0 @@ -// ************************************************************************** -// * 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 PARSE_TXT_H_INCLUDED -#define PARSE_TXT_H_INCLUDED - -#include "file_io.h" -#include <vector> -#include <string> - -namespace zen -{ -class LineExtractor -{ -public: - LineExtractor(const Zstring& filename, const std::string& lineBreak = std::string()); //throw FileError - bool getLine(std::string& output); //throw FileError - -private: - zen::FileInput inputStream; - std::vector<char> buffer; - std::vector<char>::iterator bufferLogBegin; - std::string lineBreak_; -}; - -} - - -#endif // PARSE_TXT_H_INCLUDED diff --git a/zen/recycler.cpp b/zen/recycler.cpp index 16c2ac11..11b599d4 100644 --- a/zen/recycler.cpp +++ b/zen/recycler.cpp @@ -103,13 +103,13 @@ void zen::recycleOrDelete(const std::vector<Zstring>& filenames, const std::func if (!moveToRecycler(&cNames[0], cNames.size(), recyclerCallback, &cbd)) { if (cbd.exceptionInUserCallback) - try - { - assert(notifyDeletionStatus); - notifyDeletionStatus(Zstring()); //should throw again!!! - assert(false); - } - catch (...) { throw; } + try + { + assert(notifyDeletionStatus); + notifyDeletionStatus(Zstring()); //should throw again!!! + assert(false); + } + catch (...) { throw; } std::wstring filenameFmt = fmtFileName(filenames[0]); //probably not the correct file name for file lists larger than 1! if (filenames.size() > 1) diff --git a/zen/recycler.h b/zen/recycler.h index 80b31160..8068c4ec 100644 --- a/zen/recycler.h +++ b/zen/recycler.h @@ -46,8 +46,8 @@ StatusRecycler recycleBinStatus(const Zstring& pathName); //test existence of Re //Win: blocks heavily if recycle bin is really full and drive is slow!!! void recycleOrDelete(const std::vector<Zstring>& filenames, //throw FileError, return "true" if file/dir was actually deleted - //may throw: first exception is swallowed, updateStatus() is then called again where it should throw again and the exception will propagate as expected - const std::function<void (const Zstring& currentItem)>& notifyDeletionStatus); //optional; currentItem may be empty + //may throw: first exception is swallowed, updateStatus() is then called again where it should throw again and the exception will propagate as expected + const std::function<void (const Zstring& currentItem)>& notifyDeletionStatus); //optional; currentItem may be empty #endif } diff --git a/zen/scroll_window_under_cursor.cpp b/zen/scroll_window_under_cursor.cpp deleted file mode 100644 index 76a5ab4a..00000000 --- a/zen/scroll_window_under_cursor.cpp +++ /dev/null @@ -1,72 +0,0 @@ -// ************************************************************************** -// * 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 * -// ************************************************************************** - -//redirect mouse wheel events directly to window under cursor rather than window having input focus -//implementing new Windows Vista UI guidelines: http://msdn.microsoft.com/en-us/library/bb545459.aspx#wheel -//this is confirmed to be required for at least Windows 2000 to Windows 8 -//on Ubuntu Linux, this is already the default behavior - -//Usage: just include this file into a Windows project - -#include <cassert> -#include "win.h" //includes "windows.h" -#include <Windowsx.h> //WM_MOUSEWHEEL - - -namespace -{ -LRESULT CALLBACK mouseInputHook(int nCode, WPARAM wParam, LPARAM lParam) -{ - //"if nCode is less than zero, the hook procedure must pass the message to the CallNextHookEx function - //without further processing and should return the value returned by CallNextHookEx" - if (nCode == HC_ACTION) //the only valid value for this hook type - { - MSG& msgInfo = *reinterpret_cast<MSG*>(lParam); - - if (msgInfo.message == WM_MOUSEWHEEL || - msgInfo.message == WM_MOUSEHWHEEL) - { - POINT pt = {}; - pt.x = GET_X_LPARAM(msgInfo.lParam); //yes, there's also msgInfo.pt, but let's not take chances - pt.y = GET_Y_LPARAM(msgInfo.lParam); // - - //visible child window directly under cursor; attention: not necessarily from our process! - if (HWND hWin = ::WindowFromPoint(pt)) //http://blogs.msdn.com/b/oldnewthing/archive/2010/12/30/10110077.aspx - if (msgInfo.hwnd != hWin && ::GetCapture() == nullptr) - { - DWORD winProcessId = 0; - ::GetWindowThreadProcessId( //no-fail! - hWin, //_In_ HWND hWnd, - &winProcessId); //_Out_opt_ LPDWORD lpdwProcessId - if (winProcessId == ::GetCurrentProcessId()) //no-fail! - msgInfo.hwnd = hWin; //it would be a bug to set handle from another process here - } - } - } - return ::CallNextHookEx(nullptr, nCode, wParam, lParam); -} - -struct InstallMouseHook -{ - InstallMouseHook() - { - hHook = ::SetWindowsHookEx(WH_GETMESSAGE, //__in int idHook, - mouseInputHook, //__in HOOKPROC lpfn, - nullptr, //__in HINSTANCE hMod, - ::GetCurrentThreadId()); //__in DWORD dwThreadId - assert(hHook); - } - - ~InstallMouseHook() - { - if (hHook) - ::UnhookWindowsHookEx(hHook); - } - -private: - HHOOK hHook; -} dummy; -} diff --git a/zen/stl_tools.h b/zen/stl_tools.h index 92cd86ad..38752e67 100644 --- a/zen/stl_tools.h +++ b/zen/stl_tools.h @@ -94,7 +94,7 @@ void vector_remove_if(V& vec, Predicate p) template <class V, class W> inline void vector_append(V& vec, W& vec2) { -vec.insert(vec.end(), vec2.begin(), vec2.end()); + vec.insert(vec.end(), vec2.begin(), vec2.end()); } diff --git a/zen/string_base.h b/zen/string_base.h index 0e3bbdd3..c134a6fc 100644 --- a/zen/string_base.h +++ b/zen/string_base.h @@ -171,7 +171,7 @@ private: Descriptor(int rc, size_t len, size_t cap) : length (static_cast<std::uint32_t>(len)), capacity(static_cast<std::uint32_t>(cap)), - refCount(rc) { assert_static(ATOMIC_INT_LOCK_FREE == 2); } //2: "the types are always lock-free" + refCount(rc) { assert_static(ATOMIC_INT_LOCK_FREE == 2); } //2: "the types are always lock-free" std::uint32_t length; std::uint32_t capacity; //allocated size without null-termination diff --git a/zen/xml_io.cpp b/zen/xml_io.cpp new file mode 100644 index 00000000..4b9abc29 --- /dev/null +++ b/zen/xml_io.cpp @@ -0,0 +1,88 @@ +// ************************************************************************** +// * 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 * +// ************************************************************************** + +#include "xml_io.h" +#include <zen/file_handling.h> +#include <zen/file_io.h> +#include <zen/serialize.h> + +using namespace zen; + + +XmlDoc zen::loadXmlDocument(const Zstring& filename) //throw FileError +{ + //can't simply use zen::loadBinStream() due to the short-circuit xml-validation below! + + std::string stream; + + FileInput inputFile(filename); //throw FileError + { + //quick test whether input is an XML: avoid loading large binary files up front! + const std::string xmlBegin = "<?xml version="; + stream.resize(strLength(BYTE_ORDER_MARK_UTF8) + xmlBegin.size()); + + const size_t bytesRead = inputFile.read(&stream[0], stream.size()); //throw FileError + stream.resize(bytesRead); + + if (!startsWith(stream, xmlBegin) && + !startsWith(stream, BYTE_ORDER_MARK_UTF8 + xmlBegin)) //respect BOM! + throw FileError(replaceCpy(_("File %x does not contain a valid configuration."), L"%x", fmtFileName(filename))); + } + + const size_t blockSize = 128 * 1024; + do + { + stream.resize(stream.size() + blockSize); + + const size_t bytesRead = inputFile.read(&*stream.begin() + stream.size() - blockSize, blockSize); //throw FileError + if (bytesRead < blockSize) + stream.resize(stream.size() - (blockSize - bytesRead)); //caveat: unsigned arithmetics + } + while (!inputFile.eof()); + + try + { + return parse(stream); //throw XmlParsingError + } + catch (const XmlParsingError& e) + { + throw FileError( + replaceCpy(replaceCpy(replaceCpy(_("Error parsing file %x, row %y, column %z."), + L"%x", fmtFileName(filename)), + L"%y", numberTo<std::wstring>(e.row + 1)), + L"%z", numberTo<std::wstring>(e.col + 1))); + } +} + + +void zen::saveXmlDocument(const XmlDoc& doc, const Zstring& filename) //throw FileError +{ + std::string stream = serialize(doc); //noexcept + + try + { + if (getFilesize(filename) == stream.size()) //throw FileError + if (loadBinStream<std::string>(filename) == stream) //throw FileError + return; + } + catch (FileError&) {} + + FileOutput outputFile(filename, FileOutput::ACC_OVERWRITE); //throw FileError + outputFile.write(stream.c_str(), stream.length()); // +} + + +void zen::checkForMappingErrors(const XmlIn& xmlInput, const Zstring& filename) //throw FileError +{ + if (xmlInput.errorsOccured()) + { + std::wstring msg = _("Cannot read the following XML elements:") + L"\n"; + for (const std::wstring& elem : xmlInput.getErrorsAs<std::wstring>()) + msg += L"\n" + elem; + + throw FileError(replaceCpy(_("Configuration file %x loaded partially only."), L"%x", fmtFileName(filename)) + L"\n\n" + msg); + } +} diff --git a/zen/xml_io.h b/zen/xml_io.h new file mode 100644 index 00000000..b53a5ef4 --- /dev/null +++ b/zen/xml_io.h @@ -0,0 +1,27 @@ +// ************************************************************************** +// * 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 XMLBASE_H_INCLUDED +#define XMLBASE_H_INCLUDED + +#include <zenxml/xml.h> +#include <zen/zstring.h> +#include <zen/file_error.h> + +//combine zen::Xml and zen file i/o +//-> loadXmlDocument vs loadStream: +//1. better error reporting +//2. quick exit if (potentially large) input file is not an XML + +namespace zen +{ +XmlDoc loadXmlDocument(const Zstring& filename); //throw FileError +void checkForMappingErrors(const XmlIn& xmlInput, const Zstring& filename); //throw FileError + +void saveXmlDocument(const XmlDoc& doc, const Zstring& filename); //throw FileError +} + +#endif // XMLBASE_H_INCLUDED |