diff options
Diffstat (limited to 'RealtimeSync')
-rw-r--r-- | RealtimeSync/RealtimeSync.cbp | 10 | ||||
-rw-r--r-- | RealtimeSync/RealtimeSync.vcxproj | 6 | ||||
-rw-r--r-- | RealtimeSync/application.cpp | 2 | ||||
-rw-r--r-- | RealtimeSync/main_dlg.cpp | 1 | ||||
-rw-r--r-- | RealtimeSync/makefile | 3 | ||||
-rw-r--r-- | RealtimeSync/notify.cpp | 274 | ||||
-rw-r--r-- | RealtimeSync/notify.h | 40 | ||||
-rw-r--r-- | RealtimeSync/resources.cpp | 1 | ||||
-rw-r--r-- | RealtimeSync/tray_menu.cpp | 12 | ||||
-rw-r--r-- | RealtimeSync/watcher.cpp | 334 | ||||
-rw-r--r-- | RealtimeSync/watcher.h | 2 | ||||
-rw-r--r-- | RealtimeSync/xml_ffs.cpp | 41 | ||||
-rw-r--r-- | RealtimeSync/xml_proc.cpp | 2 |
13 files changed, 80 insertions, 648 deletions
diff --git a/RealtimeSync/RealtimeSync.cbp b/RealtimeSync/RealtimeSync.cbp index 9e81c8ea..867b898c 100644 --- a/RealtimeSync/RealtimeSync.cbp +++ b/RealtimeSync/RealtimeSync.cbp @@ -27,7 +27,7 @@ <Add library="libwxbase28u.a" /> <Add library="libwxpng.a" /> <Add library="libwxzlib.a" /> - <Add library="libboost_thread-mgw45-mt-s-1_46_1.a" /> + <Add library="libboost_thread-mgw45-mt-s-1_47.a" /> <Add directory="C:\Programme\C++\wxWidgets\lib\gcc_lib" /> </Linker> </Target> @@ -51,7 +51,7 @@ <Add library="libwxbase28ud.a" /> <Add library="libwxpngd.a" /> <Add library="libwxzlibd.a" /> - <Add library="libboost_thread-mgw45-mt-sd-1_46_1.a" /> + <Add library="libboost_thread-mgw45-mt-sd-1_47.a" /> <Add directory="C:\Program Files\C++\wxWidgets\lib\gcc_dll" /> </Linker> </Target> @@ -101,7 +101,6 @@ <Unit filename="gui_generated.h" /> <Unit filename="main_dlg.cpp" /> <Unit filename="main_dlg.h" /> - <Unit filename="notify.cpp" /> <Unit filename="notify.h" /> <Unit filename="resource.rc"> <Option compilerVar="WINDRES" /> @@ -124,6 +123,8 @@ <Unit filename="..\Shared\zstring.h" /> <Unit filename="..\library\process_xml.cpp" /> <Unit filename="..\shared\check_exist.cpp" /> + <Unit filename="..\shared\dir_watcher.cpp" /> + <Unit filename="..\shared\dir_watcher.h" /> <Unit filename="..\shared\dll_loader.cpp" /> <Unit filename="..\shared\dll_loader.h" /> <Unit filename="..\shared\dst_hack.cpp" /> @@ -134,7 +135,6 @@ <Unit filename="..\shared\file_id.cpp" /> <Unit filename="..\shared\file_io.cpp" /> <Unit filename="..\shared\file_traverser.cpp" /> - <Unit filename="..\shared\global_func.cpp" /> <Unit filename="..\shared\global_func.h" /> <Unit filename="..\shared\help_provider.cpp" /> <Unit filename="..\shared\i18n.cpp" /> @@ -144,6 +144,8 @@ <Unit filename="..\shared\localization.cpp" /> <Unit filename="..\shared\long_path_prefix.h" /> <Unit filename="..\shared\mouse_move_dlg.cpp" /> + <Unit filename="..\shared\notify_removal.cpp" /> + <Unit filename="..\shared\notify_removal.h" /> <Unit filename="..\shared\pch.h"> <Option compile="1" /> <Option weight="0" /> diff --git a/RealtimeSync/RealtimeSync.vcxproj b/RealtimeSync/RealtimeSync.vcxproj index 12d36822..cdeb18b4 100644 --- a/RealtimeSync/RealtimeSync.vcxproj +++ b/RealtimeSync/RealtimeSync.vcxproj @@ -199,7 +199,7 @@ <PreprocessorDefinitions>ZEN_PLATFORM_WINDOWS;wxUSE_UNICODE;__WXMSW__;FFS_WIN;WXINTL_NO_GETTEXT_MACRO;NDEBUG</PreprocessorDefinitions> <AdditionalIncludeDirectories>..\shared;C:\Program Files\C++\wxWidgets-x64\include;C:\Program Files\C++\wxWidgets-x64\lib\vc_lib\mswu;C:\Program Files\C++\Boost</AdditionalIncludeDirectories> <FavorSizeOrSpeed>Speed</FavorSizeOrSpeed> - <DisableSpecificWarnings>4100;4996</DisableSpecificWarnings> + <DisableSpecificWarnings>4512;4996;4100;4127</DisableSpecificWarnings> <RuntimeLibrary>MultiThreaded</RuntimeLibrary> <MultiProcessorCompilation>true</MultiProcessorCompilation> <DisableLanguageExtensions>false</DisableLanguageExtensions> @@ -228,17 +228,18 @@ <ClCompile Include="..\library\process_xml.cpp" /> <ClCompile Include="..\shared\check_exist.cpp" /> <ClCompile Include="..\shared\custom_button.cpp" /> + <ClCompile Include="..\shared\dir_watcher.cpp" /> <ClCompile Include="..\shared\dll_loader.cpp" /> <ClCompile Include="..\shared\dir_name.cpp" /> <ClCompile Include="..\shared\dst_hack.cpp" /> <ClCompile Include="..\shared\file_handling.cpp" /> <ClCompile Include="..\shared\file_io.cpp" /> <ClCompile Include="..\shared\file_traverser.cpp" /> - <ClCompile Include="..\shared\global_func.cpp" /> <ClCompile Include="..\shared\help_provider.cpp" /> <ClCompile Include="..\shared\i18n.cpp" /> <ClCompile Include="..\shared\localization.cpp" /> <ClCompile Include="..\shared\mouse_move_dlg.cpp" /> + <ClCompile Include="..\shared\notify_removal.cpp" /> <ClCompile Include="..\shared\privilege.cpp" /> <ClCompile Include="..\shared\resolve_path.cpp" /> <ClCompile Include="..\shared\standard_paths.cpp" /> @@ -254,7 +255,6 @@ </ClCompile> <ClCompile Include="gui_generated.cpp" /> <ClCompile Include="main_dlg.cpp" /> - <ClCompile Include="notify.cpp" /> <ClCompile Include="resources.cpp" /> <ClCompile Include="tray_menu.cpp" /> <ClCompile Include="watcher.cpp" /> diff --git a/RealtimeSync/application.cpp b/RealtimeSync/application.cpp index 75f77da4..196e0ecc 100644 --- a/RealtimeSync/application.cpp +++ b/RealtimeSync/application.cpp @@ -42,7 +42,7 @@ void Application::OnStartApplication(wxIdleEvent& event) SetAppName(wxT("FreeFileSync")); //use a different app name, to have "GetUserDataDir()" return the same directory as for FreeFileSync #ifdef FFS_LINUX - ::gtk_rc_parse((zen::wxToZ(zen::getResourceDir()) + "styles.rc").c_str()); //remove inner border from bitmap buttons + ::gtk_rc_parse((zen::utf8CvrtTo<std::string>(zen::getResourceDir()) + "styles.rc").c_str()); //remove inner border from bitmap buttons #endif //set program language diff --git a/RealtimeSync/main_dlg.cpp b/RealtimeSync/main_dlg.cpp index 5a89e4cd..860ddcef 100644 --- a/RealtimeSync/main_dlg.cpp +++ b/RealtimeSync/main_dlg.cpp @@ -16,7 +16,6 @@ #include "tray_menu.h" #include "../shared/file_handling.h" #include "xml_ffs.h" -#include "../shared/system_constants.h" #include "../shared/string_conv.h" #include "../shared/assert_static.h" #include "../shared/build_info.h" diff --git a/RealtimeSync/makefile b/RealtimeSync/makefile index 56e8eb60..2e123af2 100644 --- a/RealtimeSync/makefile +++ b/RealtimeSync/makefile @@ -30,8 +30,7 @@ FILE_LIST+=../shared/util.cpp FILE_LIST+=../shared/check_exist.cpp FILE_LIST+=../shared/i18n.cpp FILE_LIST+=../shared/localization.cpp -FILE_LIST+=../shared/inotify/inotify-cxx.cpp -FILE_LIST+=../shared/global_func.cpp +FILE_LIST+=../shared/dir_watcher.cpp FILE_LIST+=../shared/last_error.cpp FILE_LIST+=../shared/dir_name.cpp FILE_LIST+=../shared/zstring.cpp diff --git a/RealtimeSync/notify.cpp b/RealtimeSync/notify.cpp deleted file mode 100644 index 5969ee08..00000000 --- a/RealtimeSync/notify.cpp +++ /dev/null @@ -1,274 +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 "notify.h" -#include <set> -#include "../shared/last_error.h" -#include "../shared/Loki/ScopeGuard.h" -#include <algorithm> -#include <boost/bind.hpp> -#include <dbt.h> - -using namespace zen; - - -/* -//convert bitmask into "real" drive-letter -Zstring getDriveFromMask(ULONG unitmask) -{ - for (int i = 0; i < 26; ++i) - { - if (unitmask & 0x1) - return Zstring() + static_cast<DefaultChar>(DefaultChar('A') + i) + DefaultStr(":\\"); - unitmask >>= 1; - } - return Zstring(); -} -*/ - -namespace -{ -bool messageProviderConstructed = false; -} - - -class MessageProvider //administrates a single dummy window to receive messages -{ -public: - static MessageProvider& instance() //throw (FileError) - { - static MessageProvider inst; - messageProviderConstructed = true; - return inst; - } - - class Listener - { - public: - virtual ~Listener() {} - virtual void onMessage(UINT message, WPARAM wParam, LPARAM lParam) = 0; //throw()! - }; - void registerListener(Listener& l); - void unregisterListener(Listener& l); //don't unregister objects with static lifetime - - HWND getWnd() const; //get handle in order to register additional notifications - -private: - MessageProvider(); - ~MessageProvider(); - MessageProvider(const MessageProvider&); - MessageProvider& operator=(const MessageProvider&); - - static const wchar_t WINDOW_NAME[]; - - friend LRESULT CALLBACK topWndProc(HWND, UINT, WPARAM, LPARAM); - void processMessage(UINT message, WPARAM wParam, LPARAM lParam); - - const HINSTANCE process; - HWND windowHandle; - - std::set<Listener*> listener; -}; - - -const wchar_t MessageProvider::WINDOW_NAME[] = L"E6AD5EB1-527B-4EEF-AC75-27883B233380"; //random name - - -LRESULT CALLBACK topWndProc( - HWND hwnd, //handle to window - UINT uMsg, //message identifier - WPARAM wParam, //first message parameter - LPARAM lParam) //second message parameter -{ - if (messageProviderConstructed) //attention: this callback is triggered in the middle of singleton construction! It is a bad idea to to call back at this time! - try - { - MessageProvider::instance().processMessage(uMsg, wParam, lParam); //not supposed to throw - } - catch (...) {} - - return ::DefWindowProc(hwnd, uMsg, wParam, lParam); -} - - -MessageProvider::MessageProvider() : - process(::GetModuleHandle(NULL)), //get program's module handle - windowHandle(NULL) -{ - if (process == NULL) - throw zen::FileError(wxString(wxT("Could not start monitoring window notifications:")) + wxT("\n\n") + - zen::getLastErrorFormatted() + wxT(" (GetModuleHandle)")); - - //register the main window class - WNDCLASS wc = {}; - wc.lpfnWndProc = topWndProc; - wc.hInstance = process; - wc.lpszClassName = WINDOW_NAME; - - if (::RegisterClass(&wc) == 0) - throw zen::FileError(wxString(wxT("Could not start monitoring window notifications:")) + wxT("\n\n") + - zen::getLastErrorFormatted() + wxT(" (RegisterClass)")); - - Loki::ScopeGuard guardClass = Loki::MakeGuard(::UnregisterClass, WINDOW_NAME, process); - - //create dummy-window - windowHandle = ::CreateWindow( - WINDOW_NAME, //LPCTSTR lpClassName OR ATOM in low-order word! - NULL, //LPCTSTR lpWindowName, - 0, //DWORD dwStyle, - 0, //int x, - 0, //int y, - 0, //int nWidth, - 0, //int nHeight, - 0, //note: we need a toplevel window to receive device arrival events, not a message-window (HWND_MESSAGE)! - NULL, //HMENU hMenu, - process, //HINSTANCE hInstance, - NULL); //LPVOID lpParam - if (windowHandle == NULL) - throw zen::FileError(wxString(wxT("Could not start monitoring window notifications:")) + wxT("\n\n") + - zen::getLastErrorFormatted() + wxT(" (CreateWindow)")); - - guardClass.Dismiss(); -} - - -MessageProvider::~MessageProvider() -{ - //clean-up in reverse order - ::DestroyWindow(windowHandle); - ::UnregisterClass(WINDOW_NAME, //LPCTSTR lpClassName OR ATOM in low-order word! - process); //HINSTANCE hInstance -} - - -inline -void MessageProvider::registerListener(Listener& l) -{ - listener.insert(&l); -} - - -inline -void MessageProvider::unregisterListener(Listener& l) //don't unregister objects with static lifetime -{ - listener.erase(&l); -} - - -inline -HWND MessageProvider::getWnd() const //get handle in order to register additional notifications -{ - return windowHandle; -} - - -void MessageProvider::processMessage(UINT message, WPARAM wParam, LPARAM lParam) -{ - std::for_each(listener.begin(), listener.end(), boost::bind(&Listener::onMessage, _1, message, wParam, lParam)); -} -//#################################################################################################### - - -class NotifyRequestDeviceRemoval::Pimpl : private MessageProvider::Listener -{ -public: - Pimpl(NotifyRequestDeviceRemoval& parent, const std::vector<HANDLE>& openHandles) : //throw (FileError) - parent_(parent) - { - MessageProvider::instance().registerListener(*this); //throw (FileError) - - //register handles to receive notifications - DEV_BROADCAST_HANDLE filter = {}; - filter.dbch_size = sizeof(filter); - filter.dbch_devicetype = DBT_DEVTYP_HANDLE; - - try - { - for (std::vector<HANDLE>::const_iterator i = openHandles.begin(); i != openHandles.end(); ++i) - { - filter.dbch_handle = *i; - - HDEVNOTIFY hNotfication = ::RegisterDeviceNotification( - MessageProvider::instance().getWnd(), //__in HANDLE hRecipient, - &filter, //__in LPVOID NotificationFilter, - DEVICE_NOTIFY_WINDOW_HANDLE); //__in DWORD Flags - if (hNotfication == NULL) - { - const DWORD lastError = ::GetLastError(); - if (lastError != ERROR_CALL_NOT_IMPLEMENTED && //fail on SAMBA share: this shouldn't be a showstopper! - lastError != ERROR_SERVICE_SPECIFIC_ERROR && //neither should be fail for "Pogoplug" mapped network drives - lastError != ERROR_INVALID_DATA) //this seems to happen for a NetDrive-mapped FTP server - throw zen::FileError(wxString(wxT("Could not register device removal notifications:")) + wxT("\n\n") + zen::getLastErrorFormatted(lastError)); - } - else - notifications.insert(hNotfication); - } - } - catch (...) - { - std::for_each(notifications.begin(), notifications.end(), ::UnregisterDeviceNotification); - MessageProvider::instance().unregisterListener(*this); //throw() in this case - throw; - } - } - - ~Pimpl() - { - std::for_each(notifications.begin(), notifications.end(), ::UnregisterDeviceNotification); - MessageProvider::instance().unregisterListener(*this); - } - -private: - virtual void onMessage(UINT message, WPARAM wParam, LPARAM lParam) //throw()! - { - //DBT_DEVICEQUERYREMOVE example: http://msdn.microsoft.com/en-us/library/aa363427(v=VS.85).aspx - if (message == WM_DEVICECHANGE) - { - if ( wParam == DBT_DEVICEQUERYREMOVE || - wParam == DBT_DEVICEQUERYREMOVEFAILED || - wParam == DBT_DEVICEREMOVECOMPLETE) - { - PDEV_BROADCAST_HDR header = reinterpret_cast<PDEV_BROADCAST_HDR>(lParam); - if (header->dbch_devicetype == DBT_DEVTYP_HANDLE) - { - PDEV_BROADCAST_HANDLE body = reinterpret_cast<PDEV_BROADCAST_HANDLE>(lParam); - -#ifdef __MINGW32__ - const HDEVNOTIFY requestNotification = reinterpret_cast<HDEVNOTIFY>(body->dbch_hdevnotify); -#else - const HDEVNOTIFY requestNotification = body->dbch_hdevnotify; -#endif - if (notifications.find(requestNotification) != notifications.end()) //is it for one of our notifications we registered? - switch (wParam) - { - case DBT_DEVICEQUERYREMOVE: - parent_.onRequestRemoval(body->dbch_handle); - break; - case DBT_DEVICEQUERYREMOVEFAILED: - parent_.onRemovalFinished(body->dbch_handle, false); - break; - case DBT_DEVICEREMOVECOMPLETE: - parent_.onRemovalFinished(body->dbch_handle, true); - break; - } - } - } - } - } - - NotifyRequestDeviceRemoval& parent_; - std::set<HDEVNOTIFY> notifications; -}; -//#################################################################################################### - - -NotifyRequestDeviceRemoval::NotifyRequestDeviceRemoval(const std::vector<HANDLE>& openHandles) -{ - pimpl.reset(new Pimpl(*this, openHandles)); -} - - -NotifyRequestDeviceRemoval::~NotifyRequestDeviceRemoval() {} //make sure ~auto_ptr() works with complete type diff --git a/RealtimeSync/notify.h b/RealtimeSync/notify.h deleted file mode 100644 index 47f6c3cb..00000000 --- a/RealtimeSync/notify.h +++ /dev/null @@ -1,40 +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) * -// ************************************************************************** -// -#ifndef NOTIFY_H_INCLUDED -#define NOTIFY_H_INCLUDED - -#ifndef FFS_WIN -#error use in windows build only -#endif - -#include <wx/msw/wrapwin.h> //includes "windows.h" -#include "../shared/file_error.h" -#include <vector> -#include <memory> - -//handle (user-) request for device removal via template method pattern -//evaluate directly after processing window messages -class NotifyRequestDeviceRemoval -{ -public: - NotifyRequestDeviceRemoval(const std::vector<HANDLE>& openHandles); //throw (FileError) - virtual ~NotifyRequestDeviceRemoval(); - -private: - virtual void onRequestRemoval(HANDLE hnd) = 0; //throw()! - //NOTE: onRemovalFinished is NOT guaranteed to execute after onRequestRemoval()! but most likely will - virtual void onRemovalFinished(HANDLE hnd, bool successful) = 0; //throw()! - - NotifyRequestDeviceRemoval(NotifyRequestDeviceRemoval&); //no copying - void operator=(NotifyRequestDeviceRemoval&); // - - class Pimpl; - std::auto_ptr<Pimpl> pimpl; -}; - - -#endif // NOTIFY_H_INCLUDED diff --git a/RealtimeSync/resources.cpp b/RealtimeSync/resources.cpp index 24356ff8..3f7f7988 100644 --- a/RealtimeSync/resources.cpp +++ b/RealtimeSync/resources.cpp @@ -11,7 +11,6 @@ #include <wx/icon.h> #include <memory> #include "../shared/standard_paths.h" -#include "../shared/system_constants.h" using namespace zen; diff --git a/RealtimeSync/tray_menu.cpp b/RealtimeSync/tray_menu.cpp index d42aea0a..e6d5f0d4 100644 --- a/RealtimeSync/tray_menu.cpp +++ b/RealtimeSync/tray_menu.cpp @@ -27,7 +27,7 @@ #include "../shared/shell_execute.h" using namespace rts; - +using namespace zen; class TrayIconHolder : private wxEvtHandler { @@ -227,7 +227,7 @@ std::vector<Zstring> convert(const std::vector<wxString>& dirList) { std::set<Zstring, LessFilename> output; std::transform(dirList.begin(), dirList.end(), - std::inserter(output, output.end()), static_cast<Zstring (*)(const wxString&)>(zen::wxToZ)); + std::inserter(output, output.end()), [](const wxString& str) { return zen::toZ(str); }); return std::vector<Zstring>(output.begin(), output.end()); } } @@ -299,9 +299,9 @@ rts::MonitorResponse rts::startDirectoryMonitor(const xmlAccess::XmlRealConfig& if (config.commandline.empty()) { - wxString errorMsg = _("Invalid commandline: \"%x\""); - errorMsg.Replace(L"%x", config.commandline); - throw zen::FileError(errorMsg); + std::wstring errorMsg = _("Invalid commandline: \"%x\""); + replace(errorMsg, L"%x", config.commandline); + throw FileError(errorMsg); } callback.notifyDirectoryMissing(); @@ -337,7 +337,7 @@ rts::MonitorResponse rts::startDirectoryMonitor(const xmlAccess::XmlRealConfig& callback.scheduleNextSync(wxGetLocalTime() + static_cast<long>(config.delay)); } } - catch (StartSyncNowException) {} + catch (StartSyncNowException&) {} } } catch (const ::AbortThisProcess& ab) diff --git a/RealtimeSync/watcher.cpp b/RealtimeSync/watcher.cpp index 7cd062b7..059f420b 100644 --- a/RealtimeSync/watcher.cpp +++ b/RealtimeSync/watcher.cpp @@ -5,28 +5,16 @@ // ************************************************************************** // #include "watcher.h" -#include "../shared/last_error.h" -#include "../shared/string_conv.h" #include "../shared/file_handling.h" #include "../shared/i18n.h" -#include <stdexcept> #include <set> #include <wx/timer.h> -#include <algorithm> #include "../shared/resolve_path.h" - -#ifdef FFS_WIN -#include "notify.h" -#include <wx/msw/wrapwin.h> //includes "windows.h" -#include "../shared/long_path_prefix.h" -#include <boost/shared_ptr.hpp> -#include "../shared/loki/ScopeGuard.h" -#include <boost/scoped_array.hpp> - -#elif defined FFS_LINUX -#include "../shared/inotify/inotify-cxx.h" -#include "../shared/file_traverser.h" -#endif +#include "../shared/dir_watcher.h" +#include "../shared/string_conv.h" +//#include "../library/db_file.h" //SYNC_DB_FILE_ENDING -> complete file too much of a dependency; file ending too little to decouple into single header +//#include "../library/lock_holder.h" //LOCK_FILE_ENDING +#include <wx/msgdlg.h> using namespace zen; @@ -45,45 +33,10 @@ bool rts::updateUiIsAllowed() } -#ifdef FFS_WIN -//shared_ptr custom deleter -void cleanUpChangeNotifications(const std::vector<HANDLE>* handles) -{ - for (std::vector<HANDLE>::const_iterator i = handles->begin(); i != handles->end(); ++i) - if (*i != INVALID_HANDLE_VALUE) - ::FindCloseChangeNotification(*i); - - delete handles; //don't forget!!! custom deleter needs to care for everything! -} - -#elif defined FFS_LINUX -class DirsOnlyTraverser : public zen::TraverseCallback +class MonitorExistence //detect changes to directory availability { public: - DirsOnlyTraverser(std::vector<std::string>& dirs) : m_dirs(dirs) {} - - virtual void onFile(const Zchar* shortName, const Zstring& fullName, const FileInfo& details) {} - virtual void onSymlink(const Zchar* shortName, const Zstring& fullName, const SymlinkInfo& details) {} - virtual ReturnValDir onDir(const Zchar* shortName, const Zstring& fullName) - { - m_dirs.push_back(fullName.c_str()); - return ReturnValDir(Loki::Int2Type<ReturnValDir::TRAVERSING_DIR_CONTINUE>(), *this); - } - virtual void onError(const wxString& errorText) - { - throw zen::FileError(errorText); - } - -private: - std::vector<std::string>& m_dirs; -}; -#endif - - -class WatchDirectories //detect changes to directory availability -{ -public: - WatchDirectories() : allExisting_(true) {} + MonitorExistence() : allExisting_(true) {} //initialization void addForMonitoring(const Zstring& dirName) @@ -116,79 +69,12 @@ private: rts::WaitResult rts::waitForChanges(const std::vector<Zstring>& dirNames, WaitCallback* statusHandler) //throw(FileError) { - /* - #warning cleanup - { - const Zstring formattedDir = zen::getFormattedDirectoryName(dirNames.front()); - - //SE_BACKUP_NAME and SE_RESTORE_NAME <- required by FILE_FLAG_BACKUP_SEMANTICS??? - - //open the directory to watch.... - HANDLE hDir = ::CreateFile(zen::applyLongPathPrefix(formattedDir).c_str(), - FILE_LIST_DIRECTORY, - FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, //leaving out last flag may prevent files to be deleted WITHIN monitored dir (http://qualapps.blogspot.com/2010/05/understanding-readdirectorychangesw_19.html) - NULL, - OPEN_EXISTING, - FILE_FLAG_BACKUP_SEMANTICS, - NULL); - if (hDir == INVALID_HANDLE_VALUE) - { - const DWORD lastError = ::GetLastError(); - if ( lastError == ERROR_FILE_NOT_FOUND || //no need to check this condition any earlier! - lastError == ERROR_BAD_NETPATH) // - return CHANGE_DIR_MISSING; - - const wxString errorMessage = wxString(_("Could not initialize directory monitoring:")) + wxT("\n\"") + zToWx(formattedDir) + wxT("\""); - throw zen::FileError(errorMessage + wxT("\n\n") + zen::getLastErrorFormatted()); - } - - Loki::ScopeGuard dummy = Loki::MakeGuard(::CloseHandle, hDir); - (void)dummy; //silence warning "unused variable" - - - const size_t bufferSize = sizeof(FILE_NOTIFY_INFORMATION); - boost::scoped_array<char> tmp(new char[bufferSize]); - FILE_NOTIFY_INFORMATION& notifyInfo = reinterpret_cast<FILE_NOTIFY_INFORMATION&>(*tmp.get()); - - DWORD bytesWritten = 0; - - if (!::ReadDirectoryChangesW( - hDir, //__in HANDLE hDirectory, - ¬ifyInfo, //__out LPVOID lpBuffer, - bufferSize, //__in DWORD nBufferLength, - true, //__in BOOL bWatchSubtree, - FILE_NOTIFY_CHANGE_FILE_NAME | //__in DWORD dwNotifyFilter, - FILE_NOTIFY_CHANGE_DIR_NAME | - FILE_NOTIFY_CHANGE_SIZE | - FILE_NOTIFY_CHANGE_LAST_WRITE, - &bytesWritten, //__out_opt LPDWORD lpBytesReturned, - NULL, //__inout_opt LPOVERLAPPED lpOverlapped, - NULL)) //__in_opt LPOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine - { - const wxString errorMessage = wxString(_("Could not initialize directory monitoring:")) + wxT("\n\"") + zToWx(formattedDir) + wxT("\""); - throw zen::FileError(errorMessage + wxT("\n\n") + zen::getLastErrorFormatted()); - } - return CHANGE_DETECTED; - } - */ - - - - - - - - - if (dirNames.empty()) //pathological case, but check is needed nevertheless throw zen::FileError(_("A directory input field is empty.")); //detect when volumes are removed/are not available anymore - WatchDirectories dirWatcher; - -#ifdef FFS_WIN - typedef boost::shared_ptr<std::vector<HANDLE> > ChangeNotifList; - ChangeNotifList changeNotifications(new std::vector<HANDLE>, ::cleanUpChangeNotifications); + MonitorExistence checkExist; + std::vector<std::shared_ptr<DirWatcher>> watches; for (std::vector<Zstring>::const_iterator i = dirNames.begin(); i != dirNames.end(); ++i) { @@ -197,198 +83,72 @@ rts::WaitResult rts::waitForChanges(const std::vector<Zstring>& dirNames, WaitCa if (formattedDir.empty()) throw zen::FileError(_("A directory input field is empty.")); - dirWatcher.addForMonitoring(formattedDir); - - const HANDLE rv = ::FindFirstChangeNotification( - zen::applyLongPathPrefix(formattedDir).c_str(), //__in LPCTSTR lpPathName, - true, //__in BOOL bWatchSubtree, - FILE_NOTIFY_CHANGE_FILE_NAME | - FILE_NOTIFY_CHANGE_DIR_NAME | - FILE_NOTIFY_CHANGE_SIZE | - FILE_NOTIFY_CHANGE_LAST_WRITE); //__in DWORD dwNotifyFilter - - if (rv == INVALID_HANDLE_VALUE) - { - const DWORD lastError = ::GetLastError(); - if ( lastError == ERROR_FILE_NOT_FOUND || //no need to check this condition any earlier! - lastError == ERROR_BAD_NETPATH) // - return CHANGE_DIR_MISSING; - - const wxString errorMessage = wxString(_("Could not initialize directory monitoring:")) + wxT("\n\"") + zToWx(formattedDir) + wxT("\""); - throw zen::FileError(errorMessage + wxT("\n\n") + zen::getLastErrorFormatted()); - } - - changeNotifications->push_back(rv); - } - - if (changeNotifications->size() == 0) - throw zen::FileError(_("A directory input field is empty.")); - - - //detect user request for device removal (e.g. usb stick) - class HandleVolumeRemoval : public NotifyRequestDeviceRemoval - { - public: - HandleVolumeRemoval(ChangeNotifList& openHandles) : - NotifyRequestDeviceRemoval(*openHandles), //throw (FileError) - removalRequested(false), - operationComplete(false), - openHandles_(openHandles) {} - - bool requestReceived() const - { - return removalRequested; - } - bool finished() const - { - return operationComplete; - } + checkExist.addForMonitoring(formattedDir); - private: - virtual void onRequestRemoval(HANDLE hnd) //don't throw! + try { - openHandles_.reset(); //free all handles - removalRequested = true; //and make sure they are not used anymore + watches.push_back(std::make_shared<DirWatcher>(formattedDir)); //throw FileError } - virtual void onRemovalFinished(HANDLE hnd, bool successful) //throw()! + catch (zen::FileError&) { - operationComplete = true; + if (!zen::dirExists(formattedDir)) //that's no good locking behavior, but better than nothing + return CHANGE_DIR_MISSING; + throw; } - - bool removalRequested; - bool operationComplete; - ChangeNotifList& openHandles_; - } removalRequest(changeNotifications); - + } while (true) { - //check for changes within directories: - const DWORD rv = ::WaitForMultipleObjects( //NOTE: changeNotifications returns valid pointer, because it cannot be empty in this context - static_cast<DWORD>(changeNotifications->size()), //__in DWORD nCount, - &(*changeNotifications)[0], //__in const HANDLE *lpHandles, - false, //__in BOOL bWaitAll, - UI_UPDATE_INTERVAL); //__in DWORD dwMilliseconds - if (WAIT_OBJECT_0 <= rv && rv < WAIT_OBJECT_0 + changeNotifications->size()) - return CHANGE_DETECTED; //directory change detected - else if (rv == WAIT_FAILED) - throw zen::FileError(wxString(_("Error when monitoring directories.")) + wxT("\n\n") + zen::getLastErrorFormatted()); - //else if (rv == WAIT_TIMEOUT) - - if (!dirWatcher.allExisting()) //check for removed devices: + //IMPORTANT CHECK: dirwatcher has problems detecting removal of top watched directories! + if (!checkExist.allExisting()) //check for removed devices: return CHANGE_DIR_MISSING; - statusHandler->requestUiRefresh(); - - //handle device removal - if (removalRequest.requestReceived()) + try { - const wxMilliClock_t maxwait = wxGetLocalTimeMillis() + 5000; //HandleVolumeRemoval::finished() not guaranteed! - while (!removalRequest.finished() && wxGetLocalTimeMillis() < maxwait) + for (auto iter = watches.begin(); iter != watches.end(); ++iter) { - wxMilliSleep(rts::UI_UPDATE_INTERVAL); - statusHandler->requestUiRefresh(); - } - return CHANGE_DIR_MISSING; - } - } + std::vector<Zstring> changedFiles = (*iter)->getChanges(); //throw FileError -#elif defined FFS_LINUX - std::vector<std::string> fullDirList; //including subdirectories! - - //add all subdirectories - for (std::vector<Zstring>::const_iterator i = dirNames.begin(); i != dirNames.end(); ++i) - { - const Zstring formattedDir = zen::getFormattedDirectoryName(*i); - - if (formattedDir.empty()) - throw zen::FileError(_("A directory input field is empty.")); - - dirWatcher.addForMonitoring(formattedDir); + //remove to be ignored changes + changedFiles.erase(std::remove_if(changedFiles.begin(), changedFiles.end(), + [](const Zstring& name) + { + return endsWith(name, Zstr(".ffs_lock")) || //sync.ffs_lock, sync.Del.ffs_lock + endsWith(name, Zstr(".ffs_db")); //sync.ffs_db, .sync.tmp.ffs_db + //no need to ignore temporal recycle bin directory: this must be caused by a file deletion anyway + }), changedFiles.end()); + if (!changedFiles.empty()) + { +/* + std::for_each(changedFiles.begin(), changedFiles.end(), + [](const Zstring& fn) { wxMessageBox(toWx(fn));}); - fullDirList.push_back(formattedDir.c_str()); + const wxString filename = toWx(changedFiles[0]); + ::wxSetEnv(wxT("RTS_CHANGE"), filename); +*/ - try //get all subdirectories - { - DirsOnlyTraverser traverser(fullDirList); - zen::traverseFolder(formattedDir, false, traverser); //don't traverse into symlinks (analog to windows build) + return CHANGE_DETECTED; //directory change detected + } + } } - catch (const zen::FileError&) + catch (FileError&) { - if (!zen::dirExists(formattedDir)) //that's no good locking behavior, but better than nothing + //maybe some error is caused due to some unexpected removal/unavailability of a watched directory? If so we can remedy this error: + if (!checkExist.allExisting()) return CHANGE_DIR_MISSING; - throw; } - } - - try - { - Inotify notifications; - notifications.SetNonBlock(true); - - for (std::vector<std::string>::const_iterator i = fullDirList.begin(); i != fullDirList.end(); ++i) - { - try - { - InotifyWatch newWatch(*i, //dummy object: InotifyWatch may be destructed safely after Inotify::Add() - IN_DONT_FOLLOW | //don't follow symbolic links - IN_ONLYDIR | //watch directories only - IN_CLOSE_WRITE | - IN_CREATE | - IN_DELETE | - IN_DELETE_SELF | - IN_MODIFY | - IN_MOVE_SELF | - IN_MOVED_FROM | - IN_MOVED_TO ); - notifications.Add(newWatch); - } - catch (const InotifyException& e) - { - if (!zen::dirExists(i->c_str())) //that's no good locking behavior, but better than nothing - return CHANGE_DIR_MISSING; - - const wxString errorMessage = wxString(_("Could not initialize directory monitoring:")) + wxT("\n\"") + zToWx(i->c_str()) + wxT("\""); - throw zen::FileError(errorMessage + wxT("\n\n") + zToWx(e.GetMessage().c_str())); - } - } - - - if (notifications.GetWatchCount() == 0) - throw zen::FileError(_("A directory input field is empty.")); - - while (true) - { - notifications.WaitForEvents(); //called in non-blocking mode - - if (notifications.GetEventCount() > 0) - return CHANGE_DETECTED; //directory change detected - if (!dirWatcher.allExisting()) //check for removed devices: - return CHANGE_DIR_MISSING; - - wxMilliSleep(rts::UI_UPDATE_INTERVAL); - statusHandler->requestUiRefresh(); - } - } - catch (const InotifyException& e) - { - throw zen::FileError(wxString(_("Error when monitoring directories.")) + wxT("\n\n") + zToWx(e.GetMessage().c_str())); - } - catch (const std::exception& e) - { - throw zen::FileError(wxString(_("Error when monitoring directories.")) + wxT("\n\n") + zToWx(e.what())); + wxMilliSleep(rts::UI_UPDATE_INTERVAL); + statusHandler->requestUiRefresh(); } -#endif } +//support for monitoring newly connected directories volumes (e.g.: USB-sticks) void rts::waitForMissingDirs(const std::vector<Zstring>& dirNames, WaitCallback* statusHandler) //throw(FileError) { - //new: support for monitoring newly connected directories volumes (e.g.: USB-sticks) - wxLongLong lastCheck; while (true) diff --git a/RealtimeSync/watcher.h b/RealtimeSync/watcher.h index 46dfc50e..7208e7fb 100644 --- a/RealtimeSync/watcher.h +++ b/RealtimeSync/watcher.h @@ -33,7 +33,7 @@ enum WaitResult CHANGE_DETECTED, CHANGE_DIR_MISSING }; -WaitResult waitForChanges(const std::vector<Zstring>& dirNames444, WaitCallback* statusHandler); //throw(FileError) +WaitResult waitForChanges(const std::vector<Zstring>& dirNames, WaitCallback* statusHandler); //throw(FileError) //wait until all directories become available (again) void waitForMissingDirs(const std::vector<Zstring>& dirNames, WaitCallback* statusHandler); //throw(FileError) diff --git a/RealtimeSync/xml_ffs.cpp b/RealtimeSync/xml_ffs.cpp index 15e6f4c2..3424dea2 100644 --- a/RealtimeSync/xml_ffs.cpp +++ b/RealtimeSync/xml_ffs.cpp @@ -18,42 +18,29 @@ using namespace zen; -#ifdef FFS_WIN -struct CmpNoCase -{ - bool operator()(const wxString& a, const wxString& b) const - { - return a.CmpNoCase(b) < 0; - } -}; -#endif - - xmlAccess::XmlRealConfig convertBatchToReal(const xmlAccess::XmlBatchConfig& batchCfg, const wxString& filename) { xmlAccess::XmlRealConfig output; -#ifdef FFS_WIN - std::set<wxString, CmpNoCase> uniqueFolders; -#elif defined FFS_LINUX - std::set<wxString> uniqueFolders; -#endif + std::set<Zstring, LessFilename> uniqueFolders; //add main folders - uniqueFolders.insert(zToWx(batchCfg.mainCfg.firstPair.leftDirectory)); - uniqueFolders.insert(zToWx(batchCfg.mainCfg.firstPair.rightDirectory)); + uniqueFolders.insert(batchCfg.mainCfg.firstPair.leftDirectory); + uniqueFolders.insert(batchCfg.mainCfg.firstPair.rightDirectory); //additional folders - for (std::vector<zen::FolderPairEnh>::const_iterator i = batchCfg.mainCfg.additionalPairs.begin(); - i != batchCfg.mainCfg.additionalPairs.end(); ++i) + std::for_each(batchCfg.mainCfg.additionalPairs.begin(), batchCfg.mainCfg.additionalPairs.end(), + [&](const FolderPairEnh& fp) { - uniqueFolders.insert(zToWx(i->leftDirectory)); - uniqueFolders.insert(zToWx(i->rightDirectory)); - } + uniqueFolders.insert(fp.leftDirectory); + uniqueFolders.insert(fp.rightDirectory); + }); - uniqueFolders.erase(wxString()); + uniqueFolders.erase(Zstring()); - output.directories.insert(output.directories.end(), uniqueFolders.begin(), uniqueFolders.end()); + output.directories.clear(); + std::transform(uniqueFolders.begin(), uniqueFolders.end(), std::back_inserter(output.directories), + [](const Zstring& fn) { return toWx(fn); }); output.commandline = wxT("\"") + zen::getLauncher() + wxT("\"") + wxT(" \"") + filename + wxT("\""); @@ -62,7 +49,7 @@ xmlAccess::XmlRealConfig convertBatchToReal(const xmlAccess::XmlBatchConfig& bat } -void rts::readRealOrBatchConfig(const wxString& filename, xmlAccess::XmlRealConfig& config) //throw (xmlAccess::FfsXmlError); +void rts::readRealOrBatchConfig(const wxString& filename, xmlAccess::XmlRealConfig& config) //throw xmlAccess::FfsXmlError; { if (xmlAccess::getXmlType(filename) != xmlAccess::XML_TYPE_BATCH) { @@ -74,7 +61,7 @@ void rts::readRealOrBatchConfig(const wxString& filename, xmlAccess::XmlRealConf xmlAccess::XmlBatchConfig batchCfg; try { - xmlAccess::readConfig(filename, batchCfg); //throw (xmlAccess::FfsXmlError); + xmlAccess::readConfig(filename, batchCfg); //throw xmlAccess::FfsXmlError; } catch (const xmlAccess::FfsXmlError& e) { diff --git a/RealtimeSync/xml_proc.cpp b/RealtimeSync/xml_proc.cpp index 4ddf8bc4..e3d7f270 100644 --- a/RealtimeSync/xml_proc.cpp +++ b/RealtimeSync/xml_proc.cpp @@ -43,7 +43,7 @@ bool isXmlTypeRTS(const XmlDoc& doc) //throw() void xmlAccess::readRealConfig(const wxString& filename, XmlRealConfig& config) { - if (!fileExists(wxToZ(filename))) + if (!fileExists(toZ(filename))) throw FfsXmlError(wxString(_("File does not exist:")) + wxT("\n\"") + filename + wxT("\"")); XmlDoc doc; |