summaryrefslogtreecommitdiff
path: root/RealtimeSync
diff options
context:
space:
mode:
Diffstat (limited to 'RealtimeSync')
-rw-r--r--RealtimeSync/RealtimeSync.cbp10
-rw-r--r--RealtimeSync/RealtimeSync.vcxproj6
-rw-r--r--RealtimeSync/application.cpp2
-rw-r--r--RealtimeSync/main_dlg.cpp1
-rw-r--r--RealtimeSync/makefile3
-rw-r--r--RealtimeSync/notify.cpp274
-rw-r--r--RealtimeSync/notify.h40
-rw-r--r--RealtimeSync/resources.cpp1
-rw-r--r--RealtimeSync/tray_menu.cpp12
-rw-r--r--RealtimeSync/watcher.cpp334
-rw-r--r--RealtimeSync/watcher.h2
-rw-r--r--RealtimeSync/xml_ffs.cpp41
-rw-r--r--RealtimeSync/xml_proc.cpp2
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,
- &notifyInfo, //__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;
bgstack15