diff options
author | Daniel Wilhelm <daniel@wili.li> | 2014-04-18 17:13:13 +0200 |
---|---|---|
committer | Daniel Wilhelm <daniel@wili.li> | 2014-04-18 17:13:13 +0200 |
commit | 7f23ee90fd545995a29e2175f15e8b97e59ca67a (patch) | |
tree | f8d0afac51995032e58b9a475ccbbc73ba207baf /shared | |
parent | 3.19 (diff) | |
download | FreeFileSync-7f23ee90fd545995a29e2175f15e8b97e59ca67a.tar.gz FreeFileSync-7f23ee90fd545995a29e2175f15e8b97e59ca67a.tar.bz2 FreeFileSync-7f23ee90fd545995a29e2175f15e8b97e59ca67a.zip |
3.20
Diffstat (limited to 'shared')
95 files changed, 704 insertions, 533 deletions
diff --git a/shared/IFileOperation/dll_main.cpp b/shared/IFileOperation/dll_main.cpp index ab387012..3805c99d 100644 --- a/shared/IFileOperation/dll_main.cpp +++ b/shared/IFileOperation/dll_main.cpp @@ -3,7 +3,7 @@ // * GNU General Public License: http://www.gnu.org/licenses/gpl.html * // * Copyright (C) 2008-2011 ZenJu (zhnmju123 AT gmx.de) * // ************************************************************************** -// + #define WIN32_LEAN_AND_MEAN #include <windows.h> diff --git a/shared/IFileOperation/file_op.cpp b/shared/IFileOperation/file_op.cpp index fc942f44..a2cf9413 100644 --- a/shared/IFileOperation/file_op.cpp +++ b/shared/IFileOperation/file_op.cpp @@ -3,7 +3,7 @@ // * GNU General Public License: http://www.gnu.org/licenses/gpl.html * // * Copyright (C) 2008-2011 ZenJu (zhnmju123 AT gmx.de) * // ************************************************************************** -// + #include "file_op.h" #include "../com_ptr.h" #include "../com_error.h" diff --git a/shared/IFileOperation/file_op.h b/shared/IFileOperation/file_op.h index 25098e45..c1bb26a2 100644 --- a/shared/IFileOperation/file_op.h +++ b/shared/IFileOperation/file_op.h @@ -3,7 +3,7 @@ // * GNU General Public License: http://www.gnu.org/licenses/gpl.html * // * Copyright (C) 2008-2011 ZenJu (zhnmju123 AT gmx.de) * // ************************************************************************** -// + #ifndef RECYCLER_DLL_H #define RECYCLER_DLL_H diff --git a/shared/ShadowCopy/LockFile.cpp b/shared/ShadowCopy/LockFile.cpp index 0761a3e3..7df3ec66 100644 --- a/shared/ShadowCopy/LockFile.cpp +++ b/shared/ShadowCopy/LockFile.cpp @@ -3,7 +3,7 @@ // * GNU General Public License: http://www.gnu.org/licenses/gpl.html * // * Copyright (C) 2008-2011 ZenJu (zhnmju123 AT gmx.de) * // ************************************************************************** -// + #include <string> #include <iostream> diff --git a/shared/ShadowCopy/dll_main.cpp b/shared/ShadowCopy/dll_main.cpp index ab387012..3805c99d 100644 --- a/shared/ShadowCopy/dll_main.cpp +++ b/shared/ShadowCopy/dll_main.cpp @@ -3,7 +3,7 @@ // * GNU General Public License: http://www.gnu.org/licenses/gpl.html * // * Copyright (C) 2008-2011 ZenJu (zhnmju123 AT gmx.de) * // ************************************************************************** -// + #define WIN32_LEAN_AND_MEAN #include <windows.h> diff --git a/shared/ShadowCopy/shadow.cpp b/shared/ShadowCopy/shadow.cpp index d536470a..8b7b9971 100644 --- a/shared/ShadowCopy/shadow.cpp +++ b/shared/ShadowCopy/shadow.cpp @@ -3,7 +3,7 @@ // * GNU General Public License: http://www.gnu.org/licenses/gpl.html * // * Copyright (C) 2008-2011 ZenJu (zhnmju123 AT gmx.de) * // ************************************************************************** -// + #include "shadow.h" #include <algorithm> #include <string> diff --git a/shared/ShadowCopy/shadow.h b/shared/ShadowCopy/shadow.h index a96d8578..b21395da 100644 --- a/shared/ShadowCopy/shadow.h +++ b/shared/ShadowCopy/shadow.h @@ -3,7 +3,7 @@ // * GNU General Public License: http://www.gnu.org/licenses/gpl.html * // * Copyright (C) 2008-2011 ZenJu (zhnmju123 AT gmx.de) * // ************************************************************************** -// + #ifndef SHADOWCOPY_H #define SHADOWCOPY_H diff --git a/shared/Taskbar_Seven/dll_main.cpp b/shared/Taskbar_Seven/dll_main.cpp index ab387012..3805c99d 100644 --- a/shared/Taskbar_Seven/dll_main.cpp +++ b/shared/Taskbar_Seven/dll_main.cpp @@ -3,7 +3,7 @@ // * GNU General Public License: http://www.gnu.org/licenses/gpl.html * // * Copyright (C) 2008-2011 ZenJu (zhnmju123 AT gmx.de) * // ************************************************************************** -// + #define WIN32_LEAN_AND_MEAN #include <windows.h> diff --git a/shared/Taskbar_Seven/taskbar.cpp b/shared/Taskbar_Seven/taskbar.cpp index 297a0739..bbbaaf7d 100644 --- a/shared/Taskbar_Seven/taskbar.cpp +++ b/shared/Taskbar_Seven/taskbar.cpp @@ -3,7 +3,7 @@ // * GNU General Public License: http://www.gnu.org/licenses/gpl.html * // * Copyright (C) 2008-2011 ZenJu (zhnmju123 AT gmx.de) * // ************************************************************************** -// + #include "taskbar.h" #define WIN32_LEAN_AND_MEAN diff --git a/shared/Taskbar_Seven/taskbar.h b/shared/Taskbar_Seven/taskbar.h index d52420ab..3bae28a9 100644 --- a/shared/Taskbar_Seven/taskbar.h +++ b/shared/Taskbar_Seven/taskbar.h @@ -3,7 +3,7 @@ // * GNU General Public License: http://www.gnu.org/licenses/gpl.html * // * Copyright (C) 2008-2011 ZenJu (zhnmju123 AT gmx.de) * // ************************************************************************** -// + #ifndef TASKBAR_SEVEN_DLL_H #define TASKBAR_SEVEN_DLL_H diff --git a/shared/app_main.cpp b/shared/app_main.cpp index b727724f..28ce1e09 100644 --- a/shared/app_main.cpp +++ b/shared/app_main.cpp @@ -3,7 +3,7 @@ // * GNU General Public License: http://www.gnu.org/licenses/gpl.html * // * Copyright (C) 2008-2011 ZenJu (zhnmju123 AT gmx.de) * // ************************************************************************** -// + #include "app_main.h" #include <wx/window.h> #include <wx/app.h> diff --git a/shared/app_main.h b/shared/app_main.h index 33ddcfb6..fa538771 100644 --- a/shared/app_main.h +++ b/shared/app_main.h @@ -3,7 +3,7 @@ // * GNU General Public License: http://www.gnu.org/licenses/gpl.html * // * Copyright (C) 2008-2011 ZenJu (zhnmju123 AT gmx.de) * // ************************************************************************** -// + #ifndef APPMAIN_H_INCLUDED #define APPMAIN_H_INCLUDED diff --git a/shared/build_info.h b/shared/build_info.h index c3be26bd..f13b2dbc 100644 --- a/shared/build_info.h +++ b/shared/build_info.h @@ -3,7 +3,7 @@ // * GNU General Public License: http://www.gnu.org/licenses/gpl.html * // * Copyright (C) 2008-2011 ZenJu (zhnmju123 AT gmx.de) * // ************************************************************************** -// + #ifndef BUILDINFO_H_INCLUDED #define BUILDINFO_H_INCLUDED diff --git a/shared/c_dll.h b/shared/c_dll.h index f913cde9..15597a9c 100644 --- a/shared/c_dll.h +++ b/shared/c_dll.h @@ -3,7 +3,7 @@ // * GNU General Public License: http://www.gnu.org/licenses/gpl.html * // * Copyright (C) 2008-2011 ZenJu (zhnmju123 AT gmx.de) * // ************************************************************************** -// + #ifndef C_DLL_HEADER #define C_DLL_HEADER diff --git a/shared/check_exist.cpp b/shared/check_exist.cpp deleted file mode 100644 index 6c6c0871..00000000 --- a/shared/check_exist.cpp +++ /dev/null @@ -1,58 +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) 2008-2011 ZenJu (zhnmju123 AT gmx.de) * -// ************************************************************************** -// -#include "check_exist.h" -#include "file_handling.h" -#include <memory> -#include "boost_thread_wrap.h" //include <boost/thread.hpp> - - -/* -#ifdef __MINGW32__ -//oh well, nothing is for free... -//https://svn.boost.org/trac/boost/ticket/4258 -extern "C" void tss_cleanup_implemented() {}; -#endif -*/ - -namespace -{ -typedef Zbase<Zchar, StorageDeepCopy> BasicString; //thread safe string class - -template <bool (*fun)(const Zstring&)> -util::ResultExist checkExistence(const Zstring& objName, size_t timeout) //timeout in ms -{ - using namespace util; - - std::shared_ptr<bool> isExisting = std::make_shared<bool>(false); //no mutex required: accessed after thread has finished only! - BasicString filename = objName.c_str(); //using thread safe string without ref-count! - - boost::thread worker([=]() { *isExisting = fun(filename.c_str()); }); //throw() - - if (worker.timed_join(boost::posix_time::milliseconds(timeout))) - return *isExisting ? EXISTING_TRUE : EXISTING_FALSE; - else - return EXISTING_TIMEOUT; - /* - main/worker thread may access different shared_ptr instances safely (even though they have the same target!) - http://www.boost.org/doc/libs/1_43_0/libs/smart_ptr/shared_ptr.htm?sess=8153b05b34d890e02d48730db1ff7ddc#ThreadSafety - */ -} -} - - -util::ResultExist util::fileExists(const Zstring& filename, size_t timeout) //timeout in ms -{ - assert(!filename.empty()); - return ::checkExistence<zen::fileExists>(filename, timeout); -} - - -util::ResultExist util::dirExists(const Zstring& dirname, size_t timeout) //timeout in ms -{ - assert(!dirname.empty()); - return ::checkExistence<zen::dirExists>(dirname, timeout); -} diff --git a/shared/check_exist.h b/shared/check_exist.h index 6ec5534c..14a8a3f8 100644 --- a/shared/check_exist.h +++ b/shared/check_exist.h @@ -3,23 +3,86 @@ // * GNU General Public License: http://www.gnu.org/licenses/gpl.html * // * Copyright (C) 2008-2011 ZenJu (zhnmju123 AT gmx.de) * // ************************************************************************** -// + #ifndef CHECKEXIST_H_INCLUDED #define CHECKEXIST_H_INCLUDED #include "zstring.h" +#include "boost_thread_wrap.h" //include <boost/thread.hpp> +#include "file_handling.h" + namespace util { +//check for file or folder existence asynchronously +boost::unique_future<bool> somethingExistsAsync(const Zstring& somename); +boost::unique_future<bool> fileExistsAsync(const Zstring& filename); +boost::unique_future<bool> dirExistsAsync(const Zstring& dirname); + +//some syntactic sugar: enum ResultExist { EXISTING_TRUE, EXISTING_FALSE, - EXISTING_TIMEOUT + EXISTING_NOT_READY }; -ResultExist fileExists(const Zstring& filename, size_t timeout); //timeout in ms -ResultExist dirExists( const Zstring& dirname, size_t timeout); //timeout in ms +ResultExist somethingExists(const Zstring& somename, size_t timeout); +ResultExist fileExists(const Zstring& filename, size_t timeout); +ResultExist dirExists(const Zstring& dirname, size_t timeout); + + + + + + + + + + + + +//################## implementation ########################## +template <bool (*fun)(const Zstring&)> +boost::unique_future<bool> objExistsAsync(const Zstring& objname) +{ + //thread safety: make it a pure value type for use in the thread! + const Zstring objnameVal = objname; //atomic ref-count => binary value-type semantics! + boost::packaged_task<bool> pt([=] { return (*fun)(objnameVal); }); + auto fut = pt.get_future(); + boost::thread(std::move(pt)); + return std::move(fut); +} + + +inline +boost::unique_future<bool> somethingExistsAsync(const Zstring& somename) { return objExistsAsync<&zen::somethingExists>(somename); } + +inline +boost::unique_future<bool> fileExistsAsync(const Zstring& filename) { return objExistsAsync<&zen::fileExists>(filename); } + +inline +boost::unique_future<bool> dirExistsAsync(const Zstring& dirname) { return objExistsAsync<&zen::dirExists>(dirname); } + + +template <bool (*fun)(const Zstring&)> inline +ResultExist objExists(const Zstring& objname, size_t timeout) +{ + auto ft = objExistsAsync<fun>(objname); + if (!ft.timed_wait(boost::posix_time::milliseconds(timeout))) + return EXISTING_NOT_READY; + return ft.get() ? EXISTING_TRUE : EXISTING_FALSE; +} + + +inline +ResultExist somethingExists(const Zstring& somename, size_t timeout) { return objExists<&zen::somethingExists>(somename, timeout); } + +inline +ResultExist fileExists(const Zstring& filename, size_t timeout) { return objExists<&zen::fileExists>(filename, timeout); } + +inline +ResultExist dirExists(const Zstring& dirname, size_t timeout) { return objExists<&zen::dirExists>(dirname, timeout); } } #endif // CHECKEXIST_H_INCLUDED diff --git a/shared/com_error.h b/shared/com_error.h index 909e04c1..39f26555 100644 --- a/shared/com_error.h +++ b/shared/com_error.h @@ -3,7 +3,7 @@ // * GNU General Public License: http://www.gnu.org/licenses/gpl.html * // * Copyright (C) 2008-2011 ZenJu (zhnmju123 AT gmx.de) * // ************************************************************************** -// + #ifndef COM_ERROR_HEADER #define COM_ERROR_HEADER diff --git a/shared/com_ptr.h b/shared/com_ptr.h index fa1b3e8f..be1776fd 100644 --- a/shared/com_ptr.h +++ b/shared/com_ptr.h @@ -3,7 +3,7 @@ // * GNU General Public License: http://www.gnu.org/licenses/gpl.html * // * Copyright (C) 2008-2011 ZenJu (zhnmju123 AT gmx.de) * // ************************************************************************** -// + #ifndef SMART_COM_PTR_H #define SMART_COM_PTR_H diff --git a/shared/com_util.h b/shared/com_util.h index 4a8c4f54..b8fc777d 100644 --- a/shared/com_util.h +++ b/shared/com_util.h @@ -3,7 +3,7 @@ // * GNU General Public License: http://www.gnu.org/licenses/gpl.html * // * Copyright (C) 2008-2011 ZenJu (zhnmju123 AT gmx.de) * // ************************************************************************** -// + #ifndef COM_UTILITY_HEADER #define COM_UTILITY_HEADER diff --git a/shared/custom_button.cpp b/shared/custom_button.cpp index 98c0a3cd..0c4c3019 100644 --- a/shared/custom_button.cpp +++ b/shared/custom_button.cpp @@ -3,7 +3,7 @@ // * GNU General Public License: http://www.gnu.org/licenses/gpl.html * // * Copyright (C) 2008-2011 ZenJu (zhnmju123 AT gmx.de) * // ************************************************************************** -// + #include "custom_button.h" #include <wx/dcmemory.h> #include <wx/image.h> diff --git a/shared/custom_button.h b/shared/custom_button.h index 752c763e..8500e59b 100644 --- a/shared/custom_button.h +++ b/shared/custom_button.h @@ -3,7 +3,7 @@ // * GNU General Public License: http://www.gnu.org/licenses/gpl.html * // * Copyright (C) 2008-2011 ZenJu (zhnmju123 AT gmx.de) * // ************************************************************************** -// + #ifndef CUSTOMBUTTON_H_INCLUDED #define CUSTOMBUTTON_H_INCLUDED diff --git a/shared/custom_combo_box.cpp b/shared/custom_combo_box.cpp index f6084fdf..fb16a303 100644 --- a/shared/custom_combo_box.cpp +++ b/shared/custom_combo_box.cpp @@ -3,7 +3,7 @@ // * GNU General Public License: http://www.gnu.org/licenses/gpl.html * // * Copyright (C) 2008-2011 ZenJu (zhnmju123 AT gmx.de) * // ************************************************************************** -// + #include "custom_combo_box.h" diff --git a/shared/custom_combo_box.h b/shared/custom_combo_box.h index 070790a6..3ddd73b0 100644 --- a/shared/custom_combo_box.h +++ b/shared/custom_combo_box.h @@ -3,7 +3,7 @@ // * GNU General Public License: http://www.gnu.org/licenses/gpl.html * // * Copyright (C) 2008-2011 ZenJu (zhnmju123 AT gmx.de) * // ************************************************************************** -// + #ifndef CUSTOMCOMBOBOX_H_INCLUDED #define CUSTOMCOMBOBOX_H_INCLUDED diff --git a/shared/custom_tooltip.cpp b/shared/custom_tooltip.cpp index f19f3822..184c2716 100644 --- a/shared/custom_tooltip.cpp +++ b/shared/custom_tooltip.cpp @@ -3,7 +3,7 @@ // * GNU General Public License: http://www.gnu.org/licenses/gpl.html * // * Copyright (C) 2008-2011 ZenJu (zhnmju123 AT gmx.de) * // ************************************************************************** -// + #include "custom_tooltip.h" #include <wx/stattext.h> #include <wx/sizer.h> diff --git a/shared/custom_tooltip.h b/shared/custom_tooltip.h index c5cb132b..c68856b4 100644 --- a/shared/custom_tooltip.h +++ b/shared/custom_tooltip.h @@ -3,7 +3,7 @@ // * GNU General Public License: http://www.gnu.org/licenses/gpl.html * // * Copyright (C) 2008-2011 ZenJu (zhnmju123 AT gmx.de) * // ************************************************************************** -// + #ifndef CUSTOMTOOLTIP_H_INCLUDED #define CUSTOMTOOLTIP_H_INCLUDED diff --git a/shared/debug_log.h b/shared/debug_log.h index 8e8090f0..561eee9d 100644 --- a/shared/debug_log.h +++ b/shared/debug_log.h @@ -3,7 +3,7 @@ // * GNU General Public License: http://www.gnu.org/licenses/gpl.html * // * Copyright (C) 2008-2011 ZenJu (zhnmju123 AT gmx.de) * // ************************************************************************** -// + #ifndef DEBUG_LOG_HEADER_017324601673246392184621895740256342 #define DEBUG_LOG_HEADER_017324601673246392184621895740256342 diff --git a/shared/debug_new.cpp b/shared/debug_new.cpp index a7324239..23a26a4e 100644 --- a/shared/debug_new.cpp +++ b/shared/debug_new.cpp @@ -3,7 +3,7 @@ // * GNU General Public License: http://www.gnu.org/licenses/gpl.html * // * Copyright (C) 2008-2011 ZenJu (zhnmju123 AT gmx.de) * // ************************************************************************** -// + #include "debug_new.h" #ifdef _MSC_VER diff --git a/shared/debug_new.h b/shared/debug_new.h index afa66a55..b8911b4d 100644 --- a/shared/debug_new.h +++ b/shared/debug_new.h @@ -3,7 +3,7 @@ // * GNU General Public License: http://www.gnu.org/licenses/gpl.html * // * Copyright (C) 2008-2011 ZenJu (zhnmju123 AT gmx.de) * // ************************************************************************** -// + #ifndef DEBUGNEW_H_INCLUDED #define DEBUGNEW_H_INCLUDED diff --git a/shared/dir_name.cpp b/shared/dir_name.cpp index 6566bb3a..6945fb9c 100644 --- a/shared/dir_name.cpp +++ b/shared/dir_name.cpp @@ -3,7 +3,7 @@ // * GNU General Public License: http://www.gnu.org/licenses/gpl.html * // * Copyright (C) 2008-2011 ZenJu (zhnmju123 AT gmx.de) * // ************************************************************************** -// + #include "dir_name.h" #include <wx/dnd.h> #include <wx/window.h> @@ -40,7 +40,8 @@ void setDirectoryNameImpl(const wxString& dirname, wxDirPickerCtrl* dirPicker, w if (dirPicker) { - if (!dirFormatted.empty() && util::dirExists(toZ(dirFormatted), timeout) == util::EXISTING_TRUE) //potentially slow network access: wait 200ms at most + if (!dirFormatted.empty() && + util::dirExists(toZ(dirFormatted), timeout) == util::EXISTING_TRUE) //potentially slow network access: wait 200ms at most dirPicker->SetPath(dirFormatted); } } diff --git a/shared/dir_name.h b/shared/dir_name.h index 4bf07231..6e783d75 100644 --- a/shared/dir_name.h +++ b/shared/dir_name.h @@ -3,7 +3,7 @@ // * GNU General Public License: http://www.gnu.org/licenses/gpl.html * // * Copyright (C) 2008-2011 ZenJu (zhnmju123 AT gmx.de) * // ************************************************************************** -// + #ifndef DRAGANDDROP_H_INCLUDED #define DRAGANDDROP_H_INCLUDED diff --git a/shared/dir_watcher.cpp b/shared/dir_watcher.cpp index 8e0b7f94..9c3a00c7 100644 --- a/shared/dir_watcher.cpp +++ b/shared/dir_watcher.cpp @@ -3,7 +3,7 @@ // * GNU General Public License: http://www.gnu.org/licenses/gpl.html * // * Copyright (C) 2008-2011 ZenJu (zhnmju123 AT gmx.de) * // ************************************************************************** -// + #include "dir_watcher.h" #include "last_error.h" #include "i18n.h" @@ -32,23 +32,22 @@ using namespace zen; #ifdef FFS_WIN namespace { -typedef Zbase<Zchar, StorageDeepCopy> BasicString; //thread safe string class for file names -typedef Zbase<wchar_t, StorageDeepCopy> BasicWString; //thread safe string class for UI texts +typedef Zbase<wchar_t> BasicWString; //thread safe string class for UI texts struct SharedData { boost::mutex lockAccess; - std::set<BasicString> changedFiles; //get rid of duplicate entries (actually occur!) + std::set<Zstring> changedFiles; //get rid of duplicate entries (actually occur!) BasicWString errorMsg; //non-empty if errors occured in thread }; -void addChanges(SharedData& shared, const char* buffer, DWORD bytesWritten, const BasicString& dirname) //throw () +void addChanges(SharedData& shared, const char* buffer, DWORD bytesWritten, const Zstring& dirname) //throw () { boost::lock_guard<boost::mutex> dummy(shared.lockAccess); - std::set<BasicString>& output = shared.changedFiles; + std::set<Zstring>& output = shared.changedFiles; if (bytesWritten == 0) //according to docu this may happen in case of internal buffer overflow: report some "dummy" change output.insert(L"Overflow!"); @@ -59,14 +58,14 @@ void addChanges(SharedData& shared, const char* buffer, DWORD bytesWritten, cons { const FILE_NOTIFY_INFORMATION& notifyInfo = reinterpret_cast<const FILE_NOTIFY_INFORMATION&>(*bufPos); - const BasicString fullname = dirname + BasicString(notifyInfo.FileName, notifyInfo.FileNameLength / sizeof(WCHAR)); + const Zstring fullname = dirname + Zstring(notifyInfo.FileName, notifyInfo.FileNameLength / sizeof(WCHAR)); //skip modifications sent by changed directories: reason for change, child element creation/deletion, will notify separately! bool skip = false; if (notifyInfo.Action == FILE_ACTION_MODIFIED) { //note: this check will not work if top watched directory has been renamed - const DWORD ret = ::GetFileAttributes(applyLongPathPrefix(Zstring(fullname)).c_str()); + const DWORD ret = ::GetFileAttributes(applyLongPathPrefix(fullname).c_str()); bool isDir = ret != INVALID_FILE_ATTRIBUTES && (ret & FILE_ATTRIBUTE_DIRECTORY); //returns true for (dir-)symlinks also skip = isDir; } @@ -90,9 +89,7 @@ void getChanges(SharedData& shared, std::vector<Zstring>& output) //throw FileEr if (!shared.errorMsg.empty()) throw zen::FileError(shared.errorMsg.c_str()); - std::transform(shared.changedFiles.begin(), shared.changedFiles.end(), - std::back_inserter(output), [](const BasicString& str) { return Zstring(str); }); - + output.assign(shared.changedFiles.begin(), shared.changedFiles.end()); shared.changedFiles.clear(); } @@ -107,7 +104,7 @@ void reportError(SharedData& shared, const BasicWString& errorMsg) //throw () class ReadChangesAsync { public: - ReadChangesAsync(const BasicString& directory, //make sure to not leak in thread-unsafe types! + ReadChangesAsync(const Zstring& directory, //make sure to not leak in thread-unsafe types! const std::shared_ptr<SharedData>& shared) : shared_(shared), dirname(directory) @@ -239,7 +236,7 @@ private: //shared between main and worker: std::shared_ptr<SharedData> shared_; //worker thread only: - BasicString dirname; //conceptually thread-only, but technically moved to thread-local storage on instance creation: -> must not use ref-copying! + Zstring dirname; //thread safe! HANDLE hDir; }; @@ -250,7 +247,7 @@ public: HandleVolumeRemoval(HANDLE hDir, boost::thread& worker, const std::shared_ptr<SharedData>& shared, - const BasicString& dirname) : + const Zstring& dirname) : NotifyRequestDeviceRemoval(hDir), //throw FileError worker_(worker), shared_(shared), @@ -283,7 +280,7 @@ private: boost::thread& worker_; std::shared_ptr<SharedData> shared_; - BasicString dirname_; + Zstring dirname_; bool removalRequested; bool operationComplete; }; @@ -304,8 +301,8 @@ DirWatcher::DirWatcher(const Zstring& directory) : //throw FileError { pimpl_->shared = std::make_shared<SharedData>(); - ReadChangesAsync reader(BasicString(directory), pimpl_->shared); //throw FileError - pimpl_->volRemoval.reset(new HandleVolumeRemoval(reader.getDirHandle(), pimpl_->worker, pimpl_->shared, BasicString(directory))); //throw FileError + ReadChangesAsync reader(directory, pimpl_->shared); //throw FileError + pimpl_->volRemoval.reset(new HandleVolumeRemoval(reader.getDirHandle(), pimpl_->worker, pimpl_->shared, directory)); //throw FileError pimpl_->worker = boost::thread(std::move(reader)); } diff --git a/shared/dir_watcher.h b/shared/dir_watcher.h index 572515dc..c2bab1d5 100644 --- a/shared/dir_watcher.h +++ b/shared/dir_watcher.h @@ -3,7 +3,7 @@ // * GNU General Public License: http://www.gnu.org/licenses/gpl.html * // * Copyright (C) 2008-2011 ZenJu (zhnmju123 AT gmx.de) * // ************************************************************************** -// + #ifndef DIR_WATCHER_348577025748023458 #define DIR_WATCHER_348577025748023458 diff --git a/shared/dll_loader.cpp b/shared/dll_loader.cpp index 029cabc5..4e2c0e65 100644 --- a/shared/dll_loader.cpp +++ b/shared/dll_loader.cpp @@ -3,7 +3,7 @@ // * GNU General Public License: http://www.gnu.org/licenses/gpl.html * // * Copyright (C) 2008-2011 ZenJu (zhnmju123 AT gmx.de) * // ************************************************************************** -// + #include "dll_loader.h" #include <map> diff --git a/shared/dll_loader.h b/shared/dll_loader.h index 3efb0d96..252e7598 100644 --- a/shared/dll_loader.h +++ b/shared/dll_loader.h @@ -3,7 +3,7 @@ // * GNU General Public License: http://www.gnu.org/licenses/gpl.html * // * Copyright (C) 2008-2011 ZenJu (zhnmju123 AT gmx.de) * // ************************************************************************** -// + #ifndef DLLLOADER_H_INCLUDED #define DLLLOADER_H_INCLUDED @@ -23,7 +23,7 @@ namespace util /* load function from a DLL library, e.g. from kernel32.dll -NOTE: you're allowed to take a static reference to the return value to optimize performance! :) +NOTE: you're allowed to take a static reference to the return value! :) */ template <typename FunctionType> FunctionType getDllFun(const std::wstring& libraryName, const std::string& functionName); diff --git a/shared/dst_hack.cpp b/shared/dst_hack.cpp index a64df448..d52a335f 100644 --- a/shared/dst_hack.cpp +++ b/shared/dst_hack.cpp @@ -28,8 +28,8 @@ Zstring getVolumeName(const Zstring& filename) // volumePath += FILE_NAME_SEPARATOR; Zstring nameFmt = removeLongPathPrefix(filename); //throw() - if (!nameFmt.EndsWith(Zstr("\\"))) - nameFmt += Zstr("\\"); //GetVolumeInformation expects trailing backslash + if (!endsWith(nameFmt, FILE_NAME_SEPARATOR)) + nameFmt += FILE_NAME_SEPARATOR; //GetVolumeInformation expects trailing backslash if (nameFmt.StartsWith(Zstr("\\\\"))) //UNC path: "\\ComputerName\SharedFolder\" { @@ -58,8 +58,6 @@ Zstring getVolumeName(const Zstring& filename) bool dst::isFatDrive(const Zstring& fileName) //throw() { - using namespace zen; - const size_t BUFFER_SIZE = MAX_PATH + 1; wchar_t fsName[BUFFER_SIZE]; diff --git a/shared/file_drop.h b/shared/file_drop.h index c85d4cbb..8b11ccfb 100644 --- a/shared/file_drop.h +++ b/shared/file_drop.h @@ -3,7 +3,7 @@ // * GNU General Public License: http://www.gnu.org/licenses/gpl.html * // * Copyright (C) 2008-2011 ZenJu (zhnmju123 AT gmx.de) * // ************************************************************************** -// + #ifndef FILE_DROP_H_INCLUDED #define FILE_DROP_H_INCLUDED diff --git a/shared/file_error.h b/shared/file_error.h index ae9cc83e..d814e05d 100644 --- a/shared/file_error.h +++ b/shared/file_error.h @@ -3,7 +3,7 @@ // * GNU General Public License: http://www.gnu.org/licenses/gpl.html * // * Copyright (C) 2008-2011 ZenJu (zhnmju123 AT gmx.de) * // ************************************************************************** -// + #ifndef FILEERROR_H_INCLUDED #define FILEERROR_H_INCLUDED @@ -35,7 +35,7 @@ DEFINE_NEW_FILE_ERROR(ErrorFileLocked); -//facilitate usage of std::wstring for error messages: +//----------- facilitate usage of std::wstring for error messages -------------------- //allow implicit UTF8 conversion: since std::wstring models a GUI string, convenience is more important than performance inline std::wstring operator+(const std::wstring& lhs, const Zstring& rhs) { return std::wstring(lhs) += zen::utf8CvrtTo<std::wstring>(rhs); } diff --git a/shared/file_handling.cpp b/shared/file_handling.cpp index a5e7fa9f..6b41f4f5 100644 --- a/shared/file_handling.cpp +++ b/shared/file_handling.cpp @@ -3,11 +3,10 @@ // * GNU General Public License: http://www.gnu.org/licenses/gpl.html * // * Copyright (C) 2008-2011 ZenJu (zhnmju123 AT gmx.de) * // ************************************************************************** -// + #include "file_handling.h" #include <map> #include <algorithm> -#include <boost/bind.hpp> #include <stdexcept> #include "last_error.h" #include "file_traverser.h" @@ -16,6 +15,8 @@ #include "file_io.h" #include "i18n.h" #include "assert_static.h" +#include <boost/thread/tss.hpp> +#include <boost/thread/once.hpp> #ifdef FFS_WIN #include "privilege.h" @@ -24,6 +25,7 @@ #include "long_path_prefix.h" #include <Aclapi.h> #include "dst_hack.h" +#include "file_update_handle.h" #elif defined FFS_LINUX #include <sys/stat.h> @@ -99,68 +101,10 @@ bool zen::somethingExists(const Zstring& objname) //throw() check whether #ifdef FFS_WIN namespace { -//manage file handle to update existing files (temporarily resetting read-only if necessary) -//CreateFileCmd: lambda directly returning non-owned file handle from ::CreateFile() -class FileUpdateHandle -{ -public: - template <class CreateFileCmd> - FileUpdateHandle(const Zstring& filename, CreateFileCmd cmd) : - filenameFmt(applyLongPathPrefix(filename)), - hFile(INVALID_HANDLE_VALUE), - attr(INVALID_FILE_ATTRIBUTES) - { - hFile = cmd(); - if (hFile != INVALID_HANDLE_VALUE) - return; - - const DWORD lastError = ::GetLastError(); - if (lastError == ERROR_ACCESS_DENIED) //function fails if file is read-only - { - Loki::ScopeGuard guardErrorCode = Loki::MakeGuard(::SetLastError, lastError); //transactional behavior: ensure cleanup (e.g. network drop) -> cref [!] - - //read-only file attribute may cause trouble: temporarily reset it - const DWORD tmpAttr = ::GetFileAttributes(filenameFmt.c_str()); - if (tmpAttr != INVALID_FILE_ATTRIBUTES && (tmpAttr & FILE_ATTRIBUTE_READONLY)) - { - if (::SetFileAttributes(filenameFmt.c_str(), FILE_ATTRIBUTE_NORMAL)) - { - guardErrorCode.Dismiss(); - attr = tmpAttr; //"create" guard on read-only attribute - - //now try again - hFile = cmd(); - } - } - } - } - - ~FileUpdateHandle() - { - if (hFile != INVALID_HANDLE_VALUE) - ::CloseHandle(hFile); - - if (attr != INVALID_FILE_ATTRIBUTES) - ::SetFileAttributes(filenameFmt.c_str(), attr); - } - - //may return INVALID_FILE_ATTRIBUTES, in which case ::GetLastError() may be called directly after FileUpdateHandle() - HANDLE get() const { return hFile; } - -private: - FileUpdateHandle(const FileUpdateHandle&); - FileUpdateHandle& operator=(const FileUpdateHandle&); - - Zstring filenameFmt; - HANDLE hFile; - DWORD attr; -}; - - zen::UInt64 getFileSizeSymlink(const Zstring& linkName) //throw (FileError) { //open handle to target of symbolic link - const HANDLE hFile = ::CreateFile(zen::applyLongPathPrefix(linkName).c_str(), + const HANDLE hFile = ::CreateFile(applyLongPathPrefix(linkName).c_str(), 0, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, NULL, @@ -168,28 +112,28 @@ zen::UInt64 getFileSizeSymlink(const Zstring& linkName) //throw (FileError) FILE_FLAG_BACKUP_SEMANTICS, NULL); if (hFile == INVALID_HANDLE_VALUE) - throw FileError(_("Error reading file attributes:") + "\n\"" + linkName + "\"" + "\n\n" + zen::getLastErrorFormatted()); + throw FileError(_("Error reading file attributes:") + "\n\"" + linkName + "\"" + "\n\n" + getLastErrorFormatted()); Loki::ScopeGuard dummy = Loki::MakeGuard(::CloseHandle, hFile); (void)dummy; //silence warning "unused variable" BY_HANDLE_FILE_INFORMATION fileInfo = {}; if (!::GetFileInformationByHandle(hFile, &fileInfo)) - throw FileError(_("Error reading file attributes:") + "\n\"" + linkName + "\"" + "\n\n" + zen::getLastErrorFormatted()); + throw FileError(_("Error reading file attributes:") + "\n\"" + linkName + "\"" + "\n\n" + getLastErrorFormatted()); - return zen::UInt64(fileInfo.nFileSizeLow, fileInfo.nFileSizeHigh); + return UInt64(fileInfo.nFileSizeLow, fileInfo.nFileSizeHigh); } } #endif -zen::UInt64 zen::getFilesize(const Zstring& filename) //throw (FileError) +UInt64 zen::getFilesize(const Zstring& filename) //throw (FileError) { #ifdef FFS_WIN WIN32_FIND_DATA fileInfo = {}; const HANDLE searchHandle = ::FindFirstFile(applyLongPathPrefix(filename).c_str(), &fileInfo); if (searchHandle == INVALID_HANDLE_VALUE) - throw FileError(_("Error reading file attributes:") + "\n\"" + filename + "\"" + "\n\n" + zen::getLastErrorFormatted()); + throw FileError(_("Error reading file attributes:") + "\n\"" + filename + "\"" + "\n\n" + getLastErrorFormatted()); ::FindClose(searchHandle); @@ -197,14 +141,14 @@ zen::UInt64 zen::getFilesize(const Zstring& filename) //throw (FileError) if (isSymbolicLink) return getFileSizeSymlink(filename); //throw (FileError) - return zen::UInt64(fileInfo.nFileSizeLow, fileInfo.nFileSizeHigh); + return UInt64(fileInfo.nFileSizeLow, fileInfo.nFileSizeHigh); #elif defined FFS_LINUX struct stat fileInfo = {}; if (::stat(filename.c_str(), &fileInfo) != 0) //follow symbolic links - throw FileError(_("Error reading file attributes:") + "\n\"" + filename + "\"" + "\n\n" + zen::getLastErrorFormatted()); + throw FileError(_("Error reading file attributes:") + "\n\"" + filename + "\"" + "\n\n" + getLastErrorFormatted()); - return zen::UInt64(fileInfo.st_size); + return UInt64(fileInfo.st_size); #endif } @@ -214,7 +158,7 @@ namespace #ifdef FFS_WIN DWORD retrieveVolumeSerial(const Zstring& pathName) //return 0 on error! { - std::vector<wchar_t> buffer(std::max(pathName.size(), static_cast<size_t>(10000))); + std::vector<wchar_t> buffer(10000); //full pathName need not yet exist! if (!::GetVolumePathName(pathName.c_str(), //__in LPCTSTR lpszFileName, @@ -263,14 +207,14 @@ dev_t retrieveVolumeSerial(const Zstring& pathName) //return 0 on error! } -zen::ResponseSameVol zen::onSameVolume(const Zstring& folderLeft, const Zstring& folderRight) //throw() +zen::ResponseSame zen::onSameVolume(const Zstring& folderLeft, const Zstring& folderRight) //throw() { const auto serialLeft = retrieveVolumeSerial(folderLeft); //returns 0 on error! const auto serialRight = retrieveVolumeSerial(folderRight); //returns 0 on error! if (serialLeft == 0 || serialRight == 0) - return VOLUME_CANT_SAY; + return IS_SAME_CANT_SAY; - return serialLeft == serialRight ? VOLUME_SAME : VOLUME_DIFFERENT; + return serialLeft == serialRight ? IS_SAME_YES : IS_SAME_NO; } @@ -302,12 +246,12 @@ bool zen::removeFile(const Zstring& filename) //throw (FileError); #endif //no error situation if file is not existing! manual deletion relies on it! - //perf: place check in error handling block + //perf: check is placed in error handling block //warning: this call changes error code!! if (!somethingExists(filename)) return false; //neither file nor any other object (e.g. broken symlink) with that name existing - throw FileError(_("Error deleting file:") + "\n\"" + filename + "\"" + "\n\n" + zen::getLastErrorFormatted(lastError)); + throw FileError(_("Error deleting file:") + "\n\"" + filename + "\"" + "\n\n" + getLastErrorFormatted(lastError)); } return true; } @@ -364,7 +308,7 @@ void renameFileInternal(const Zstring& oldName, const Zstring& newName) //throw } } - std::wstring errorMessage = _("Error moving file:") + "\n\"" + oldName + "\" ->\n\"" + newName + "\"" + "\n\n" + zen::getLastErrorFormatted(lastError); + std::wstring errorMessage = _("Error moving file:") + "\n\"" + oldName + "\" ->\n\"" + newName + "\"" + "\n\n" + getLastErrorFormatted(lastError); if (lastError == ERROR_NOT_SAME_DEVICE) throw ErrorDifferentVolume(errorMessage); @@ -379,7 +323,7 @@ void renameFileInternal(const Zstring& oldName, const Zstring& newName) //throw { const int lastError = errno; - std::wstring errorMessage = _("Error moving file:") + "\n\"" + oldName + "\" ->\n\"" + newName + "\"" + "\n\n" + zen::getLastErrorFormatted(lastError); + std::wstring errorMessage = _("Error moving file:") + "\n\"" + oldName + "\" ->\n\"" + newName + "\"" + "\n\n" + getLastErrorFormatted(lastError); if (lastError == EXDEV) throw ErrorDifferentVolume(errorMessage); @@ -399,7 +343,7 @@ void renameFileInternal(const Zstring& oldName, const Zstring& newName) //throw template <typename Function> Zstring getFilenameFmt(const Zstring& filename, Function fun) //throw(); returns empty string on error { - const Zstring filenameFmt = zen::applyLongPathPrefix(filename); + const Zstring filenameFmt = applyLongPathPrefix(filename); const DWORD bufferSize = fun(filenameFmt.c_str(), NULL, 0); if (bufferSize == 0) @@ -430,11 +374,11 @@ Zstring createTemp8Dot3Name(const Zstring& fileName) //find a unique 8.3 short n for (int index = 0; index < 100000000; ++index) //filename must be representable by <= 8 characters { const Zstring output = pathPrefix + Zstring::fromNumber(index) + Zchar('.') + extension; - if (!zen::somethingExists(output)) //ensure uniqueness + if (!somethingExists(output)) //ensure uniqueness return output; } - throw std::runtime_error(std::string("100000000 files, one for each number, exist in this directory? You're kidding...\n") + zen::utf8CvrtTo<std::string>(pathPrefix)); + throw std::runtime_error(std::string("100000000 files, one for each number, exist in this directory? You're kidding...\n") + utf8CvrtTo<std::string>(pathPrefix)); } @@ -446,7 +390,7 @@ bool fix8Dot3NameClash(const Zstring& oldName, const Zstring& newName) //throw if (newName.find(FILE_NAME_SEPARATOR) == Zstring::npos) return false; - if (zen::somethingExists(newName)) //name OR directory! + if (somethingExists(newName)) //name OR directory! { const Zstring fileNameOrig = newName.AfterLast(FILE_NAME_SEPARATOR); //returns the whole string if ch not found const Zstring fileNameShort = getFilenameFmt(newName, ::GetShortPathName).AfterLast(FILE_NAME_SEPARATOR); //throw() returns empty string on error @@ -467,7 +411,7 @@ bool fix8Dot3NameClash(const Zstring& oldName, const Zstring& newName) //throw //move already existing short name out of the way for now renameFileInternal(unrelatedPathLong, parkedTarget); //throw (FileError: ErrorDifferentVolume); - //DON'T call zen::renameFile() to avoid reentrance! + //DON'T call renameFile() to avoid reentrance! //schedule cleanup; the file system should assign this unrelated file a new (unique) short name Loki::ScopeGuard guard = Loki::MakeGuard(renameFileInternal, parkedTarget, unrelatedPathLong);//equivalent to Boost.ScopeExit in this case @@ -508,7 +452,7 @@ public: virtual void deleteTargetFile(const Zstring& targetFile) { assert(!fileExists(targetFile)); } - virtual void updateCopyStatus(zen::UInt64 totalBytesTransferred) + virtual void updateCopyStatus(UInt64 totalBytesTransferred) { moveCallback.requestUiRefresh(sourceFile_); } @@ -665,7 +609,7 @@ void moveDirectoryImpl(const Zstring& sourceDir, const Zstring& targetDir, bool //move files for (TraverseOneLevel::NameList::const_iterator i = fileList.begin(); i != fileList.end(); ++i) - zen::moveFile(i->second, targetDirFormatted + i->first, ignoreExisting, callback); //throw (FileError: ErrorTargetExisting); + moveFile(i->second, targetDirFormatted + i->first, ignoreExisting, callback); //throw (FileError: ErrorTargetExisting); //move directories for (TraverseOneLevel::NameList::const_iterator i = dirList.begin(); i != dirList.end(); ++i) @@ -753,7 +697,7 @@ void zen::removeDirectory(const Zstring& directory, CallbackRemoveDir* callback) #elif defined FFS_LINUX if (::unlink(directory.c_str()) != 0) #endif - throw FileError(_("Error deleting directory:") + "\n\"" + directory + "\"" + "\n\n" + zen::getLastErrorFormatted()); + throw FileError(_("Error deleting directory:") + "\n\"" + directory + "\"" + "\n\n" + getLastErrorFormatted()); if (callback) callback->notifyDeletion(directory); //once per symlink return; @@ -764,7 +708,7 @@ void zen::removeDirectory(const Zstring& directory, CallbackRemoveDir* callback) //get all files and directories from current directory (WITHOUT subdirectories!) FilesDirsOnlyTraverser traverser(fileList, dirList); - zen::traverseFolder(directory, false, traverser); //don't follow symlinks + traverseFolder(directory, false, traverser); //don't follow symlinks //delete files for (std::vector<Zstring>::const_iterator i = fileList.begin(); i != fileList.end(); ++i) @@ -784,7 +728,7 @@ void zen::removeDirectory(const Zstring& directory, CallbackRemoveDir* callback) if (::rmdir(directory.c_str()) != 0) #endif { - throw FileError(_("Error deleting directory:") + "\n\"" + directory + "\"" + "\n\n" + zen::getLastErrorFormatted()); + throw FileError(_("Error deleting directory:") + "\n\"" + directory + "\"" + "\n\n" + getLastErrorFormatted()); } if (callback) callback->notifyDeletion(directory); //and once per folder } @@ -801,7 +745,7 @@ void zen::copyFileTimes(const Zstring& sourceObj, const Zstring& targetObj, bool if (!::GetFileAttributesEx(applyLongPathPrefix(sourceObj).c_str(), //__in LPCTSTR lpFileName, GetFileExInfoStandard, //__in GET_FILEEX_INFO_LEVELS fInfoLevelId, &sourceAttr)) //__out LPVOID lpFileInformation - throw FileError(_("Error reading file attributes:") + "\n\"" + sourceObj + "\"" + "\n\n" + zen::getLastErrorFormatted()); + throw FileError(_("Error reading file attributes:") + "\n\"" + sourceObj + "\"" + "\n\n" + getLastErrorFormatted()); const bool isReparsePoint = (sourceAttr.dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT) != 0; const bool isDirectory = (sourceAttr.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) != 0; @@ -816,7 +760,7 @@ void zen::copyFileTimes(const Zstring& sourceObj, const Zstring& targetObj, bool FILE_FLAG_BACKUP_SEMANTICS, //needed to open a directory; no FILE_FLAG_OPEN_REPARSE_POINT => deref symlinks NULL); if (hSource == INVALID_HANDLE_VALUE) - throw FileError(_("Error reading file attributes:") + "\n\"" + sourceObj + "\"" + "\n\n" + zen::getLastErrorFormatted()); + throw FileError(_("Error reading file attributes:") + "\n\"" + sourceObj + "\"" + "\n\n" + getLastErrorFormatted()); Loki::ScopeGuard dummy = Loki::MakeGuard(::CloseHandle, hSource); (void)dummy; //silence warning "unused variable" @@ -825,7 +769,7 @@ void zen::copyFileTimes(const Zstring& sourceObj, const Zstring& targetObj, bool &creationTime, //__out_opt LPFILETIME lpCreationTime, NULL, //__out_opt LPFILETIME lpLastAccessTime, &lastWriteTime)) //__out_opt LPFILETIME lpLastWriteTime - throw FileError(_("Error reading file attributes:") + "\n\"" + sourceObj + "\"" + "\n\n" + zen::getLastErrorFormatted()); + throw FileError(_("Error reading file attributes:") + "\n\"" + sourceObj + "\"" + "\n\n" + getLastErrorFormatted()); } else { @@ -884,7 +828,7 @@ void zen::copyFileTimes(const Zstring& sourceObj, const Zstring& targetObj, bool }); if (targetHandle.get() == INVALID_HANDLE_VALUE) - throw FileError(_("Error changing modification time:") + "\n\"" + targetObj + "\"" + "\n\n" + zen::getLastErrorFormatted()); + throw FileError(_("Error changing modification time:") + "\n\"" + targetObj + "\"" + "\n\n" + getLastErrorFormatted()); /* if (hTarget == INVALID_HANDLE_VALUE && ::GetLastError() == ERROR_SHARING_VIOLATION) @@ -898,10 +842,10 @@ void zen::copyFileTimes(const Zstring& sourceObj, const Zstring& targetObj, bool &creationTime, NULL, &lastWriteTime)) - throw FileError(_("Error changing modification time:") + "\n\"" + targetObj + "\"" + "\n\n" + zen::getLastErrorFormatted()); + throw FileError(_("Error changing modification time:") + "\n\"" + targetObj + "\"" + "\n\n" + getLastErrorFormatted()); #ifndef NDEBUG //dst hack: verify data written - if (dst::isFatDrive(targetObj) && !zen::dirExists(targetObj)) //throw() + if (dst::isFatDrive(targetObj) && !dirExists(targetObj)) //throw() { WIN32_FILE_ATTRIBUTE_DATA debugeAttr = {}; assert(::GetFileAttributesEx(applyLongPathPrefix(targetObj).c_str(), //__in LPCTSTR lpFileName, @@ -918,7 +862,7 @@ void zen::copyFileTimes(const Zstring& sourceObj, const Zstring& targetObj, bool { struct stat objInfo = {}; if (::stat(sourceObj.c_str(), &objInfo) != 0) //read file attributes from source directory - throw FileError(_("Error reading file attributes:") + "\n\"" + sourceObj + "\"" + "\n\n" + zen::getLastErrorFormatted()); + throw FileError(_("Error reading file attributes:") + "\n\"" + sourceObj + "\"" + "\n\n" + getLastErrorFormatted()); struct utimbuf newTimes = {}; newTimes.actime = objInfo.st_atime; @@ -926,13 +870,13 @@ void zen::copyFileTimes(const Zstring& sourceObj, const Zstring& targetObj, bool //(try to) set new "last write time" if (::utime(targetObj.c_str(), &newTimes) != 0) //return value not evaluated! - throw FileError(_("Error changing modification time:") + "\n\"" + targetObj + "\"" + "\n\n" + zen::getLastErrorFormatted()); + throw FileError(_("Error changing modification time:") + "\n\"" + targetObj + "\"" + "\n\n" + getLastErrorFormatted()); } else { struct stat objInfo = {}; if (::lstat(sourceObj.c_str(), &objInfo) != 0) //read file attributes from source directory - throw FileError(_("Error reading file attributes:") + "\n\"" + sourceObj + "\"" + "\n\n" + zen::getLastErrorFormatted()); + throw FileError(_("Error reading file attributes:") + "\n\"" + sourceObj + "\"" + "\n\n" + getLastErrorFormatted()); struct timeval newTimes[2] = {}; newTimes[0].tv_sec = objInfo.st_atime; /* seconds */ @@ -942,7 +886,7 @@ void zen::copyFileTimes(const Zstring& sourceObj, const Zstring& targetObj, bool newTimes[1].tv_usec = 0; /* microseconds */ if (::lutimes(targetObj.c_str(), newTimes) != 0) //return value not evaluated! - throw FileError(_("Error changing modification time:") + "\n\"" + targetObj + "\"" + "\n\n" + zen::getLastErrorFormatted()); + throw FileError(_("Error changing modification time:") + "\n\"" + targetObj + "\"" + "\n\n" + getLastErrorFormatted()); } #endif } @@ -954,7 +898,7 @@ namespace Zstring resolveDirectorySymlink(const Zstring& dirLinkName) //get full target path of symbolic link to a directory; throw (FileError) { //open handle to target of symbolic link - const HANDLE hDir = ::CreateFile(zen::applyLongPathPrefix(dirLinkName).c_str(), + const HANDLE hDir = ::CreateFile(applyLongPathPrefix(dirLinkName).c_str(), 0, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, NULL, @@ -962,7 +906,7 @@ Zstring resolveDirectorySymlink(const Zstring& dirLinkName) //get full target pa FILE_FLAG_BACKUP_SEMANTICS, //needed to open a directory NULL); if (hDir == INVALID_HANDLE_VALUE) - throw FileError(_("Error resolving symbolic link:") + "\n\"" + dirLinkName + "\"" + "\n\n" + zen::getLastErrorFormatted()); + throw FileError(_("Error resolving symbolic link:") + "\n\"" + dirLinkName + "\"" + "\n\n" + getLastErrorFormatted()); Loki::ScopeGuard dummy = Loki::MakeGuard(::CloseHandle, hDir); (void)dummy; //silence warning "unused variable" @@ -976,7 +920,7 @@ Zstring resolveDirectorySymlink(const Zstring& dirLinkName) //get full target pa LPTSTR lpszFilePath, DWORD cchFilePath, DWORD dwFlags); - static const GetFinalPathNameByHandleWFunc getFinalPathNameByHandle = + const GetFinalPathNameByHandleWFunc getFinalPathNameByHandle = util::getDllFun<GetFinalPathNameByHandleWFunc>(L"kernel32.dll", "GetFinalPathNameByHandleW"); if (getFinalPathNameByHandle == NULL) @@ -991,7 +935,7 @@ Zstring resolveDirectorySymlink(const Zstring& dirLinkName) //get full target pa { std::wstring errorMessage = _("Error resolving symbolic link:") + "\n\"" + dirLinkName + "\""; if (rv == 0) - errorMessage += L"\n\n" + zen::getLastErrorFormatted(); + errorMessage += L"\n\n" + getLastErrorFormatted(); throw FileError(errorMessage); } @@ -1014,7 +958,7 @@ void copySecurityContext(const Zstring& source, const Zstring& target, bool dere errno == EOPNOTSUPP) //extended attributes are not supported by the filesystem return; - throw FileError(_("Error reading security context:") + "\n\"" + source + "\"" + "\n\n" + zen::getLastErrorFormatted()); + throw FileError(_("Error reading security context:") + "\n\"" + source + "\"" + "\n\n" + getLastErrorFormatted()); } Loki::ScopeGuard dummy1 = Loki::MakeGuard(::freecon, contextSource); (void)dummy1; //silence warning "unused variable" @@ -1044,7 +988,7 @@ void copySecurityContext(const Zstring& source, const Zstring& target, bool dere ::setfilecon (target.c_str(), contextSource) : ::lsetfilecon(target.c_str(), contextSource); if (rv3 < 0) - throw FileError(_("Error writing security context:") + "\n\"" + target + "\"" + "\n\n" + zen::getLastErrorFormatted()); + throw FileError(_("Error writing security context:") + "\n\"" + target + "\"" + "\n\n" + getLastErrorFormatted()); } #endif //HAVE_SELINUX @@ -1077,7 +1021,7 @@ void copyObjectPermissions(const Zstring& source, const Zstring& target, bool de PACL sacl = NULL; //http://msdn.microsoft.com/en-us/library/aa364399(v=VS.85).aspx - const HANDLE hSource = ::CreateFile(zen::applyLongPathPrefix(source).c_str(), + const HANDLE hSource = ::CreateFile(applyLongPathPrefix(source).c_str(), READ_CONTROL | ACCESS_SYSTEM_SECURITY, //ACCESS_SYSTEM_SECURITY required for SACL access FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, NULL, @@ -1085,7 +1029,7 @@ void copyObjectPermissions(const Zstring& source, const Zstring& target, bool de FILE_FLAG_BACKUP_SEMANTICS | (derefSymlinks ? 0 : FILE_FLAG_OPEN_REPARSE_POINT), //FILE_FLAG_BACKUP_SEMANTICS needed to open a directory NULL); if (hSource == INVALID_HANDLE_VALUE) - throw FileError(_("Error copying file permissions:") + "\n\"" + source + "\" ->\n\"" + target + "\"" + "\n\n" + zen::getLastErrorFormatted() + " (OR)"); + throw FileError(_("Error copying file permissions:") + "\n\"" + source + "\" ->\n\"" + target + "\"" + "\n\n" + getLastErrorFormatted() + " (OR)"); Loki::ScopeGuard dummy = Loki::MakeGuard(::CloseHandle, hSource); (void)dummy; //silence warning "unused variable" @@ -1100,7 +1044,7 @@ void copyObjectPermissions(const Zstring& source, const Zstring& target, bool de &sacl, //__out_opt PACL *ppSacl, &buffer); //__out_opt PSECURITY_DESCRIPTOR *ppSecurityDescriptor if (rc != ERROR_SUCCESS) - throw FileError(_("Error copying file permissions:") + "\n\"" + source + "\" ->\n\"" + target + "\"" + "\n\n" + zen::getLastErrorFormatted(rc) + " (R)"); + throw FileError(_("Error copying file permissions:") + "\n\"" + source + "\" ->\n\"" + target + "\"" + "\n\n" + getLastErrorFormatted(rc) + " (R)"); Loki::ScopeGuard dummy4 = Loki::MakeGuard(::LocalFree, buffer); (void)dummy4; //silence warning "unused variable" @@ -1119,7 +1063,7 @@ void copyObjectPermissions(const Zstring& source, const Zstring& target, bool de }); if (targetHandle.get() == INVALID_HANDLE_VALUE) - throw FileError(_("Error copying file permissions:") + "\n\"" + source + "\" ->\n\"" + target + "\"" + "\n\n" + zen::getLastErrorFormatted() + " (OW)"); + throw FileError(_("Error copying file permissions:") + "\n\"" + source + "\" ->\n\"" + target + "\"" + "\n\n" + getLastErrorFormatted() + " (OW)"); // rc = ::SetNamedSecurityInfo(const_cast<WCHAR*>(applyLongPathPrefix(target).c_str()), //__in LPTSTR pObjectName, -> does NOT dereference symlinks! rc = ::SetSecurityInfo( @@ -1132,7 +1076,7 @@ void copyObjectPermissions(const Zstring& source, const Zstring& target, bool de sacl); //__in_opt PACL pSacl if (rc != ERROR_SUCCESS) - throw FileError(_("Error copying file permissions:") + "\n\"" + source + "\" ->\n\"" + target + "\"" + "\n\n" + zen::getLastErrorFormatted(rc) + " (W)"); + throw FileError(_("Error copying file permissions:") + "\n\"" + source + "\" ->\n\"" + target + "\"" + "\n\n" + getLastErrorFormatted(rc) + " (W)"); #elif defined FFS_LINUX @@ -1146,7 +1090,7 @@ void copyObjectPermissions(const Zstring& source, const Zstring& target, bool de if (::stat (source.c_str(), &fileInfo) != 0 || ::chown(target.c_str(), fileInfo.st_uid, fileInfo.st_gid) != 0 || // may require admin rights! ::chmod(target.c_str(), fileInfo.st_mode) != 0) - throw FileError(_("Error copying file permissions:") + "\n\"" + source + "\" ->\n\"" + target + "\"" + "\n\n" + zen::getLastErrorFormatted() + " (R)"); + throw FileError(_("Error copying file permissions:") + "\n\"" + source + "\" ->\n\"" + target + "\"" + "\n\n" + getLastErrorFormatted() + " (R)"); } else { @@ -1154,7 +1098,7 @@ void copyObjectPermissions(const Zstring& source, const Zstring& target, bool de if (::lstat (source.c_str(), &fileInfo) != 0 || ::lchown(target.c_str(), fileInfo.st_uid, fileInfo.st_gid) != 0 || // may require admin rights! (!symlinkExists(target) && ::chmod(target.c_str(), fileInfo.st_mode) != 0)) //setting access permissions doesn't make sense for symlinks on Linux: there is no lchmod() - throw FileError(_("Error copying file permissions:") + "\n\"" + source + "\" ->\n\"" + target + "\"" + "\n\n" + zen::getLastErrorFormatted() + " (W)"); + throw FileError(_("Error copying file permissions:") + "\n\"" + source + "\" ->\n\"" + target + "\"" + "\n\n" + getLastErrorFormatted() + " (W)"); } #endif } @@ -1163,8 +1107,8 @@ void copyObjectPermissions(const Zstring& source, const Zstring& target, bool de namespace { //provide uniform binary interface: -void removeDirSimple(const Zstring& directory) { zen::removeDirectory(directory); } //throw (FileError) -void removeFileSimple(const Zstring& filename) { zen::removeFile(filename); } //throw (FileError) +void removeDirSimple(const Zstring& directory) { removeDirectory(directory); } //throw (FileError) +void removeFileSimple(const Zstring& filename) { removeFile(filename); } //throw (FileError) } @@ -1172,7 +1116,7 @@ void createDirectoryRecursively(const Zstring& directory, const Zstring& templat { using namespace zen; - if (zen::dirExists(directory)) + if (dirExists(directory)) return; if (level == 100) //catch endless recursion @@ -1180,7 +1124,7 @@ void createDirectoryRecursively(const Zstring& directory, const Zstring& templat //try to create parent folders first const Zstring dirParent = directory.BeforeLast(FILE_NAME_SEPARATOR); - if (!dirParent.empty() && !zen::dirExists(dirParent)) + if (!dirParent.empty() && !dirExists(dirParent)) { //call function recursively const Zstring templateParent = templateDir.BeforeLast(FILE_NAME_SEPARATOR); @@ -1201,7 +1145,7 @@ void createDirectoryRecursively(const Zstring& directory, const Zstring& templat #endif { if (level != 0) return; - throw FileError(_("Error creating directory:") + "\n\"" + directory + "\"" + "\n\n" + zen::getLastErrorFormatted()); + throw FileError(_("Error creating directory:") + "\n\"" + directory + "\"" + "\n\n" + getLastErrorFormatted()); } if (!templateDir.empty()) @@ -1314,7 +1258,7 @@ void zen::copySymlink(const Zstring& sourceLink, const Zstring& targetLink, zen: #ifdef FFS_WIN //dynamically load windows API function typedef BOOLEAN (WINAPI *CreateSymbolicLinkFunc)(LPCTSTR lpSymlinkFileName, LPCTSTR lpTargetFileName, DWORD dwFlags); - static const CreateSymbolicLinkFunc createSymbolicLink = util::getDllFun<CreateSymbolicLinkFunc>(L"kernel32.dll", "CreateSymbolicLinkW"); + const CreateSymbolicLinkFunc createSymbolicLink = util::getDllFun<CreateSymbolicLinkFunc>(L"kernel32.dll", "CreateSymbolicLinkW"); if (createSymbolicLink == NULL) throw FileError(_("Error loading library function:") + "\n\"" + "CreateSymbolicLinkW" + "\""); @@ -1322,11 +1266,11 @@ void zen::copySymlink(const Zstring& sourceLink, const Zstring& targetLink, zen: targetLink.c_str(), //__in LPTSTR lpSymlinkFileName, linkPath.c_str(), //__in LPTSTR lpTargetFileName, (type == SYMLINK_TYPE_DIR ? SYMBOLIC_LINK_FLAG_DIRECTORY : 0))) //__in DWORD dwFlags - throw FileError(_("Error copying symbolic link:") + "\n\"" + sourceLink + "\" ->\n\"" + targetLink + "\"" + "\n\n" + zen::getLastErrorFormatted()); + throw FileError(_("Error copying symbolic link:") + "\n\"" + sourceLink + "\" ->\n\"" + targetLink + "\"" + "\n\n" + getLastErrorFormatted()); #elif defined FFS_LINUX if (::symlink(linkPath.c_str(), targetLink.c_str()) != 0) - throw FileError(_("Error copying symbolic link:") + "\n\"" + sourceLink + "\" ->\n\"" + targetLink + "\"" + "\n\n" + zen::getLastErrorFormatted()); + throw FileError(_("Error copying symbolic link:") + "\n\"" + sourceLink + "\" ->\n\"" + targetLink + "\"" + "\n\n" + getLastErrorFormatted()); #endif //allow only consistent objects to be created -> don't place before ::symlink, targetLink may already exist @@ -1351,7 +1295,7 @@ Zstring createTempName(const Zstring& filename) Zstring output = filename + zen::TEMP_FILE_ENDING; //ensure uniqueness - for (int i = 1; zen::somethingExists(output); ++i) + for (int i = 1; somethingExists(output); ++i) output = filename + Zchar('_') + Zstring::fromNumber(i) + zen::TEMP_FILE_ENDING; return output; @@ -1362,11 +1306,13 @@ struct CallbackData { CallbackData(CallbackCopyFile& cb) : callback(cb), + callNr(0), exceptionCaught(false) {} CallbackCopyFile& callback; + size_t callNr; bool exceptionCaught; - zen::UInt64 bytesTransferredOnException; + UInt64 bytesTransferredOnException; }; @@ -1381,14 +1327,13 @@ DWORD CALLBACK copyCallbackInternal( HANDLE hDestinationFile, LPVOID lpData) { - //small performance optimization: it seems this callback function is called for every 64 kB (depending on cluster size). - static size_t callNr = 0; - if (++callNr % 4 == 0) //executing callback every 256 kB should suffice + if (lpData) { - if (lpData) - { - CallbackData& cbd = *static_cast<CallbackData*>(lpData); + CallbackData& cbd = *static_cast<CallbackData*>(lpData); + //small performance optimization: it seems this callback function is called for every 64 kB (depending on cluster size). + if (++cbd.callNr % 4 == 0) //executing callback every 256 kB should suffice + { //some odd check for some possible(?) error condition if (totalBytesTransferred.QuadPart < 0) //let's see if someone answers the call... ::MessageBox(NULL, L"You've just discovered a bug in WIN32 API function \"CopyFileEx\"! \n\n\ @@ -1398,12 +1343,15 @@ DWORD CALLBACK copyCallbackInternal( NULL, 0); try { - cbd.callback.updateCopyStatus(zen::UInt64(totalBytesTransferred.QuadPart)); + cbd.callback.updateCopyStatus(UInt64(totalBytesTransferred.QuadPart)); } catch (...) { +#ifndef _MSC_VER +#warning migrate to std::exception_ptr when available +#endif cbd.exceptionCaught = true; - cbd.bytesTransferredOnException = zen::UInt64(totalBytesTransferred.QuadPart); + cbd.bytesTransferredOnException = UInt64(totalBytesTransferred.QuadPart); return PROGRESS_CANCEL; } } @@ -1413,23 +1361,6 @@ DWORD CALLBACK copyCallbackInternal( } -#ifndef COPY_FILE_COPY_SYMLINK -#define COPY_FILE_COPY_SYMLINK 0x00000800 -#endif - -bool supportForSymbolicLinks() -{ - OSVERSIONINFO osvi = {}; - osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFO); - - //symbolic links are supported starting with Vista - if (::GetVersionEx(&osvi)) - return osvi.dwMajorVersion > 5; //XP has majorVersion == 5, minorVersion == 1; Vista majorVersion == 6, dwMinorVersion == 0 - //overview: http://msdn.microsoft.com/en-us/library/ms724834(VS.85).aspx - return false; -} - - #ifndef COPY_FILE_ALLOW_DECRYPTED_DESTINATION #define COPY_FILE_ALLOW_DECRYPTED_DESTINATION 0x00000008 #endif @@ -1456,12 +1387,12 @@ void rawCopyWinApi(const Zstring& sourceFile, DWORD copyFlags = COPY_FILE_FAIL_IF_EXISTS; - // static const bool symlinksSupported = supportForSymbolicLinks(); //only set "true" if supported by OS: else copying in Windows XP fails - // if (copyFileSymLinks && symlinksSupported) - // copyFlags |= COPY_FILE_COPY_SYMLINK; - //allow copying from encrypted to non-encrytped location - static const bool nonEncSupported = supportForNonEncryptedDestination(); + + static bool nonEncSupported = false; + static boost::once_flag once = BOOST_ONCE_INIT; //caveat: function scope static initialization is not thread-safe in VS 2010! + boost::call_once(once, []() { nonEncSupported = supportForNonEncryptedDestination(); }); + if (nonEncSupported) copyFlags |= COPY_FILE_ALLOW_DECRYPTED_DESTINATION; @@ -1484,7 +1415,7 @@ void rawCopyWinApi(const Zstring& sourceFile, //assemble error message... std::wstring errorMessage = _("Error copying file:") + "\n\"" + sourceFile + "\" ->\n\"" + targetFile + "\"" + - "\n\n" + zen::getLastErrorFormatted(lastError); + "\n\n" + getLastErrorFormatted(lastError); //if file is locked (try to) use Windows Volume Shadow Copy Service if (lastError == ERROR_SHARING_VIOLATION || @@ -1508,7 +1439,7 @@ void rawCopyWinApi(const Zstring& sourceFile, //trying to copy > 4GB file to FAT/FAT32 volume gives obscure ERROR_INVALID_PARAMETER (FAT can indeed handle files up to 4 Gig, tested!) if (lastError == ERROR_INVALID_PARAMETER && dst::isFatDrive(targetFile) && - getFilesize(sourceFile) >= 4U * zen::UInt64(1024U * 1024 * 1024)) //throw (FileError) + getFilesize(sourceFile) >= 4U * UInt64(1024U * 1024 * 1024)) //throw (FileError) errorMessage += L"\nFAT volume cannot store files larger than 4 gigabyte!"; } catch(...) {} @@ -1555,7 +1486,7 @@ void rawCopyWinApi(const Zstring& sourceFile, // */ // // //open sourceFile for reading -// HANDLE hFileIn = ::CreateFile(zen::applyLongPathPrefix(sourceFile).c_str(), +// HANDLE hFileIn = ::CreateFile(applyLongPathPrefix(sourceFile).c_str(), // GENERIC_READ, // FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, //all shared modes are required to read files that are open in other applications // NULL, @@ -1565,7 +1496,7 @@ void rawCopyWinApi(const Zstring& sourceFile, // if (hFileIn == INVALID_HANDLE_VALUE) // { // const DWORD lastError = ::GetLastError(); -// const std::wstring& errorMessage = _("Error opening file:") + "\n\"" + sourceFile + "\"" + "\n\n" + zen::getLastErrorFormatted(lastError); +// const std::wstring& errorMessage = _("Error opening file:") + "\n\"" + sourceFile + "\"" + "\n\n" + getLastErrorFormatted(lastError); // // //if file is locked (try to) use Windows Volume Shadow Copy Service // if (lastError == ERROR_SHARING_VIOLATION || @@ -1580,7 +1511,7 @@ void rawCopyWinApi(const Zstring& sourceFile, // // BY_HANDLE_FILE_INFORMATION infoFileIn = {}; // if (!::GetFileInformationByHandle(hFileIn, &infoFileIn)) -// throw FileError(_("Error reading file attributes:") + "\n\"" + sourceFile + "\"" + "\n\n" + zen::getLastErrorFormatted()); +// throw FileError(_("Error reading file attributes:") + "\n\"" + sourceFile + "\"" + "\n\n" + getLastErrorFormatted()); // // //####################################### DST hack ########################################### // if (dst::isFatDrive(sourceFile)) //throw() @@ -1609,7 +1540,7 @@ void rawCopyWinApi(const Zstring& sourceFile, // FILE_ATTRIBUTE_ENCRYPTED; // // //create targetFile and open it for writing -// HANDLE hFileOut = ::CreateFile(zen::applyLongPathPrefix(targetFile).c_str(), +// HANDLE hFileOut = ::CreateFile(applyLongPathPrefix(targetFile).c_str(), // GENERIC_READ | GENERIC_WRITE, //read access required for FSCTL_SET_COMPRESSION // FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, // NULL, @@ -1620,7 +1551,7 @@ void rawCopyWinApi(const Zstring& sourceFile, // { // const DWORD lastError = ::GetLastError(); // const std::wstring& errorMessage = _("Error writing file:") + "\n\"" + targetFile + "\"" + -// "\n\n" + zen::getLastErrorFormatted(lastError); +// "\n\n" + getLastErrorFormatted(lastError); // // if (lastError == ERROR_FILE_EXISTS) // throw ErrorTargetExisting(errorMessage); @@ -1648,7 +1579,7 @@ void rawCopyWinApi(const Zstring& sourceFile, // &fsFlags, //__out_opt LPDWORD lpFileSystemFlags, // NULL, //__out LPTSTR lpFileSystemNameBuffer, // 0)) //__in DWORD nFileSystemNameSize -// throw FileError(_("Error reading file attributes:") + "\n\"" + sourceFile + "\"" + "\n\n" + zen::getLastErrorFormatted()); +// throw FileError(_("Error reading file attributes:") + "\n\"" + sourceFile + "\"" + "\n\n" + getLastErrorFormatted()); // // const bool sourceIsEncrypted = (infoFileIn.dwFileAttributes & FILE_ATTRIBUTE_ENCRYPTED) != 0; // const bool sourceIsCompressed = (infoFileIn.dwFileAttributes & FILE_ATTRIBUTE_COMPRESSED) != 0; @@ -1675,7 +1606,7 @@ void rawCopyWinApi(const Zstring& sourceFile, // &bytesReturned, //number of bytes returned // NULL)) //OVERLAPPED structure // throw FileError(_("Error writing file:") + "\n\"" + targetFile + "\"" + -// "\n\n" + zen::getLastErrorFormatted() + +// "\n\n" + getLastErrorFormatted() + // "\nFailed to write NTFS compressed attribute!"); // } // @@ -1694,14 +1625,17 @@ void rawCopyWinApi(const Zstring& sourceFile, // &bytesReturned, //number of bytes returned // NULL)) //OVERLAPPED structure // throw FileError(_("Error writing file:") + "\n\"" + targetFile + "\"" + -// "\n\n" + zen::getLastErrorFormatted() + +// "\n\n" + getLastErrorFormatted() + // "\nFailed to write NTFS sparse attribute!"); // } // } // // // const DWORD BUFFER_SIZE = 512 * 1024; //512 kb seems to be a reasonable buffer size -// static const boost::scoped_array<BYTE> memory(new BYTE[BUFFER_SIZE]); +// static boost::thread_specific_ptr<std::vector<char>> cpyBuf; +// if (!cpyBuf.get()) +// cpyBuf.reset(new std::vector<char>(BUFFER_SIZE)); //512 kb seems to be a reasonable buffer size +// std::vector<char>& buffer = *cpyBuf; // // struct ManageCtxt //manage context for BackupRead()/BackupWrite() // { @@ -1719,7 +1653,7 @@ void rawCopyWinApi(const Zstring& sourceFile, // } context; // // //copy contents of sourceFile to targetFile -// zen::UInt64 totalBytesTransferred; +// UInt64 totalBytesTransferred; // // bool eof = false; // do @@ -1729,22 +1663,22 @@ void rawCopyWinApi(const Zstring& sourceFile, // if (useBackupFun) // { // if (!::BackupRead(hFileIn, //__in HANDLE hFile, -// memory.get(), //__out LPBYTE lpBuffer, +// &buffer[0], //__out LPBYTE lpBuffer, // BUFFER_SIZE, //__in DWORD nNumberOfBytesToRead, // &bytesRead, //__out LPDWORD lpNumberOfBytesRead, // false, //__in BOOL bAbort, // false, //__in BOOL bProcessSecurity, // &context.read)) //__out LPVOID *lpContext // throw FileError(_("Error reading file:") + "\n\"" + sourceFile + "\"" + -// "\n\n" + zen::getLastErrorFormatted()); +// "\n\n" + getLastErrorFormatted()); // } // else if (!::ReadFile(hFileIn, //__in HANDLE hFile, -// memory.get(), //__out LPVOID lpBuffer, +// &buffer[0], //__out LPVOID lpBuffer, // BUFFER_SIZE, //__in DWORD nNumberOfBytesToRead, // &bytesRead, //__out_opt LPDWORD lpNumberOfBytesRead, // NULL)) //__inout_opt LPOVERLAPPED lpOverlapped // throw FileError(_("Error reading file:") + "\n\"" + sourceFile + "\"" + -// "\n\n" + zen::getLastErrorFormatted()); +// "\n\n" + getLastErrorFormatted()); // // if (bytesRead > BUFFER_SIZE) // throw FileError(_("Error reading file:") + "\n\"" + sourceFile + "\"" + @@ -1758,22 +1692,22 @@ void rawCopyWinApi(const Zstring& sourceFile, // if (useBackupFun) // { // if (!::BackupWrite(hFileOut, //__in HANDLE hFile, -// memory.get(), //__in LPBYTE lpBuffer, +// &buffer[0], //__in LPBYTE lpBuffer, // bytesRead, //__in DWORD nNumberOfBytesToWrite, // &bytesWritten, //__out LPDWORD lpNumberOfBytesWritten, // false, //__in BOOL bAbort, // false, //__in BOOL bProcessSecurity, // &context.write)) //__out LPVOID *lpContext // throw FileError(_("Error writing file:") + "\n\"" + targetFile + "\"" + -// "\n\n" + zen::getLastErrorFormatted() + " (w)"); //w -> distinguish from fopen error message! +// "\n\n" + getLastErrorFormatted() + " (w)"); //w -> distinguish from fopen error message! // } // else if (!::WriteFile(hFileOut, //__in HANDLE hFile, -// memory.get(), //__out LPVOID lpBuffer, +// &buffer[0], //__out LPVOID lpBuffer, // bytesRead, //__in DWORD nNumberOfBytesToWrite, // &bytesWritten, //__out_opt LPDWORD lpNumberOfBytesWritten, // NULL)) //__inout_opt LPOVERLAPPED lpOverlapped // throw FileError(_("Error writing file:") + "\n\"" + targetFile + "\"" + -// "\n\n" + zen::getLastErrorFormatted() + " (w)"); //w -> distinguish from fopen error message! +// "\n\n" + getLastErrorFormatted() + " (w)"); //w -> distinguish from fopen error message! // // if (bytesWritten != bytesRead) // throw FileError(_("Error writing file:") + "\n\"" + targetFile + "\"" + "\n\n" + "incomplete write"); @@ -1803,7 +1737,7 @@ void rawCopyWinApi(const Zstring& sourceFile, // { // LARGE_INTEGER inputSize = {}; // if (!::GetFileSizeEx(hFileIn, &inputSize)) -// throw FileError(_("Error reading file attributes:") + "\n\"" + sourceFile + "\"" + "\n\n" + zen::getLastErrorFormatted()); +// throw FileError(_("Error reading file attributes:") + "\n\"" + sourceFile + "\"" + "\n\n" + getLastErrorFormatted()); // // if (inputSize.QuadPart != 0) // throw FileError(_("Error reading file:") + "\n\"" + sourceFile + "\"" + "\n\n" + "unknown error"); @@ -1814,7 +1748,7 @@ void rawCopyWinApi(const Zstring& sourceFile, // &infoFileIn.ftCreationTime, // NULL, // &infoFileIn.ftLastWriteTime)) -// throw FileError(_("Error changing modification time:") + "\n\"" + targetFile + "\"" + "\n\n" + zen::getLastErrorFormatted()); +// throw FileError(_("Error changing modification time:") + "\n\"" + targetFile + "\"" + "\n\n" + getLastErrorFormatted()); // // //#ifndef NDEBUG //dst hack: verify data written @@ -1878,10 +1812,13 @@ void rawCopyStream(const Zstring& sourceFile, //create targetFile and open it for writing FileOutput fileOut(targetFile, FileOutput::ACC_CREATE_NEW); //throw (FileError: ErrorTargetPathMissing, ErrorTargetExisting) - static std::vector<wchar_t> buffer(512 * 1024); //512 kb seems to be a reasonable buffer size + static boost::thread_specific_ptr<std::vector<char>> cpyBuf; + if (!cpyBuf.get()) + cpyBuf.reset(new std::vector<char>(512 * 1024)); //512 kb seems to be a reasonable buffer size + std::vector<char>& buffer = *cpyBuf; //copy contents of sourceFile to targetFile - zen::UInt64 totalBytesTransferred; + UInt64 totalBytesTransferred; do { const size_t bytesRead = fileIn.read(&buffer[0], buffer.size()); //throw (FileError) @@ -1944,7 +1881,7 @@ void zen::copyFile(const Zstring& sourceFile, //throw (FileError: ErrorTargetPat CallbackCopyFile* callback) { Zstring temporary = targetFile + zen::TEMP_FILE_ENDING; //use temporary file until a correct date has been set - Loki::ScopeGuard guardTempFile = Loki::MakeGuard(&removeFile, boost::cref(temporary)); //transactional behavior: ensure cleanup (e.g. network drop) -> cref [!] + Loki::ScopeGuard guardTempFile = Loki::MakeGuard([&]() { removeFile(temporary); }); //transactional behavior: ensure cleanup (e.g. network drop) -> ref to temporary[!] //raw file copy try diff --git a/shared/file_handling.h b/shared/file_handling.h index 0ee4b1e9..113168f3 100644 --- a/shared/file_handling.h +++ b/shared/file_handling.h @@ -3,7 +3,7 @@ // * GNU General Public License: http://www.gnu.org/licenses/gpl.html * // * Copyright (C) 2008-2011 ZenJu (zhnmju123 AT gmx.de) * // ************************************************************************** -// + #ifndef FILE_HANDLING_H_INCLUDED #define FILE_HANDLING_H_INCLUDED @@ -25,13 +25,15 @@ bool somethingExists(const Zstring& objname); //throw() check whether any //check whether two folders are located on the same (logical) volume //left and right directories NEED NOT yet exist! volume prefix is sufficient! path may end with PATH_SEPARATOR -enum ResponseSameVol +enum ResponseSame { - VOLUME_SAME, - VOLUME_DIFFERENT, - VOLUME_CANT_SAY + IS_SAME_YES, + IS_SAME_NO, + IS_SAME_CANT_SAY }; -ResponseSameVol onSameVolume(const Zstring& folderLeft, const Zstring& folderRight); //throw() +ResponseSame onSameVolume(const Zstring& folderLeft, const Zstring& folderRight); //throw() + +void checkthis(const Zstring& folderLeft); //throw() //copy file or directory create/last change date, void copyFileTimes(const Zstring& sourceDir, const Zstring& targetDir, bool derefSymlinks); //throw (FileError) diff --git a/shared/file_id.cpp b/shared/file_id.cpp index da8fd815..e6c016e7 100644 --- a/shared/file_id.cpp +++ b/shared/file_id.cpp @@ -3,7 +3,7 @@ // * GNU General Public License: http://www.gnu.org/licenses/gpl.html * // * Copyright (C) 2008-2011 ZenJu (zhnmju123 AT gmx.de) * // ************************************************************************** -// + #include "file_id.h" #ifdef FFS_WIN @@ -18,8 +18,7 @@ namespace { -template <class T> -inline +template <class T> inline std::string numberToBytes(T number) { const char* rawBegin = reinterpret_cast<const char*>(&number); diff --git a/shared/file_id.h b/shared/file_id.h index 2e94bf5a..eaf47e3c 100644 --- a/shared/file_id.h +++ b/shared/file_id.h @@ -3,7 +3,7 @@ // * GNU General Public License: http://www.gnu.org/licenses/gpl.html * // * Copyright (C) 2008-2011 ZenJu (zhnmju123 AT gmx.de) * // ************************************************************************** -// + #ifndef FILEID_H_INCLUDED #define FILEID_H_INCLUDED diff --git a/shared/file_io.cpp b/shared/file_io.cpp index c19101aa..2614ac06 100644 --- a/shared/file_io.cpp +++ b/shared/file_io.cpp @@ -3,7 +3,7 @@ // * GNU General Public License: http://www.gnu.org/licenses/gpl.html * // * Copyright (C) 2008-2011 ZenJu (zhnmju123 AT gmx.de) * // ************************************************************************** -// + #include "file_io.h" #include "last_error.h" #include "i18n.h" diff --git a/shared/file_io.h b/shared/file_io.h index 79b521f1..6f87845b 100644 --- a/shared/file_io.h +++ b/shared/file_io.h @@ -3,7 +3,7 @@ // * GNU General Public License: http://www.gnu.org/licenses/gpl.html * // * Copyright (C) 2008-2011 ZenJu (zhnmju123 AT gmx.de) * // ************************************************************************** -// + #ifndef FILEIO_H_INCLUDED #define FILEIO_H_INCLUDED diff --git a/shared/file_traverser.cpp b/shared/file_traverser.cpp index aced3487..595b2768 100644 --- a/shared/file_traverser.cpp +++ b/shared/file_traverser.cpp @@ -3,7 +3,7 @@ // * GNU General Public License: http://www.gnu.org/licenses/gpl.html * // * Copyright (C) 2008-2011 ZenJu (zhnmju123 AT gmx.de) * // ************************************************************************** -// + #include "file_traverser.h" #include <limits> #include "last_error.h" @@ -14,6 +14,7 @@ #include <wx/msw/wrapwin.h> //includes "windows.h" #include "long_path_prefix.h" #include "dst_hack.h" +#include "file_update_handle.h" #elif defined FFS_LINUX #include <sys/stat.h> @@ -57,7 +58,7 @@ inline zen::Int64 filetimeToTimeT(const FILETIME& lastWriteTime) { //convert UTC FILETIME to ANSI C format (number of seconds since Jan. 1st 1970 UTC) - zen::Int64 writeTimeLong = zen::to<zen::Int64>(zen::UInt64(lastWriteTime.dwLowDateTime, lastWriteTime.dwHighDateTime) / 10000000U); //reduce precision to 1 second (FILETIME has unit 10^-7 s) + zen::Int64 writeTimeLong = to<zen::Int64>(zen::UInt64(lastWriteTime.dwLowDateTime, lastWriteTime.dwHighDateTime) / 10000000U); //reduce precision to 1 second (FILETIME has unit 10^-7 s) writeTimeLong -= zen::Int64(3054539008UL, 2); //timeshift between ansi C time and FILETIME in seconds == 11644473600s return writeTimeLong; } @@ -126,14 +127,12 @@ public: } private: - DirTraverser(const DirTraverser&); - DirTraverser& operator=(const DirTraverser&); + DirTraverser(const DirTraverser&); + DirTraverser& operator=(const DirTraverser&); template <bool followSymlinks> void traverse(const Zstring& directory, zen::TraverseCallback& sink, int level) { - using namespace zen; - tryReportingError([&](std::wstring& errorMsg) -> bool { if (level == 100) //notify endless recursion @@ -146,19 +145,16 @@ private: #ifdef FFS_WIN - //ensure directoryFormatted ends with backslash - const Zstring& directoryFormatted = directory.EndsWith(FILE_NAME_SEPARATOR) ? - directory : - directory + FILE_NAME_SEPARATOR; - + //ensure directoryPf ends with backslash + const Zstring& directoryPf = directory.EndsWith(FILE_NAME_SEPARATOR) ? + directory : + directory + FILE_NAME_SEPARATOR; WIN32_FIND_DATA fileInfo = {}; HANDLE searchHandle = INVALID_HANDLE_VALUE; tryReportingError([&](std::wstring& errorMsg) -> bool { - searchHandle = ::FindFirstFile( - applyLongPathPrefix(directoryFormatted + Zchar('*')).c_str(), //__in LPCTSTR lpFileName - &fileInfo); //__out LPWIN32_FIND_DATA lpFindFileData + searchHandle = ::FindFirstFile(applyLongPathPrefix(directoryPf + L'*').c_str(), &fileInfo); //no noticable performance difference compared to FindFirstFileEx with FindExInfoBasic, FIND_FIRST_EX_CASE_SENSITIVE and/or FIND_FIRST_EX_LARGE_FETCH if (searchHandle == INVALID_HANDLE_VALUE) @@ -188,7 +184,7 @@ private: (shortName[1] == L'\0' || (shortName[1] == L'.' && shortName[2] == L'\0'))) continue; - const Zstring& fullName = directoryFormatted + shortName; + const Zstring& fullName = directoryPf + shortName; const bool isSymbolicLink = (fileInfo.dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT) != 0; @@ -254,7 +250,7 @@ private: details.fileSize = zen::UInt64(fileInfo.nFileSizeLow, fileInfo.nFileSizeHigh); } - sink.onFile(shortName, fullName, details); + sink.onFile(shortName, fullName, details); } } while ([&]() -> bool @@ -322,7 +318,7 @@ private: //don't return "." and ".." - const Zchar* const shortName = dirEntry->d_name; + const char* const shortName = dirEntry->d_name; if (shortName[0] == '.' && (shortName[1] == '\0' || (shortName[1] == '.' && shortName[2] == '\0'))) continue; @@ -421,23 +417,25 @@ private: const dst::RawTime encodedTime = dst::fatEncodeUtcTime(i->second); //throw (std::runtime_error) { - HANDLE hTarget = ::CreateFile(zen::applyLongPathPrefix(i->first).c_str(), - GENERIC_WRITE, //just FILE_WRITE_ATTRIBUTES may not be enough for some NAS shares! - FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, - NULL, - OPEN_EXISTING, - FILE_FLAG_BACKUP_SEMANTICS, - NULL); - if (hTarget == INVALID_HANDLE_VALUE) + //may need to remove the readonly-attribute (e.g. FAT usb drives) + FileUpdateHandle updateHandle(i->first, [=]() + { + return ::CreateFile(zen::applyLongPathPrefix(i->first).c_str(), + GENERIC_WRITE, //just FILE_WRITE_ATTRIBUTES may not be enough for some NAS shares! + FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, + NULL, + OPEN_EXISTING, + FILE_FLAG_BACKUP_SEMANTICS, + NULL); + }); + if (updateHandle.get() == INVALID_HANDLE_VALUE) { ++failedAttempts; assert(false); //don't throw exceptions due to dst hack here continue; } - Loki::ScopeGuard dummy = Loki::MakeGuard(::CloseHandle, hTarget); - (void)dummy; //silence warning "unused variable" - if (!::SetFileTime(hTarget, + if (!::SetFileTime(updateHandle.get(), &encodedTime.createTimeRaw, NULL, &encodedTime.writeTimeRaw)) @@ -483,7 +481,7 @@ void zen::traverseFolder(const Zstring& directory, bool followSymlinks, Traverse #ifdef FFS_WIN try //traversing certain folders with restricted permissions requires this privilege! (but copying these files may still fail) { - zen::Privileges::getInstance().ensureActive(SE_BACKUP_NAME); //throw (FileError) + zen::Privileges::getInstance().ensureActive(SE_BACKUP_NAME); //throw FileError } catch (...) {} //don't cause issues in user mode #endif diff --git a/shared/file_traverser.h b/shared/file_traverser.h index 18d692df..aa9dffad 100644 --- a/shared/file_traverser.h +++ b/shared/file_traverser.h @@ -3,7 +3,7 @@ // * GNU General Public License: http://www.gnu.org/licenses/gpl.html * // * Copyright (C) 2008-2011 ZenJu (zhnmju123 AT gmx.de) * // ************************************************************************** -// + #ifndef FILETRAVERSER_H_INCLUDED #define FILETRAVERSER_H_INCLUDED diff --git a/shared/file_update_handle.h b/shared/file_update_handle.h new file mode 100644 index 00000000..1ffb7000 --- /dev/null +++ b/shared/file_update_handle.h @@ -0,0 +1,67 @@ +#ifndef FILE_UPDATE_HANDLE_H_INCLUDED +#define FILE_UPDATE_HANDLE_H_INCLUDED + +#include <wx/msw/wrapwin.h> //includes "windows.h" +#include "long_path_prefix.h" + +namespace +{ +//manage file handle to update existing files (temporarily resetting read-only if necessary) +//CreateFileCmd: lambda directly returning non-owned file handle from ::CreateFile() +class FileUpdateHandle +{ +public: + template <class CreateFileCmd> + FileUpdateHandle(const Zstring& filename, CreateFileCmd cmd) : + filenameFmt(zen::applyLongPathPrefix(filename)), + hFile(INVALID_HANDLE_VALUE), + attr(INVALID_FILE_ATTRIBUTES) + { + hFile = cmd(); + if (hFile != INVALID_HANDLE_VALUE) + return; + + const DWORD lastError = ::GetLastError(); + if (lastError == ERROR_ACCESS_DENIED) //function fails if file is read-only + { + Loki::ScopeGuard guardErrorCode = Loki::MakeGuard(::SetLastError, lastError); //transactional behavior: ensure cleanup (e.g. network drop) -> cref [!] + + //read-only file attribute may cause trouble: temporarily reset it + const DWORD tmpAttr = ::GetFileAttributes(filenameFmt.c_str()); + if (tmpAttr != INVALID_FILE_ATTRIBUTES && (tmpAttr & FILE_ATTRIBUTE_READONLY)) + { + if (::SetFileAttributes(filenameFmt.c_str(), FILE_ATTRIBUTE_NORMAL)) + { + guardErrorCode.Dismiss(); + attr = tmpAttr; //"create" guard on read-only attribute + + //now try again + hFile = cmd(); + } + } + } + } + + ~FileUpdateHandle() + { + if (hFile != INVALID_HANDLE_VALUE) + ::CloseHandle(hFile); + + if (attr != INVALID_FILE_ATTRIBUTES) + ::SetFileAttributes(filenameFmt.c_str(), attr); + } + + //may return INVALID_FILE_ATTRIBUTES, in which case ::GetLastError() may be called directly after FileUpdateHandle() + HANDLE get() const { return hFile; } + +private: + FileUpdateHandle(const FileUpdateHandle&); + FileUpdateHandle& operator=(const FileUpdateHandle&); + + Zstring filenameFmt; + HANDLE hFile; + DWORD attr; +}; +} + +#endif // FILE_UPDATE_HANDLE_H_INCLUDED diff --git a/shared/global_func.h b/shared/global_func.h index bf9f13dd..861e2081 100644 --- a/shared/global_func.h +++ b/shared/global_func.h @@ -3,7 +3,7 @@ // * GNU General Public License: http://www.gnu.org/licenses/gpl.html * // * Copyright (C) 2008-2011 ZenJu (zhnmju123 AT gmx.de) * // ************************************************************************** -// + #ifndef GLOBALFUNCTIONS_H_INCLUDED #define GLOBALFUNCTIONS_H_INCLUDED diff --git a/shared/guid.cpp b/shared/guid.cpp index 1580a62d..1cc304cb 100644 --- a/shared/guid.cpp +++ b/shared/guid.cpp @@ -3,7 +3,7 @@ // * GNU General Public License: http://www.gnu.org/licenses/gpl.html * // * Copyright (C) 2008-2011 ZenJu (zhnmju123 AT gmx.de) * // ************************************************************************** -// + #include "guid.h" #include <boost/uuid/uuid.hpp> diff --git a/shared/guid.h b/shared/guid.h index 166e9eb1..1986b101 100644 --- a/shared/guid.h +++ b/shared/guid.h @@ -3,7 +3,7 @@ // * GNU General Public License: http://www.gnu.org/licenses/gpl.html * // * Copyright (C) 2008-2011 ZenJu (zhnmju123 AT gmx.de) * // ************************************************************************** -// + #ifndef GUID_H_INCLUDED #define GUID_H_INCLUDED diff --git a/shared/help_provider.cpp b/shared/help_provider.cpp index 2c5d5aa9..7eb043cd 100644 --- a/shared/help_provider.cpp +++ b/shared/help_provider.cpp @@ -3,7 +3,7 @@ // * GNU General Public License: http://www.gnu.org/licenses/gpl.html * // * Copyright (C) 2008-2011 ZenJu (zhnmju123 AT gmx.de) * // ************************************************************************** -// + #include "help_provider.h" #include <wx/help.h> #include "standard_paths.h" diff --git a/shared/help_provider.h b/shared/help_provider.h index 01ac3054..dbe3ce26 100644 --- a/shared/help_provider.h +++ b/shared/help_provider.h @@ -3,7 +3,7 @@ // * GNU General Public License: http://www.gnu.org/licenses/gpl.html * // * Copyright (C) 2008-2011 ZenJu (zhnmju123 AT gmx.de) * // ************************************************************************** -// + #ifndef HELPPROVIDER_H_INCLUDED #define HELPPROVIDER_H_INCLUDED diff --git a/shared/i18n.h b/shared/i18n.h index cac6555c..8aa38f3c 100644 --- a/shared/i18n.h +++ b/shared/i18n.h @@ -3,7 +3,7 @@ // * GNU General Public License: http://www.gnu.org/licenses/gpl.html * // * Copyright (C) 2008-2011 ZenJu (zhnmju123 AT gmx.de) * // ************************************************************************** -// + #ifndef I18_N_HEADER_3843489325045 #define I18_N_HEADER_3843489325045 diff --git a/shared/int64.h b/shared/int64.h index 15900fde..61ef1716 100644 --- a/shared/int64.h +++ b/shared/int64.h @@ -3,7 +3,7 @@ // * GNU General Public License: http://www.gnu.org/licenses/gpl.html * // * Copyright (C) 2008-2011 ZenJu (zhnmju123 AT gmx.de) * // ************************************************************************** -// + #ifndef FFS_LARGE_64_BIT_INTEGER_H_INCLUDED #define FFS_LARGE_64_BIT_INTEGER_H_INCLUDED diff --git a/shared/last_error.cpp b/shared/last_error.cpp index ea8345bc..57053c30 100644 --- a/shared/last_error.cpp +++ b/shared/last_error.cpp @@ -3,7 +3,7 @@ // * GNU General Public License: http://www.gnu.org/licenses/gpl.html * // * Copyright (C) 2008-2011 ZenJu (zhnmju123 AT gmx.de) * // ************************************************************************** -// + #include "last_error.h" #include "string_utf8.h" #include "i18n.h" diff --git a/shared/last_error.h b/shared/last_error.h index b617ebf5..3e90a1a0 100644 --- a/shared/last_error.h +++ b/shared/last_error.h @@ -3,7 +3,7 @@ // * GNU General Public License: http://www.gnu.org/licenses/gpl.html * // * Copyright (C) 2008-2011 ZenJu (zhnmju123 AT gmx.de) * // ************************************************************************** -// + #ifndef SYSTEMFUNCTIONS_H_INCLUDED #define SYSTEMFUNCTIONS_H_INCLUDED diff --git a/shared/localization.cpp b/shared/localization.cpp index 919009d6..66b2d97b 100644 --- a/shared/localization.cpp +++ b/shared/localization.cpp @@ -3,7 +3,7 @@ // * GNU General Public License: http://www.gnu.org/licenses/gpl.html * // * Copyright (C) 2008-2011 ZenJu (zhnmju123 AT gmx.de) * // ************************************************************************** -// + #include "localization.h" #include <fstream> #include <map> diff --git a/shared/localization.h b/shared/localization.h index 07ac2a69..438ad445 100644 --- a/shared/localization.h +++ b/shared/localization.h @@ -3,7 +3,7 @@ // * GNU General Public License: http://www.gnu.org/licenses/gpl.html * // * Copyright (C) 2008-2011 ZenJu (zhnmju123 AT gmx.de) * // ************************************************************************** -// + #ifndef MISC_H_INCLUDED #define MISC_H_INCLUDED diff --git a/shared/long_path_prefix.h b/shared/long_path_prefix.h index b6da9168..45fde0fa 100644 --- a/shared/long_path_prefix.h +++ b/shared/long_path_prefix.h @@ -3,7 +3,7 @@ // * GNU General Public License: http://www.gnu.org/licenses/gpl.html * // * Copyright (C) 2008-2011 ZenJu (zhnmju123 AT gmx.de) * // ************************************************************************** -// + #ifndef LONGPATHPREFIX_H_INCLUDED #define LONGPATHPREFIX_H_INCLUDED diff --git a/shared/mouse_move_dlg.cpp b/shared/mouse_move_dlg.cpp index 95074b55..7981df49 100644 --- a/shared/mouse_move_dlg.cpp +++ b/shared/mouse_move_dlg.cpp @@ -3,7 +3,7 @@ // * GNU General Public License: http://www.gnu.org/licenses/gpl.html * // * Copyright (C) 2008-2011 ZenJu (zhnmju123 AT gmx.de) * // ************************************************************************** -// + #include "mouse_move_dlg.h" #include <vector> #include <wx/msw/wrapwin.h> //includes "windows.h" diff --git a/shared/mouse_move_dlg.h b/shared/mouse_move_dlg.h index 2e23c089..4412529c 100644 --- a/shared/mouse_move_dlg.h +++ b/shared/mouse_move_dlg.h @@ -3,7 +3,7 @@ // * GNU General Public License: http://www.gnu.org/licenses/gpl.html * // * Copyright (C) 2008-2011 ZenJu (zhnmju123 AT gmx.de) * // ************************************************************************** -// + #ifndef MOUSEMOVEWINDOW_H_INCLUDED #define MOUSEMOVEWINDOW_H_INCLUDED diff --git a/shared/notify_removal.cpp b/shared/notify_removal.cpp index 819604ad..3a9239db 100644 --- a/shared/notify_removal.cpp +++ b/shared/notify_removal.cpp @@ -3,7 +3,7 @@ // * GNU General Public License: http://www.gnu.org/licenses/gpl.html * // * Copyright (C) 2008-2011 ZenJu (zhnmju123 AT gmx.de) * // ************************************************************************** -// + #include "notify_removal.h" #include <set> #include "last_error.h" @@ -183,8 +183,8 @@ public: } private: - Pimpl(Pimpl&); - Pimpl& operator=(Pimpl&); + Pimpl(Pimpl&); + Pimpl& operator=(Pimpl&); virtual void onMessage(UINT message, WPARAM wParam, LPARAM lParam) //throw()! { diff --git a/shared/notify_removal.h b/shared/notify_removal.h index abdf460b..f9d1cbaf 100644 --- a/shared/notify_removal.h +++ b/shared/notify_removal.h @@ -3,7 +3,7 @@ // * GNU General Public License: http://www.gnu.org/licenses/gpl.html * // * Copyright (C) 2008-2011 ZenJu (zhnmju123 AT gmx.de) * // ************************************************************************** -// + #ifndef NOTIFY_H_INCLUDED #define NOTIFY_H_INCLUDED diff --git a/shared/parse_lng.h b/shared/parse_lng.h index fcf20d28..b943d222 100644 --- a/shared/parse_lng.h +++ b/shared/parse_lng.h @@ -3,7 +3,7 @@ // * GNU General Public License: http://www.gnu.org/licenses/gpl.html * // * Copyright (C) 2008-2011 ZenJu (zhnmju123 AT gmx.de) * // ************************************************************************** -// + #ifndef PARSE_LNG_HEADER_INCLUDED #define PARSE_LNG_HEADER_INCLUDED diff --git a/shared/parse_plural.h b/shared/parse_plural.h index 3837feba..1139ffb6 100644 --- a/shared/parse_plural.h +++ b/shared/parse_plural.h @@ -3,7 +3,7 @@ // * GNU General Public License: http://www.gnu.org/licenses/gpl.html * // * Copyright (C) 2008-2011 ZenJu (zhnmju123 AT gmx.de) * // ************************************************************************** -// + #ifndef PARSE_PLURAL_H_INCLUDED #define PARSE_PLURAL_H_INCLUDED diff --git a/shared/parse_txt.h b/shared/parse_txt.h index 56147425..ca155dec 100644 --- a/shared/parse_txt.h +++ b/shared/parse_txt.h @@ -3,7 +3,7 @@ // * GNU General Public License: http://www.gnu.org/licenses/gpl.html * // * Copyright (C) 2008-2011 ZenJu (zhnmju123 AT gmx.de) * // ************************************************************************** -// + #ifndef PARSE_TXT_H_INCLUDED #define PARSE_TXT_H_INCLUDED diff --git a/shared/pch.h b/shared/pch.h index 06d6b417..aae74c08 100644 --- a/shared/pch.h +++ b/shared/pch.h @@ -3,7 +3,7 @@ // * GNU General Public License: http://www.gnu.org/licenses/gpl.html * // * Copyright (C) 2008-2011 ZenJu (zhnmju123 AT gmx.de) * // ************************************************************************** -// + #ifndef FFS_PRECOMPILED_HEADER #define FFS_PRECOMPILED_HEADER diff --git a/shared/perf.h b/shared/perf.h index f62f9cc0..9bcf7882 100644 --- a/shared/perf.h +++ b/shared/perf.h @@ -3,7 +3,7 @@ // * GNU General Public License: http://www.gnu.org/licenses/gpl.html * // * Copyright (C) 2008-2011 ZenJu (zhnmju123 AT gmx.de) * // ************************************************************************** -// + #ifndef DEBUG_PERF_HEADER #define DEBUG_PERF_HEADER diff --git a/shared/recycler.cpp b/shared/recycler.cpp index cc216d4f..92b7b222 100644 --- a/shared/recycler.cpp +++ b/shared/recycler.cpp @@ -3,13 +3,15 @@ // * GNU General Public License: http://www.gnu.org/licenses/gpl.html * // * Copyright (C) 2008-2011 ZenJu (zhnmju123 AT gmx.de) * // ************************************************************************** -// + #include "recycler.h" #include <stdexcept> #include <iterator> #include "i18n.h" +#include "file_handling.h" #ifdef FFS_WIN +#include <boost/thread/once.hpp> #include "dll_loader.h" #include <wx/msw/wrapwin.h> //includes "windows.h" #include "build_info.h" @@ -45,7 +47,6 @@ std::wstring getRecyclerDllName() bool vistaOrLater() { OSVERSIONINFO osvi = {}; - ZeroMemory(&osvi, sizeof(OSVERSIONINFO)); osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFO); //IFileOperation is supported with Vista and later @@ -72,12 +73,12 @@ Nevertheless, let's use IFileOperation for better error reporting! void moveToWindowsRecycler(const std::vector<Zstring>& filesToDelete) //throw (FileError) { - using zen::FileError; - if (filesToDelete.empty()) return; - static const bool useIFileOperation = vistaOrLater(); + static bool useIFileOperation = false; + static boost::once_flag once = BOOST_ONCE_INIT; //caveat: function scope static initialization is not thread-safe in VS 2010! + boost::call_once(once, []() { useIFileOperation = vistaOrLater(); }); if (useIFileOperation) //new recycle bin usage: available since Vista { @@ -86,14 +87,8 @@ void moveToWindowsRecycler(const std::vector<Zstring>& filesToDelete) //throw ( std::back_inserter(fileNames), std::mem_fun_ref(&Zstring::c_str)); using namespace fileop; - - static MoveToRecycleBinFct moveToRecycler = NULL; - if (!moveToRecycler) - moveToRecycler = util::getDllFun<MoveToRecycleBinFct>(getRecyclerDllName(), moveToRecycleBinFctName); - - static GetLastErrorFct getLastError = NULL; - if (!getLastError) - getLastError = util::getDllFun<GetLastErrorFct>(getRecyclerDllName(), getLastErrorFctName); + MoveToRecycleBinFct moveToRecycler = util::getDllFun<MoveToRecycleBinFct>(getRecyclerDllName(), moveToRecycleBinFctName); + GetLastErrorFct getLastError = util::getDllFun<GetLastErrorFct> (getRecyclerDllName(), getLastErrorFctName); if (moveToRecycler == NULL || getLastError == NULL) throw FileError(_("Error moving to Recycle Bin:") + "\n\"" + fileNames[0] + "\"" + //report first file only... better than nothing @@ -122,7 +117,7 @@ void moveToWindowsRecycler(const std::vector<Zstring>& filesToDelete) //throw ( //filenameDoubleNull += removeLongPathPrefix(*i); //::SHFileOperation() can't handle \\?\-prefix! //You should use fully-qualified path names with this function. Using it with relative path names is not thread safe. filenameDoubleNull += *i; //::SHFileOperation() can't handle \\?\-prefix! - filenameDoubleNull += Zchar(0); + filenameDoubleNull += L'\0'; } SHFILEOPSTRUCT fileOp = {}; @@ -137,7 +132,7 @@ void moveToWindowsRecycler(const std::vector<Zstring>& filesToDelete) //throw ( if (::SHFileOperation(&fileOp) != 0 || fileOp.fAnyOperationsAborted) { - throw FileError(_("Error moving to Recycle Bin:") + "\n\"" + filenameDoubleNull.c_str() + "\""); //report first file only... better than nothing + throw FileError(_("Error moving to Recycle Bin:") + "\n\"" + filenameDoubleNull + "\""); //report first file only... better than nothing } } } @@ -145,41 +140,48 @@ void moveToWindowsRecycler(const std::vector<Zstring>& filesToDelete) //throw ( } -bool zen::moveToRecycleBin(const Zstring& fileToDelete) //throw (FileError) +bool zen::moveToRecycleBin(const Zstring& filename) //throw (FileError) { -#ifdef FFS_WIN - const Zstring filenameFmt = applyLongPathPrefix(fileToDelete); - - const DWORD attr = ::GetFileAttributes(filenameFmt.c_str()); - if (attr == INVALID_FILE_ATTRIBUTES) + if (!somethingExists(filename)) return false; //neither file nor any other object with that name existing: no error situation, manual deletion relies on it! - //::SetFileAttributes(filenameFmt.c_str(), FILE_ATTRIBUTE_NORMAL); - //both SHFileOperation and useIFileOperation are not able to delete a folder named "System Volume Information" with normal attributes but shamelessly report success +#ifdef FFS_WIN + //::SetFileAttributes(applyLongPathPrefix(filename).c_str(), FILE_ATTRIBUTE_NORMAL); + //both SHFileOperation and IFileOperation are not able to delete a folder named "System Volume Information" with normal attributes but shamelessly report success std::vector<Zstring> fileNames; - fileNames.push_back(fileToDelete); + fileNames.push_back(filename); ::moveToWindowsRecycler(fileNames); //throw (FileError) #elif defined FFS_LINUX - struct stat fileInfo = {}; - if (::lstat(fileToDelete.c_str(), &fileInfo) != 0) - return false; //neither file nor any other object with that name existing: no error situation, manual deletion relies on it! - - Glib::RefPtr<Gio::File> fileObj = Gio::File::create_for_path(fileToDelete.c_str()); //never fails + Glib::RefPtr<Gio::File> fileObj = Gio::File::create_for_path(filename.c_str()); //never fails try { if (!fileObj->trash()) - throw FileError(_("Error moving to Recycle Bin:") + "\n\"" + fileToDelete + "\"" + + throw FileError(_("Error moving to Recycle Bin:") + "\n\"" + filename + "\"" + "\n\n" + "(unknown error)"); } catch (const Glib::Error& errorObj) { + //implement same behavior as in Windows: if recycler is not existing, delete permanently + if (errorObj.code() == G_IO_ERROR_NOT_SUPPORTED) + { + struct stat fileInfo = {}; + if (::lstat(filename.c_str(), &fileInfo) != 0) + return false; + + if (S_ISLNK(fileInfo.st_mode) || S_ISREG(fileInfo.st_mode)) + removeFile(filename); //throw FileError + else if (S_ISDIR(fileInfo.st_mode)) + removeDirectory(filename); //throw FileError + return true; + } + //assemble error message - const std::wstring errorMessage = L"Glib Error Code " + toString<std::wstring>(errorObj.code()) + ", " + - g_quark_to_string(errorObj.domain()) + ": " + errorObj.what(); + const std::wstring errorMessage = L"Glib Error Code " + toString<std::wstring>(errorObj.code()) + /* ", " + + g_quark_to_string(errorObj.domain()) + */ ": " + errorObj.what(); - throw FileError(_("Error moving to Recycle Bin:") + "\n\"" + fileToDelete + "\"" + + throw FileError(_("Error moving to Recycle Bin:") + "\n\"" + filename + "\"" + "\n\n" + "(" + errorMessage + ")"); } #endif @@ -188,15 +190,15 @@ bool zen::moveToRecycleBin(const Zstring& fileToDelete) //throw (FileError) #ifdef FFS_WIN -zen::StatusRecycler zen::recycleBinExists(const Zstring& pathName) +zen::StatusRecycler zen::recycleBinStatus(const Zstring& pathName) { std::vector<wchar_t> buffer(MAX_PATH + 1); if (::GetVolumePathName(applyLongPathPrefix(pathName).c_str(), //__in LPCTSTR lpszFileName, &buffer[0], //__out LPTSTR lpszVolumePathName, static_cast<DWORD>(buffer.size()))) //__in DWORD cchBufferLength { - Zstring rootPath =&buffer[0]; - if (!rootPath.EndsWith(FILE_NAME_SEPARATOR)) //a trailing backslash is required + Zstring rootPath = &buffer[0]; + if (!endsWith(rootPath, FILE_NAME_SEPARATOR)) //a trailing backslash is required rootPath += FILE_NAME_SEPARATOR; SHQUERYRBINFO recInfo = {}; @@ -207,4 +209,22 @@ zen::StatusRecycler zen::recycleBinExists(const Zstring& pathName) } return STATUS_REC_UNKNOWN; } +#elif defined FFS_LINUX +/* +We really need access to a similar function to check whether a directory supports trashing and emit a warning if it does not! + +The following function looks perfect, alas it is restricted to local files and to the implementation of GIO only: + + gboolean _g_local_file_has_trash_dir(const char* dirname, dev_t dir_dev); + See: http://www.netmite.com/android/mydroid/2.0/external/bluetooth/glib/gio/glocalfileinfo.h + + Just checking for "G_FILE_ATTRIBUTE_ACCESS_CAN_TRASH" is not correct, since we find in + http://www.netmite.com/android/mydroid/2.0/external/bluetooth/glib/gio/glocalfileinfo.c + + g_file_info_set_attribute_boolean (info, G_FILE_ATTRIBUTE_ACCESS_CAN_TRASH, + writable && parent_info->has_trash_dir); + + => We're NOT interested in whether the specified folder can be trashed, but whether it supports thrashing its child elements! (Only support, not actual write access!) + This renders G_FILE_ATTRIBUTE_ACCESS_CAN_TRASH useless for this purpose. +*/ #endif diff --git a/shared/recycler.h b/shared/recycler.h index da6e3123..718b64cc 100644 --- a/shared/recycler.h +++ b/shared/recycler.h @@ -3,7 +3,7 @@ // * GNU General Public License: http://www.gnu.org/licenses/gpl.html * // * Copyright (C) 2008-2011 ZenJu (zhnmju123 AT gmx.de) * // ************************************************************************** -// + #ifndef RECYCLER_H_INCLUDED #define RECYCLER_H_INCLUDED @@ -23,15 +23,12 @@ Recycler always available: during runtime either SHFileOperation or (since Vista Linux ----- -Include compilation flag: -`pkg-config --cflags gtkmm-2.4` - -Linker flag: -`pkg-config --libs gtkmm-2.4` +Compiler flag: `pkg-config --cflags gtkmm-2.4` +Linker flag: `pkg-config --libs gtkmm-2.4` */ -//move a file or folder to Recycle Bin -bool moveToRecycleBin(const Zstring& fileToDelete); //return "true" if file/dir was actually deleted; throw (FileError) +//move a file or folder to Recycle Bin (deletes permanently if recycle is not available) +bool moveToRecycleBin(const Zstring& filename); //return "true" if file/dir was actually deleted; throw (FileError) #ifdef FFS_WIN @@ -42,7 +39,7 @@ enum StatusRecycler STATUS_REC_UNKNOWN }; -StatusRecycler recycleBinExists(const Zstring& pathName); //test existence of Recycle Bin API for certain path +StatusRecycler recycleBinStatus(const Zstring& pathName); //test existence of Recycle Bin API for certain path #endif } diff --git a/shared/resolve_path.cpp b/shared/resolve_path.cpp index 19dc0011..a9d1e0e5 100644 --- a/shared/resolve_path.cpp +++ b/shared/resolve_path.cpp @@ -8,6 +8,9 @@ #include "dll_loader.h" #include <wx/msw/wrapwin.h> //includes "windows.h" #include "long_path_prefix.h" +#ifdef _MSC_VER +#pragma comment(lib, "Mpr.lib") +#endif #elif defined FFS_LINUX #include <map> @@ -21,20 +24,42 @@ using namespace zen; namespace { #ifdef FFS_WIN -Zstring resolveRelativePath(const Zstring& relativeName, DWORD proposedBufferSize = 1000) +Zstring resolveBrokenNetworkMap(const Zstring& dirname) //circumvent issue with disconnected network maps that could be activated by a simple explorer double click { - std::vector<Zchar> fullPath(proposedBufferSize); - - const DWORD rv = ::GetFullPathName( - applyLongPathPrefix(relativeName).c_str(), //__in LPCTSTR lpFileName, - proposedBufferSize, //__in DWORD nBufferLength, - &fullPath[0], //__out LPTSTR lpBuffer, - NULL); //__out LPTSTR *lpFilePart - if (rv == 0 || rv == proposedBufferSize) + if (dirname.size() >= 2 && iswalpha(dirname[0]) && dirname[1] == L':') + { + Zstring driveLetter(dirname.c_str(), 2); //e.g.: "Q:" + if (::GetFileAttributes((driveLetter + L'\\').c_str()) == INVALID_FILE_ATTRIBUTES) + { + DWORD bufferSize = 10000; + std::vector<wchar_t> remoteNameBuffer(bufferSize); + DWORD rv = ::WNetGetConnection(driveLetter.c_str(), //__in LPCTSTR lpLocalName in the form "<driveletter>:" + &remoteNameBuffer[0], //__out LPTSTR lpRemoteName, + &bufferSize); //__inout LPDWORD lpnLength + (void)rv; + //no error check here! remoteNameBuffer will be filled on ERROR_CONNECTION_UNAVAIL and maybe others? + Zstring networkShare = &remoteNameBuffer[0]; + if (!networkShare.empty()) + return networkShare + (dirname.c_str() + 2); //replace "Q:\subdir" by "\\server\share\subdir" + } + } + return dirname; +} + + +Zstring resolveRelativePath(Zstring relativeName) +{ + relativeName = resolveBrokenNetworkMap(relativeName); + + std::vector<Zchar> fullPath(10000); + + const DWORD rv = ::GetFullPathName(applyLongPathPrefix(relativeName).c_str(), //__in LPCTSTR lpFileName, + static_cast<DWORD>(fullPath.size()), //__in DWORD nBufferLength, + &fullPath[0], //__out LPTSTR lpBuffer, + NULL); //__out LPTSTR *lpFilePart + if (rv == 0 || rv >= fullPath.size()) //theoretically, rv can never be == fullPath.size() //ERROR! Don't do anything return relativeName; - if (rv > proposedBufferSize) - return resolveRelativePath(relativeName, rv); return &fullPath[0]; } diff --git a/shared/resolve_path.h b/shared/resolve_path.h index 4ee1a90f..f6ae58cb 100644 --- a/shared/resolve_path.h +++ b/shared/resolve_path.h @@ -3,7 +3,7 @@ // * GNU General Public License: http://www.gnu.org/licenses/gpl.html * // * Copyright (C) 2008-2011 ZenJu (zhnmju123 AT gmx.de) * // ************************************************************************** -// + #ifndef RESOLVE_PATH_H_INCLUDED #define RESOLVE_PATH_H_INCLUDED diff --git a/shared/serialize.cpp b/shared/serialize.cpp index c2da1202..26102820 100644 --- a/shared/serialize.cpp +++ b/shared/serialize.cpp @@ -3,7 +3,7 @@ // * GNU General Public License: http://www.gnu.org/licenses/gpl.html * // * Copyright (C) 2008-2011 ZenJu (zhnmju123 AT gmx.de) * // ************************************************************************** -// + #include "serialize.h" #include "i18n.h" diff --git a/shared/serialize.h b/shared/serialize.h index 769b8671..c8a94ad1 100644 --- a/shared/serialize.h +++ b/shared/serialize.h @@ -3,7 +3,7 @@ // * GNU General Public License: http://www.gnu.org/licenses/gpl.html * // * Copyright (C) 2008-2011 ZenJu (zhnmju123 AT gmx.de) * // ************************************************************************** -// + #ifndef SERIALIZE_H_INCLUDED #define SERIALIZE_H_INCLUDED diff --git a/shared/shadow.cpp b/shared/shadow.cpp index 948050b6..f000a69b 100644 --- a/shared/shadow.cpp +++ b/shared/shadow.cpp @@ -3,7 +3,7 @@ // * GNU General Public License: http://www.gnu.org/licenses/gpl.html * // * Copyright (C) 2008-2011 ZenJu (zhnmju123 AT gmx.de) * // ************************************************************************** -// + #include "shadow.h" #include <wx/msw/wrapwin.h> //includes "windows.h" #include "i18n.h" @@ -14,8 +14,8 @@ #include "ShadowCopy\shadow.h" #include "Loki/ScopeGuard.h" -using shadow::ShadowCopy; using namespace zen; +using namespace shadow; namespace @@ -23,7 +23,6 @@ namespace bool newerThanXP() { OSVERSIONINFO osvi = {}; - ZeroMemory(&osvi, sizeof(OSVERSIONINFO)); osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFO); if (::GetVersionEx(&osvi)) @@ -43,7 +42,7 @@ bool runningWOW64() //test if process is running under WOW64 (reference http://m HANDLE hProcess, PBOOL Wow64Process); - static const IsWow64ProcessFun isWow64Process = + const IsWow64ProcessFun isWow64Process = util::getDllFun<IsWow64ProcessFun>(L"kernel32.dll", "IsWow64Process"); if (isWow64Process) @@ -87,13 +86,8 @@ public: ShadowVolume(const Zstring& volumeNameFormatted) : //throw(FileError) backupHandle(0) { - using namespace shadow; - - if (!createShadowCopy) - createShadowCopy = util::getDllFun<CreateShadowCopyFct>(getShadowDllName(), createShadowCopyFctName); - - if (!releaseShadowCopy) - releaseShadowCopy = util::getDllFun<ReleaseShadowCopyFct>(getShadowDllName(), releaseShadowCopyFctName); + createShadowCopy = util::getDllFun<CreateShadowCopyFct>(getShadowDllName(), createShadowCopyFctName); + releaseShadowCopy = util::getDllFun<ReleaseShadowCopyFct>(getShadowDllName(), releaseShadowCopyFctName); //check if shadow copy dll was loaded correctly if (createShadowCopy == NULL || @@ -103,8 +97,7 @@ public: //VSS does not support running under WOW64 except for Windows XP and Windows Server 2003 //(Reference: http://msdn.microsoft.com/en-us/library/aa384627(VS.85).aspx) - static const bool wow64Active = runningWOW64(); - if (wow64Active) + if (runningWOW64()) throw FileError(_("Error starting Volume Shadow Copy Service!") + "\n" + _("Making shadow copies on WOW64 is not supported. Please use FreeFileSync 64-bit version.")); @@ -140,24 +133,18 @@ private: ShadowVolume(const ShadowVolume&); ShadowVolume& operator=(const ShadowVolume&); - static shadow::CreateShadowCopyFct createShadowCopy; - static shadow::ReleaseShadowCopyFct releaseShadowCopy; + shadow::CreateShadowCopyFct createShadowCopy; + shadow::ReleaseShadowCopyFct releaseShadowCopy; Zstring shadowVol; ShadowHandle backupHandle; }; - - -shadow::CreateShadowCopyFct ShadowCopy::ShadowVolume::createShadowCopy; -shadow::ReleaseShadowCopyFct ShadowCopy::ShadowVolume::releaseShadowCopy; //############################################################################################################# Zstring ShadowCopy::makeShadowCopy(const Zstring& inputFile) { - using namespace zen; - wchar_t volumeNameRaw[1000]; if (!::GetVolumePathName(inputFile.c_str(), //__in LPCTSTR lpszFileName, diff --git a/shared/shadow.h b/shared/shadow.h index edea4377..aff5b437 100644 --- a/shared/shadow.h +++ b/shared/shadow.h @@ -3,7 +3,7 @@ // * GNU General Public License: http://www.gnu.org/licenses/gpl.html * // * Copyright (C) 2008-2011 ZenJu (zhnmju123 AT gmx.de) * // ************************************************************************** -// + #ifndef SHADOW_H_INCLUDED #define SHADOW_H_INCLUDED diff --git a/shared/shell_execute.h b/shared/shell_execute.h index 2cabbed1..64797eff 100644 --- a/shared/shell_execute.h +++ b/shared/shell_execute.h @@ -3,20 +3,20 @@ // * GNU General Public License: http://www.gnu.org/licenses/gpl.html * // * Copyright (C) 2008-2011 ZenJu (zhnmju123 AT gmx.de) * // ************************************************************************** -// + #ifndef EXECUTE_HEADER_23482134578134134 #define EXECUTE_HEADER_23482134578134134 -#include <wx/string.h> #include <wx/msgdlg.h> #ifdef FFS_WIN -#include "string_tools.h" #include "last_error.h" +#include "string_tools.h" #include "i18n.h" #include <wx/msw/wrapwin.h> //includes "windows.h" #elif defined FFS_LINUX +#include <stdlib.h> #include <wx/utils.h> #endif @@ -69,7 +69,7 @@ void shellExecute(const wxString& command, ExecutionType type = EXEC_TYPE_ASYNC) if (!::ShellExecuteEx(&execInfo)) //__inout LPSHELLEXECUTEINFO lpExecInfo { - wxString errorMsg = _("Invalid commandline: \"%x\""); + wxString errorMsg = _("Invalid commandline: %x"); wxString cmdFmt = wxString(L"\nFile: ") + filename + L"\nArg: " + arguments; errorMsg.Replace(L"%x", cmdFmt); @@ -87,10 +87,26 @@ void shellExecute(const wxString& command, ExecutionType type = EXEC_TYPE_ASYNC) } #elif defined FFS_LINUX - //by default wxExecute uses a zero sized dummy window as a hack to keep focus which leaves a useless empty icon in ALT-TAB list - //=> use wxEXEC_NODISABLE and roll our own window disabler! (see comment in app.cpp: void *wxGUIAppTraits::BeforeChildWaitLoop()) - wxWindowDisabler dummy; //disables all top level windows - wxExecute(command, (type == EXEC_TYPE_ASYNC ? wxEXEC_ASYNC : wxEXEC_SYNC) | wxEXEC_NODISABLE); + if (type == EXEC_TYPE_SYNC) + { + int rv = ::system(utf8CvrtTo<std::string>(command).c_str()); //do NOT use std::system as its documentation says nothing about "WEXITSTATUS(rv)", ect... + if (rv == -1 || WEXITSTATUS(rv) == 127) //http://linux.die.net/man/3/system "In case /bin/sh could not be executed, the exit status will be that of a command that does exit(127)" + { + wxString errorMsg = _("Invalid commandline: %x"); + replace(errorMsg, L"%x", L"\n" + command); + wxMessageBox(errorMsg); + return; + } + } + else + { + // ! unfortunately it seems there is no way on Linux to get a failure notification for calling an invalid commandline asynchronously ! + + //by default wxExecute uses a zero sized dummy window as a hack to keep focus which leaves a useless empty icon in ALT-TAB list + //=> use wxEXEC_NODISABLE and roll our own window disabler! (see comment in app.cpp: void *wxGUIAppTraits::BeforeChildWaitLoop()) + wxWindowDisabler dummy; //disables all top level windows + wxExecute(command, wxEXEC_ASYNC | wxEXEC_NODISABLE); + } #endif } } diff --git a/shared/standard_paths.cpp b/shared/standard_paths.cpp index 928dedcc..c2d79516 100644 --- a/shared/standard_paths.cpp +++ b/shared/standard_paths.cpp @@ -3,7 +3,7 @@ // * GNU General Public License: http://www.gnu.org/licenses/gpl.html * // * Copyright (C) 2008-2011 ZenJu (zhnmju123 AT gmx.de) * // ************************************************************************** -// + #include "standard_paths.h" #include <wx/stdpaths.h> #include "string_conv.h" diff --git a/shared/standard_paths.h b/shared/standard_paths.h index faafe263..708a377d 100644 --- a/shared/standard_paths.h +++ b/shared/standard_paths.h @@ -3,7 +3,7 @@ // * GNU General Public License: http://www.gnu.org/licenses/gpl.html * // * Copyright (C) 2008-2011 ZenJu (zhnmju123 AT gmx.de) * // ************************************************************************** -// + #ifndef STANDARDPATHS_H_INCLUDED #define STANDARDPATHS_H_INCLUDED diff --git a/shared/string_conv.h b/shared/string_conv.h index 477dda8c..976080fb 100644 --- a/shared/string_conv.h +++ b/shared/string_conv.h @@ -3,7 +3,7 @@ // * GNU General Public License: http://www.gnu.org/licenses/gpl.html * // * Copyright (C) 2008-2011 ZenJu (zhnmju123 AT gmx.de) * // ************************************************************************** -// + #ifndef STRINGCONV_H_INCLUDED #define STRINGCONV_H_INCLUDED diff --git a/shared/symlink_target.h b/shared/symlink_target.h index e3a75f81..ef7b2275 100644 --- a/shared/symlink_target.h +++ b/shared/symlink_target.h @@ -3,7 +3,7 @@ // * GNU General Public License: http://www.gnu.org/licenses/gpl.html * // * Copyright (C) 2008-2011 ZenJu (zhnmju123 AT gmx.de) * // ************************************************************************** -// + #ifndef SYMLINK_WIN_H_INCLUDED #define SYMLINK_WIN_H_INCLUDED diff --git a/shared/taskbar.cpp b/shared/taskbar.cpp index 969f4bb0..005df705 100644 --- a/shared/taskbar.cpp +++ b/shared/taskbar.cpp @@ -5,16 +5,24 @@ // ************************************************************************** // #include "taskbar.h" + +#ifdef FFS_WIN #include "Taskbar_Seven/taskbar.h" #include "dll_loader.h" #include "build_info.h" #include "assert_static.h" #include <wx/msw/wrapwin.h> //includes "windows.h" +#elif defined HAVE_UBUNTU_UNITY +#include <unity/unity/unity.h> +#endif + using namespace util; -using namespace tbseven; +#ifdef FFS_WIN +using namespace tbseven; + namespace { bool windows7TaskbarAvailable() @@ -45,7 +53,7 @@ std::wstring getTaskBarDllName() //######################################################################################################## -class TaskbarProgress::Pimpl //throw (TaskbarNotAvailable) +class Taskbar::Pimpl //throw (TaskbarNotAvailable) { public: Pimpl(const wxTopLevelWindow& window) : @@ -60,29 +68,26 @@ public: throw TaskbarNotAvailable(); } - ~Pimpl() - { - setStatus(STATUS_NOPROGRESS); - } + ~Pimpl() { setStatus(STATUS_NOPROGRESS); } void setStatus(Status status) { TaskBarStatus tbSevenStatus = tbseven::STATUS_NORMAL; switch (status) { - case TaskbarProgress::STATUS_NOPROGRESS: + case Taskbar::STATUS_NOPROGRESS: tbSevenStatus = tbseven::STATUS_NOPROGRESS; break; - case TaskbarProgress::STATUS_INDETERMINATE: + case Taskbar::STATUS_INDETERMINATE: tbSevenStatus = tbseven::STATUS_INDETERMINATE; break; - case TaskbarProgress::STATUS_NORMAL: + case Taskbar::STATUS_NORMAL: tbSevenStatus = tbseven::STATUS_NORMAL; break; - case TaskbarProgress::STATUS_ERROR: + case Taskbar::STATUS_ERROR: tbSevenStatus = tbseven::STATUS_ERROR; break; - case TaskbarProgress::STATUS_PAUSED: + case Taskbar::STATUS_PAUSED: tbSevenStatus = tbseven::STATUS_PAUSED; break; } @@ -96,23 +101,80 @@ public: } private: - void* assocWindow; + void* assocWindow; //HWND const SetStatusFct setStatus_; const SetProgressFct setProgress_; }; -//######################################################################################################## +#elif defined HAVE_UBUNTU_UNITY //Ubuntu unity +namespace +{ +const char FFS_DESKTOP_FILE[] = "freefilesync.desktop"; +} -TaskbarProgress::TaskbarProgress(const wxTopLevelWindow& window) : pimpl_(new Pimpl(window)) {} +class Taskbar::Pimpl //throw (TaskbarNotAvailable) +{ +public: + Pimpl(const wxTopLevelWindow& window) : + tbEntry(unity_launcher_entry_get_for_desktop_id(FFS_DESKTOP_FILE)) + //tbEntry(unity_launcher_entry_get_for_app_uri("application://freefilesync.desktop")) + { + if (!tbEntry) + throw TaskbarNotAvailable(); + } -TaskbarProgress::~TaskbarProgress() {} //std::unique_ptr ... + ~Pimpl() { setStatus(STATUS_NOPROGRESS); } //it seems UnityLauncherEntry* does not need destruction -void TaskbarProgress::setStatus(Status status) -{ - pimpl_->setStatus(status); -} + void setStatus(Status status) + { + switch (status) + { + case Taskbar::STATUS_ERROR: + unity_launcher_entry_set_urgent(tbEntry, true); + break; -void TaskbarProgress::setProgress(size_t current, size_t total) + case Taskbar::STATUS_NOPROGRESS: + case Taskbar::STATUS_INDETERMINATE: + unity_launcher_entry_set_urgent(tbEntry, false); + unity_launcher_entry_set_progress_visible(tbEntry, false); + break; + + case Taskbar::STATUS_NORMAL: + unity_launcher_entry_set_urgent(tbEntry, false); + unity_launcher_entry_set_progress_visible(tbEntry, true); + break; + + case Taskbar::STATUS_PAUSED: + unity_launcher_entry_set_urgent (tbEntry, false); + break; + } + } + + void setProgress(size_t current, size_t total) + { + unity_launcher_entry_set_progress(tbEntry, total == 0 ? 0 : double(current) / total); + } + +private: + UnityLauncherEntry* tbEntry; +}; + + +#else //no taskbar support yet +class Taskbar::Pimpl { - pimpl_->setProgress(current, total); -} +public: + Pimpl(const wxTopLevelWindow& window) { throw TaskbarNotAvailable(); } + void setStatus(Status status) {} + void setProgress(size_t current, size_t total) {} + +}; +#endif + + +//######################################################################################################## +Taskbar::Taskbar(const wxTopLevelWindow& window) : pimpl_(new Pimpl(window)) {} //throw TaskbarNotAvailable +Taskbar::~Taskbar() {} //std::unique_ptr ... + +void Taskbar::setStatus(Status status) { pimpl_->setStatus(status); } +void Taskbar::setProgress(size_t current, size_t total) { pimpl_->setProgress(current, total); } diff --git a/shared/taskbar.h b/shared/taskbar.h index 90a76d13..54e0a431 100644 --- a/shared/taskbar.h +++ b/shared/taskbar.h @@ -3,28 +3,32 @@ // * GNU General Public License: http://www.gnu.org/licenses/gpl.html * // * Copyright (C) 2008-2011 ZenJu (zhnmju123 AT gmx.de) * // ************************************************************************** -// + #ifndef TASKBARPROGRESS_H_INCLUDED #define TASKBARPROGRESS_H_INCLUDED -#ifndef FFS_WIN -use in windows build only! -#endif - #include <wx/toplevel.h> #include <memory> +/* +Windows 7; show progress in windows superbar via ITaskbarList3 Interface (http://msdn.microsoft.com/en-us/library/dd391692(VS.85).aspx) + +Ubuntu: use Unity interface (optional) + +Define HAVE_UBUNTU_UNITY and set: + Compiler flag: `pkg-config --cflags unity` + Linker flag: `pkg-config --libs unity` +*/ namespace util { class TaskbarNotAvailable {}; -//show progress in windows superbar via ITaskbarList3 Interface (http://msdn.microsoft.com/en-us/library/dd391692(VS.85).aspx) -class TaskbarProgress +class Taskbar { public: - TaskbarProgress(const wxTopLevelWindow& window); //throw TaskbarNotAvailable() - ~TaskbarProgress(); + Taskbar(const wxTopLevelWindow& window); //throw TaskbarNotAvailable() + ~Taskbar(); enum Status { diff --git a/shared/toggle_button.cpp b/shared/toggle_button.cpp index 511822b1..24f74bc7 100644 --- a/shared/toggle_button.cpp +++ b/shared/toggle_button.cpp @@ -3,7 +3,7 @@ // * GNU General Public License: http://www.gnu.org/licenses/gpl.html * // * Copyright (C) 2008-2011 ZenJu (zhnmju123 AT gmx.de) * // ************************************************************************** -// + #include "toggle_button.h" void ToggleButton::init(const wxBitmap& activeBmp, diff --git a/shared/toggle_button.h b/shared/toggle_button.h index 6613fdd4..f333ca24 100644 --- a/shared/toggle_button.h +++ b/shared/toggle_button.h @@ -3,7 +3,7 @@ // * GNU General Public License: http://www.gnu.org/licenses/gpl.html * // * Copyright (C) 2008-2011 ZenJu (zhnmju123 AT gmx.de) * // ************************************************************************** -// + #ifndef TOGGLEBUTTON_H_INCLUDED #define TOGGLEBUTTON_H_INCLUDED diff --git a/shared/util.cpp b/shared/util.cpp index faa4074c..d780d683 100644 --- a/shared/util.cpp +++ b/shared/util.cpp @@ -3,7 +3,7 @@ // * GNU General Public License: http://www.gnu.org/licenses/gpl.html * // * Copyright (C) 2008-2011 ZenJu (zhnmju123 AT gmx.de) * // ************************************************************************** -// + #include "util.h" #include "zstring.h" #include "i18n.h" diff --git a/shared/util.h b/shared/util.h index 25762ce7..0e08280e 100644 --- a/shared/util.h +++ b/shared/util.h @@ -3,7 +3,7 @@ // * GNU General Public License: http://www.gnu.org/licenses/gpl.html * // * Copyright (C) 2008-2011 ZenJu (zhnmju123 AT gmx.de) * // ************************************************************************** -// + #ifndef UTIL_H_INCLUDED #define UTIL_H_INCLUDED diff --git a/shared/warn_static.h b/shared/warn_static.h new file mode 100644 index 00000000..bb4f4a6f --- /dev/null +++ b/shared/warn_static.h @@ -0,0 +1,35 @@ +// ************************************************************************** +// * This file is part of the zenXML project. It is distributed under the * +// * Boost Software License, Version 1.0. See accompanying file * +// * LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt. * +// * Copyright (C) 2011 ZenJu (zhnmju123 AT gmx.de) * +// ************************************************************************** + +#ifndef WARN_STATIC_HEADER_08724567834560832745 +#define WARN_STATIC_HEADER_08724567834560832745 + +/* +Portable Compile-Time Warning +----------------------------- +Usage: + warn_static("my message") +*/ + +#ifdef _MSC_VER +#define MAKE_STRING_SUB(NUM) #NUM +#define MAKE_STRING(NUM) MAKE_STRING_SUB(NUM) + +#define warn_static(TXT) \ +__pragma(message (__FILE__ "(" MAKE_STRING(__LINE__) "): Warning: " ## TXT)) + +#elif defined __GNUC__ +#define LOKI_CONCAT( X, Y ) LOKI_CONCAT_SUB( X, Y ) +#define LOKI_CONCAT_SUB( X, Y ) X##Y + +#define warn_static(TXT) \ +typedef int STATIC_WARNING __attribute__ ((deprecated)); \ +enum { LOKI_CONCAT(warn_static_dummy_value, __LINE__) = sizeof(STATIC_WARNING) }; +#endif + + +#endif //WARN_STATIC_HEADER_08724567834560832745
\ No newline at end of file diff --git a/shared/wx_choice_enum.h b/shared/wx_choice_enum.h index 9f832394..e8fbeead 100644 --- a/shared/wx_choice_enum.h +++ b/shared/wx_choice_enum.h @@ -3,7 +3,7 @@ // * GNU General Public License: http://www.gnu.org/licenses/gpl.html * // * Copyright (C) 2008-2011 ZenJu (zhnmju123 AT gmx.de) * // ************************************************************************** -// + #ifndef WX_CHOICE_ENUM_H_INCLUDED #define WX_CHOICE_ENUM_H_INCLUDED diff --git a/shared/wx_timespan.h b/shared/wx_timespan.h index 108327bf..2e566927 100644 --- a/shared/wx_timespan.h +++ b/shared/wx_timespan.h @@ -3,7 +3,7 @@ // * GNU General Public License: http://www.gnu.org/licenses/gpl.html * // * Copyright (C) 2008-2011 ZenJu (zhnmju123 AT gmx.de) * // ************************************************************************** -// + #ifndef WX_TIMESPAN_CTRL_HEADER_INCLUDED #define WX_TIMESPAN_CTRL_HEADER_INCLUDED diff --git a/shared/xml_base.cpp b/shared/xml_base.cpp index cd9f58a6..c7c92401 100644 --- a/shared/xml_base.cpp +++ b/shared/xml_base.cpp @@ -3,7 +3,7 @@ // * GNU General Public License: http://www.gnu.org/licenses/gpl.html * // * Copyright (C) 2008-2011 ZenJu (zhnmju123 AT gmx.de) * // ************************************************************************** -// + #include "xml_base.h" #include <file_handling.h> #include <string_conv.h> @@ -13,12 +13,14 @@ using namespace zen; +//loadXmlDocument vs loadStream: +//1. better error reporting +//2. quick exit if (potentially large) input file is not an XML void xmlAccess::loadXmlDocument(const wxString& filename, XmlDoc& doc) //throw FfsXmlError() { std::string stream; try { - const zen::UInt64 fs = zen::getFilesize(toZ(filename)); //throw (FileError) { //quick test whether input is an XML: avoid loading large binary files up front! //doesn't correctly handle BOM! (but no issue yet...) @@ -31,6 +33,7 @@ void xmlAccess::loadXmlDocument(const wxString& filename, XmlDoc& doc) //throw F throw FfsXmlError(wxString(_("Error parsing configuration file:")) + wxT("\n\"") + filename + wxT("\"")); } + const zen::UInt64 fs = zen::getFilesize(toZ(filename)); //throw (FileError) stream.resize(to<size_t>(fs)); FileInput inputFile(toZ(filename)); //throw (FileError); diff --git a/shared/xml_base.h b/shared/xml_base.h index 6a47fcf2..37d79863 100644 --- a/shared/xml_base.h +++ b/shared/xml_base.h @@ -3,7 +3,7 @@ // * GNU General Public License: http://www.gnu.org/licenses/gpl.html * // * Copyright (C) 2008-2011 ZenJu (zhnmju123 AT gmx.de) * // ************************************************************************** -// + #ifndef XMLBASE_H_INCLUDED #define XMLBASE_H_INCLUDED diff --git a/shared/xml_error.h b/shared/xml_error.h index ffd6af8b..6e17670a 100644 --- a/shared/xml_error.h +++ b/shared/xml_error.h @@ -3,7 +3,7 @@ // * GNU General Public License: http://www.gnu.org/licenses/gpl.html * // * Copyright (C) 2008-2011 ZenJu (zhnmju123 AT gmx.de) * // ************************************************************************** -// + #ifndef XMLERROR_H_INCLUDED #define XMLERROR_H_INCLUDED diff --git a/shared/zbase.h b/shared/zbase.h index 6d9ac578..55bc0d96 100644 --- a/shared/zbase.h +++ b/shared/zbase.h @@ -3,7 +3,7 @@ // * GNU General Public License: http://www.gnu.org/licenses/gpl.html * // * Copyright (C) 2008-2011 ZenJu (zhnmju123 AT gmx.de) * // ************************************************************************** -// + #ifndef Z_BASE_H_INCLUDED #define Z_BASE_H_INCLUDED @@ -12,6 +12,7 @@ #include <sstream> #include <algorithm> #include <string_tools.h> +#include <boost/detail/atomic_count.hpp> /* Allocator Policy: @@ -101,24 +102,17 @@ private: size_t capacity; //allocated size without null-termination }; - static Descriptor* descr(T* ptr) - { - return reinterpret_cast<Descriptor*>(ptr) - 1; - } - - static const Descriptor* descr(const T* ptr) - { - return reinterpret_cast<const Descriptor*>(ptr) - 1; - } + static Descriptor* descr( T* ptr) { return reinterpret_cast< Descriptor*>(ptr) - 1; } + static const Descriptor* descr(const T* ptr) { return reinterpret_cast<const Descriptor*>(ptr) - 1; } }; template <typename T, //Character Type class AP> //Allocator Policy -class StorageRefCount : public AP +class StorageRefCountThreadSafe : public AP { protected: - ~StorageRefCount() {} + ~StorageRefCountThreadSafe() {} static T* create(size_t size) { @@ -132,10 +126,7 @@ protected: assert(minCapacity >= size); Descriptor* const newDescr = static_cast<Descriptor*>(AP::allocate(sizeof(Descriptor) + (newCapacity + 1) * sizeof(T))); - - newDescr->refCount = 1; - newDescr->length = size; - newDescr->capacity = newCapacity; + new (newDescr) Descriptor(1, size, newCapacity); return reinterpret_cast<T*>(newDescr + 1); } @@ -150,7 +141,10 @@ protected: static void destroy(T* ptr) { if (--descr(ptr)->refCount == 0) + { + descr(ptr)->~Descriptor(); AP::deallocate(descr(ptr)); + } } static bool canWrite(const T* ptr, size_t minCapacity) //needs to be checked before writing to "ptr" @@ -173,26 +167,23 @@ protected: private: struct Descriptor { - size_t refCount; + Descriptor(long rc, size_t len, size_t cap) : refCount(rc), length(len), capacity(cap) {} + + boost::detail::atomic_count refCount; //practically no perf loss: ~0.2%! (FFS comparison) size_t length; size_t capacity; //allocated size without null-termination }; - static Descriptor* descr(T* ptr) - { - return reinterpret_cast<Descriptor*>(ptr) - 1; - } - - static const Descriptor* descr(const T* ptr) - { - return reinterpret_cast<const Descriptor*>(ptr) - 1; - } + static Descriptor* descr( T* ptr) { return reinterpret_cast< Descriptor*>(ptr) - 1; } + static const Descriptor* descr(const T* ptr) { return reinterpret_cast<const Descriptor*>(ptr) - 1; } }; -template <class T, //Character Type - template <class, class> class SP = StorageRefCount, //Storage Policy - class AP = AllocatorOptimalSpeed> //Allocator Policy +//perf note: interstingly StorageDeepCopy and StorageRefCountThreadSafe show same performance in FFS comparison + +template <class T, //Character Type + template <class, class> class SP = StorageRefCountThreadSafe, //Storage Policy + class AP = AllocatorOptimalSpeed> //Allocator Policy class Zbase : public SP<T, AP> { public: @@ -200,6 +191,7 @@ public: Zbase(const T* source); //implicit conversion from a C-string Zbase(const T* source, size_t length); Zbase(const Zbase& source); + Zbase(Zbase&& tmp); explicit Zbase(T source); //dangerous if implicit: T buffer[]; Zbase name = buffer; ups... //allow explicit construction from different string type, prevent ambiguity via SFINAE template <class S> explicit Zbase(const S& other, typename S::value_type = 0); @@ -261,6 +253,7 @@ public: void push_back(T val); //STL access Zbase& operator=(const Zbase& source); + Zbase& operator=(Zbase&& tmp); Zbase& operator=(const T* source); Zbase& operator=(T source); Zbase& operator+=(const Zbase& other); @@ -380,6 +373,14 @@ Zbase<T, SP, AP>::Zbase(const Zbase<T, SP, AP>& source) template <class T, template <class, class> class SP, class AP> +inline +Zbase<T, SP, AP>::Zbase(Zbase<T, SP, AP>&& tmp) +{ + rawStr = this->clone(tmp.rawStr); //for a ref-counting string there probably isn't a faster way, even with r-value references +} + + +template <class T, template <class, class> class SP, class AP> template <class S> inline Zbase<T, SP, AP>::Zbase(const S& other, typename S::value_type) @@ -827,6 +828,15 @@ Zbase<T, SP, AP>& Zbase<T, SP, AP>::operator=(const Zbase<T, SP, AP>& source) template <class T, template <class, class> class SP, class AP> inline +Zbase<T, SP, AP>& Zbase<T, SP, AP>::operator=(Zbase<T, SP, AP>&& tmp) +{ + swap(tmp); + return *this; +} + + +template <class T, template <class, class> class SP, class AP> +inline Zbase<T, SP, AP>& Zbase<T, SP, AP>::operator=(const T* source) { return assign(source, zen::cStringLength(source)); diff --git a/shared/zstring.cpp b/shared/zstring.cpp index 2955ec3e..e1df17ee 100644 --- a/shared/zstring.cpp +++ b/shared/zstring.cpp @@ -3,9 +3,10 @@ // * GNU General Public License: http://www.gnu.org/licenses/gpl.html * // * Copyright (C) 2008-2011 ZenJu (zhnmju123 AT gmx.de) * // ************************************************************************** -// + #include "zstring.h" #include <stdexcept> +#include <boost/thread/once.hpp> #ifdef FFS_WIN #include <wx/msw/wrapwin.h> //includes "windows.h" @@ -52,6 +53,12 @@ LeakChecker& LeakChecker::instance() return inst; } +//caveat: function scope static initialization is not thread-safe in VS 2010! => make sure to call at app start! +namespace +{ +struct Dummy { Dummy() { LeakChecker::instance(); }} blah; +} + std::string LeakChecker::rawMemToString(const void* ptr, size_t size) { @@ -113,7 +120,10 @@ int z_impl::compareFilenamesWin(const wchar_t* a, const wchar_t* b, size_t sizeA LPCWSTR lpString2, int cchCount2, BOOL bIgnoreCase); - static const CompareStringOrdinalFunc ordinalCompare = util::getDllFun<CompareStringOrdinalFunc>(L"kernel32.dll", "CompareStringOrdinal"); + static CompareStringOrdinalFunc ordinalCompare = NULL; //caveat: function scope static initialization is not thread-safe in VS 2010! + static boost::once_flag once = BOOST_ONCE_INIT; + boost::call_once(once, []() { ordinalCompare = util::getDllFun<CompareStringOrdinalFunc>(L"kernel32.dll", "CompareStringOrdinal"); }); + if (ordinalCompare != NULL) //this additional test has no noticeable performance impact { diff --git a/shared/zstring.h b/shared/zstring.h index 841fb8a2..3b4837db 100644 --- a/shared/zstring.h +++ b/shared/zstring.h @@ -3,7 +3,7 @@ // * GNU General Public License: http://www.gnu.org/licenses/gpl.html * // * Copyright (C) 2008-2011 ZenJu (zhnmju123 AT gmx.de) * // ************************************************************************** -// + #ifndef ZSTRING_H_INCLUDED #define ZSTRING_H_INCLUDED @@ -11,8 +11,8 @@ #include <cstring> //strcmp() #ifndef NDEBUG +#include "boost_thread_wrap.h" //include <boost/thread.hpp> #include <map> -#include <wx/thread.h> #endif @@ -22,7 +22,7 @@ class LeakChecker //small test for memory leaks public: void insert(const void* ptr, size_t size) { - wxCriticalSectionLocker dummy(lockActStrings); + boost::lock_guard<boost::mutex> dummy(lockActStrings); if (activeStrings.find(ptr) != activeStrings.end()) reportProblem(std::string("Fatal Error: New memory points into occupied space: ") + rawMemToString(ptr, size)); @@ -31,8 +31,7 @@ public: void remove(const void* ptr) { - wxCriticalSectionLocker dummy(lockActStrings); - + boost::lock_guard<boost::mutex> dummy(lockActStrings); if (activeStrings.find(ptr) == activeStrings.end()) reportProblem(std::string("Fatal Error: No memory available for deallocation at this location!")); @@ -50,7 +49,7 @@ private: static std::string rawMemToString(const void* ptr, size_t size); void reportProblem(const std::string& message); //throw (std::logic_error) - wxCriticalSection lockActStrings; + boost::mutex lockActStrings; typedef std::map<const void*, size_t> VoidPtrSizeMap; VoidPtrSizeMap activeStrings; }; @@ -106,7 +105,6 @@ template <template <class, class> class SP, class AP> void MakeUpper(Zbase<wchar_t, SP, AP>& str); #endif - #ifdef FFS_WIN //Windows stores filenames in wide character format typedef wchar_t Zchar; #define Zstr(x) L ## x @@ -121,8 +119,8 @@ const Zchar FILE_NAME_SEPARATOR = '/'; #error define platform you are in: FFS_WIN or FFS_LINUX #endif -//"The reason for all the fuss above" (Loki/SmartPtr) -typedef Zbase<Zchar, StorageRefCount, AllocatorFreeStoreChecked> Zstring; //for use with file names +//"The reason for all the fuss above" - Loki/SmartPtr +typedef Zbase<Zchar, StorageRefCountThreadSafe, AllocatorFreeStoreChecked> Zstring; //for use with file names |