diff options
Diffstat (limited to 'RealtimeSync')
-rw-r--r-- | RealtimeSync/RealtimeSync.cbp | 62 | ||||
-rw-r--r-- | RealtimeSync/RealtimeSync.vcproj | 4 | ||||
-rw-r--r-- | RealtimeSync/mainDialog.cpp | 3 | ||||
-rw-r--r-- | RealtimeSync/makefile | 8 | ||||
-rw-r--r-- | RealtimeSync/trayMenu.cpp | 79 | ||||
-rw-r--r-- | RealtimeSync/watcher.cpp | 208 | ||||
-rw-r--r-- | RealtimeSync/watcher.h | 14 | ||||
-rw-r--r-- | RealtimeSync/xmlProcessing.h | 2 |
8 files changed, 234 insertions, 146 deletions
diff --git a/RealtimeSync/RealtimeSync.cbp b/RealtimeSync/RealtimeSync.cbp index 9a5d9f93..24b6d859 100644 --- a/RealtimeSync/RealtimeSync.cbp +++ b/RealtimeSync/RealtimeSync.cbp @@ -7,32 +7,6 @@ <Option pch_mode="2" /> <Option compiler="gcc" /> <Build> - <Target title="Debug"> - <Option output="..\BUILD\RealtimeSync" prefix_auto="1" extension_auto="1" /> - <Option working_dir="..\BUILD" /> - <Option object_output="..\OBJ\Debug_RTS_GCC" /> - <Option type="0" /> - <Option compiler="gcc" /> - <Option projectLinkerOptionsRelation="2" /> - <Compiler> - <Add option="-g" /> - <Add option="-Winvalid-pch" /> - <Add option='-include "pch.h"' /> - <Add option="-D__WXDEBUG__" /> - <Add directory="C:\Programme\C++\wxWidgets\lib\gcc_lib\mswud" /> - </Compiler> - <ResourceCompiler> - <Add directory="C:\Programme\C++\wxWidgets\lib\gcc_lib\mswud" /> - </ResourceCompiler> - <Linker> - <Add library="libwxmsw28ud_core.a" /> - <Add library="libwxmsw28ud_adv.a" /> - <Add library="libwxbase28ud.a" /> - <Add library="libwxpngd.a" /> - <Add library="libwxzlibd.a" /> - <Add directory="C:\Programme\C++\wxWidgets\lib\gcc_lib" /> - </Linker> - </Target> <Target title="Release"> <Option output="..\BUILD\RealtimeSync" prefix_auto="1" extension_auto="1" /> <Option working_dir="..\BUILD" /> @@ -45,9 +19,6 @@ <Add option="-DNDEBUG" /> <Add directory="C:\Programme\C++\wxWidgets\lib\gcc_lib\mswu" /> </Compiler> - <ResourceCompiler> - <Add directory="C:\Programme\C++\wxWidgets\lib\gcc_lib\mswu" /> - </ResourceCompiler> <Linker> <Add option="-s" /> <Add library="libwxmsw28u_core.a" /> @@ -58,12 +29,38 @@ <Add directory="C:\Programme\C++\wxWidgets\lib\gcc_lib" /> </Linker> </Target> + <Target title="Debug-DLL"> + <Option output="..\BUILD\RealtimeSync" prefix_auto="1" extension_auto="1" /> + <Option working_dir="..\BUILD" /> + <Option object_output="..\OBJ\Debug_RTS_GCC" /> + <Option type="0" /> + <Option compiler="gcc" /> + <Option projectLinkerOptionsRelation="2" /> + <Compiler> + <Add option="-g" /> + <Add option="-Winvalid-pch" /> + <Add option='-include "pch.h"' /> + <Add option="-D__WXDEBUG__" /> + <Add directory="C:\Program Files\C++\wxWidgets\lib\gcc_dll\mswud" /> + </Compiler> + <Linker> + <Add library="libwxmsw28ud_core.a" /> + <Add library="libwxmsw28ud_adv.a" /> + <Add library="libwxbase28ud.a" /> + <Add library="libwxpngd.a" /> + <Add library="libwxzlibd.a" /> + <Add directory="C:\Program Files\C++\wxWidgets\lib\gcc_dll" /> + </Linker> + </Target> </Build> <Compiler> + <Add option="-Wshadow" /> + <Add option="-Winit-self" /> + <Add option="-Wswitch-enum" /> + <Add option="-Wmain" /> <Add option="-Wall" /> <Add option="-pipe" /> <Add option="-mthreads" /> - <Add option='[[if (PLATFORM == PLATFORM_MSW && (GetCompilerFactory().GetCompilerVersionString(_T("gcc")) >= _T("4.0.0"))) print(_T("-Wno-attributes"));]]' /> <Add option="-D__GNUWIN32__" /> <Add option="-D__WXMSW__" /> <Add option="-DwxUSE_UNICODE" /> @@ -71,7 +68,6 @@ <Add option="-DZSTRING_WIDE_CHAR" /> <Add option="-DTIXML_USE_STL" /> <Add directory="C:\Programme\C++\wxWidgets\include" /> - <Add directory="C:\Programme\C++\wxWidgets\contrib\include" /> <Add directory="..\shared\boost_1_x" /> </Compiler> <ResourceCompiler> @@ -79,6 +75,7 @@ </ResourceCompiler> <Linker> <Add option="-mthreads" /> + <Add option="-Wl,--enable-auto-import" /> <Add library="libkernel32.a" /> <Add library="libuser32.a" /> <Add library="libuuid.a" /> @@ -101,7 +98,7 @@ <Unit filename="pch.h"> <Option compile="1" /> <Option weight="0" /> - <Option target="Debug" /> + <Option target="Debug-DLL" /> </Unit> <Unit filename="resource.rc"> <Option compilerVar="WINDRES" /> @@ -138,7 +135,6 @@ <Unit filename="..\shared\localization.h" /> <Unit filename="..\shared\longPathPrefix.cpp" /> <Unit filename="..\shared\longPathPrefix.h" /> - <Unit filename="..\shared\recycler.cpp" /> <Unit filename="..\shared\shadow.cpp" /> <Unit filename="..\shared\standardPaths.cpp" /> <Unit filename="..\shared\standardPaths.h" /> diff --git a/RealtimeSync/RealtimeSync.vcproj b/RealtimeSync/RealtimeSync.vcproj index 8d60d6ba..8e95f3a6 100644 --- a/RealtimeSync/RealtimeSync.vcproj +++ b/RealtimeSync/RealtimeSync.vcproj @@ -432,10 +432,6 @@ > </File> <File - RelativePath="..\shared\recycler.cpp" - > - </File> - <File RelativePath=".\resources.cpp" > </File> diff --git a/RealtimeSync/mainDialog.cpp b/RealtimeSync/mainDialog.cpp index 72b19a35..5ba378ce 100644 --- a/RealtimeSync/mainDialog.cpp +++ b/RealtimeSync/mainDialog.cpp @@ -8,6 +8,7 @@ #include "resources.h" #include "../shared/customButton.h" #include "../shared/standardPaths.h" +#include "functions.h" #include <wx/msgdlg.h> #include <wx/wupdlock.h> #include "watcher.h" @@ -288,7 +289,7 @@ void MainDialog::setConfiguration(const xmlAccess::XmlRealConfig& cfg) m_textCtrlCommand->SetValue(cfg.commandline); //set delay - m_spinCtrlDelay->SetValue(cfg.delay); + m_spinCtrlDelay->SetValue(static_cast<int>(cfg.delay)); } diff --git a/RealtimeSync/makefile b/RealtimeSync/makefile index 8f42e2e3..9692e22a 100644 --- a/RealtimeSync/makefile +++ b/RealtimeSync/makefile @@ -18,6 +18,7 @@ FILE_LIST+=xmlProcessing.cpp FILE_LIST+=xmlFreeFileSync.cpp FILE_LIST+=../library/processXml.cpp FILE_LIST+=../structures.cpp +FILE_LIST+=../shared/localization_no_BOM.cpp FILE_LIST+=../shared/inotify/inotify-cxx.cpp FILE_LIST+=../shared/tinyxml/tinyxml.cpp FILE_LIST+=../shared/tinyxml/tinystr.cpp @@ -31,7 +32,6 @@ FILE_LIST+=../shared/xmlBase.cpp FILE_LIST+=../shared/customButton.cpp FILE_LIST+=../shared/fileHandling.cpp FILE_LIST+=../shared/fileTraverser.cpp -FILE_LIST+=../shared/localization.cpp FILE_LIST+=../shared/standardPaths.cpp FILE_LIST+=../shared/helpProvider.cpp FILE_LIST+=../shared/fileIO.cpp @@ -50,8 +50,8 @@ init: #remove byte ordering mark: needed by Visual C++ but an error with GCC removeBOM: ../tools/removeBOM.cpp - g++ -o removeBOM ../tools/removeBOM.cpp - ./removeBOM ../shared/localization.cpp + g++ -o OBJ/removeBOM ../tools/removeBOM.cpp + ./OBJ/removeBOM ../shared/localization.cpp ../shared/localization_no_BOM.cpp %.dep : %.cpp #strip path information @@ -63,7 +63,7 @@ RealtimeSync: init removeBOM $(DEP_LIST) clean: rm -rf OBJ rm -f ../BUILD/$(APPNAME) - rm -f removeBOM + rm -f ../shared/localization_no_BOM.cpp install: if [ ! -d $(BINDIR) ] ; then mkdir -p $(BINDIR); fi diff --git a/RealtimeSync/trayMenu.cpp b/RealtimeSync/trayMenu.cpp index 79076abd..436ee904 100644 --- a/RealtimeSync/trayMenu.cpp +++ b/RealtimeSync/trayMenu.cpp @@ -9,7 +9,9 @@ #include <wx/taskbar.h> #include <wx/app.h> #include "resources.h" -//#include <memory> +#include <algorithm> +#include <iterator> +#include "../shared/stringConv.h" #include <wx/utils.h> #include <wx/menu.h> #include "watcher.h" @@ -23,7 +25,7 @@ using namespace RealtimeSync; -class WaitCallbackImpl : private wxEvtHandler, public RealtimeSync::WaitCallback //keep this order: else VC++ generated wrong code +class WaitCallbackImpl : private wxEvtHandler, public RealtimeSync::WaitCallback //keep this order: else VC++ generates wrong code { public: WaitCallbackImpl(); @@ -31,6 +33,9 @@ public: virtual void requestUiRefresh(); + void showIconActive(); + void showIconWaiting(); + void requestAbort() { m_abortRequested = true; @@ -114,13 +119,7 @@ WaitCallbackImpl::WaitCallbackImpl() : { trayMenu = new RtsTrayIcon(this); //not in initialization list: give it a valid parent object! -#ifdef FFS_WIN - const wxIcon& realtimeIcon = *GlobalResources::getInstance().programIcon; -#elif defined FFS_LINUX - wxIcon realtimeIcon; - realtimeIcon.CopyFromBitmap(GlobalResources::getInstance().getImageByName(wxT("RTS_tray_linux.png"))); //use a 22x22 bitmap for perfect fit -#endif - trayMenu->SetIcon(realtimeIcon, wxString(wxT("RealtimeSync")) + wxT(" - ") + _("Monitoring active...")); + showIconActive(); //register double-click trayMenu->Connect(wxEVT_TASKBAR_LEFT_DCLICK, wxCommandEventHandler(WaitCallbackImpl::OnRequestResume), NULL, this); @@ -139,6 +138,30 @@ WaitCallbackImpl::~WaitCallbackImpl() } +void WaitCallbackImpl::showIconActive() +{ + wxIcon realtimeIcon; +#ifdef FFS_WIN + realtimeIcon.CopyFromBitmap(GlobalResources::getInstance().getImageByName(wxT("RTS_tray_win.png"))); //use a 16x16 bitmap +#elif defined FFS_LINUX + realtimeIcon.CopyFromBitmap(GlobalResources::getInstance().getImageByName(wxT("RTS_tray_linux.png"))); //use a 22x22 bitmap for perfect fit +#endif + trayMenu->SetIcon(realtimeIcon, wxString(wxT("RealtimeSync")) + wxT(" - ") + _("Monitoring active...")); +} + + +void WaitCallbackImpl::showIconWaiting() +{ + wxIcon realtimeIcon; +#ifdef FFS_WIN + realtimeIcon.CopyFromBitmap(GlobalResources::getInstance().getImageByName(wxT("RTS_tray_waiting_win.png"))); //use a 16x16 bitmap +#elif defined FFS_LINUX + realtimeIcon.CopyFromBitmap(GlobalResources::getInstance().getImageByName(wxT("RTS_tray_waiting_linux.png"))); //use a 22x22 bitmap for perfect fit +#endif + trayMenu->SetIcon(realtimeIcon, wxString(wxT("RealtimeSync")) + wxT(" - ") + _("Waiting for all directories to become available...")); +} + + void WaitCallbackImpl::OnContextMenuSelection(wxCommandEvent& event) { const int eventId = event.GetId(); @@ -188,9 +211,22 @@ void WaitCallbackImpl::requestUiRefresh() } //############################################################################################################## +namespace +{ +std::vector<Zstring> convert(const std::vector<wxString>& dirList) +{ + std::vector<Zstring> output; + std::transform(dirList.begin(), dirList.end(), + std::back_inserter(output), static_cast<Zstring (*)(const wxString&)>(FreeFileSync::wxToZ)); + return output; +} +} + RealtimeSync::MonitorResponse RealtimeSync::startDirectoryMonitor(const xmlAccess::XmlRealConfig& config) { + const std::vector<Zstring> dirList = convert(config.directories); + try { WaitCallbackImpl callback; @@ -198,18 +234,31 @@ RealtimeSync::MonitorResponse RealtimeSync::startDirectoryMonitor(const xmlAcces if (config.commandline.empty()) throw FreeFileSync::FileError(_("Command line is empty!")); - long lastExec = 0; while (true) { + //execute commandline + callback.showIconWaiting(); + waitForMissingDirs(dirList, &callback); + callback.showIconActive(); + wxExecute(config.commandline, wxEXEC_SYNC); //execute command wxLog::FlushActive(); //show wxWidgets error messages (if any) - //wait - waitForChanges(config.directories, &callback); - lastExec = wxGetLocalTime(); + //wait for changes (and for all directories to become available) + switch (waitForChanges(dirList, &callback)) + { + case CHANGE_DIR_MISSING: //don't execute the commandline before all directories are available! + callback.showIconWaiting(); + waitForMissingDirs(dirList, &callback); + callback.showIconActive(); + break; + case CHANGE_DETECTED: + break; + } //some delay - while (wxGetLocalTime() - lastExec < static_cast<long>(config.delay)) + const long nextExec = wxGetLocalTime() + static_cast<long>(config.delay); + while (wxGetLocalTime() < nextExec) { callback.requestUiRefresh(); wxMilliSleep(RealtimeSync::UI_UPDATE_INTERVAL); @@ -222,7 +271,7 @@ RealtimeSync::MonitorResponse RealtimeSync::startDirectoryMonitor(const xmlAcces } catch (const FreeFileSync::FileError& error) { - wxMessageBox(error.show().c_str(), _("Error"), wxOK | wxICON_ERROR); + wxMessageBox(error.show(), _("Error"), wxOK | wxICON_ERROR); return RESUME; } diff --git a/RealtimeSync/watcher.cpp b/RealtimeSync/watcher.cpp index 3aa40520..ad9e6508 100644 --- a/RealtimeSync/watcher.cpp +++ b/RealtimeSync/watcher.cpp @@ -6,24 +6,22 @@ // #include "watcher.h" #include "../shared/systemFunctions.h" -#include "functions.h" +//#include "functions.h" #include <wx/intl.h> -#include <wx/filefn.h> -#include "../shared/fileHandling.h" +//#include <wx/filefn.h> #include "../shared/stringConv.h" +#include "../shared/fileHandling.h" #include <stdexcept> -#include <map> +#include <set> #include <wx/timer.h> +#include <algorithm> #ifdef FFS_WIN -//#include "../shared/fileId.h" -//#include "Dbt.h" #include <wx/msw/wrapwin.h> //includes "windows.h" #include "../shared/longPathPrefix.h" #elif defined FFS_LINUX -#include <wx/timer.h> -#include <exception> +//#include <exception> #include "../shared/inotify/inotify-cxx.h" #include "../shared/fileTraverser.h" #endif @@ -33,8 +31,8 @@ using namespace FreeFileSync; bool RealtimeSync::updateUiIsAllowed() { - static wxLongLong lastExec = 0; - const wxLongLong newExec = wxGetLocalTimeMillis(); + static wxLongLong lastExec; + const wxLongLong newExec = wxGetLocalTimeMillis(); if (newExec - lastExec >= RealtimeSync::UI_UPDATE_INTERVAL) //perform ui updates not more often than necessary { @@ -241,7 +239,7 @@ public: ::FindCloseChangeNotification(*i); } - void addHandle(const HANDLE hndl) + void addHandle(HANDLE hndl) { arrayHandle.push_back(hndl); } @@ -266,14 +264,18 @@ class DirsOnlyTraverser : public FreeFileSync::TraverseCallback public: DirsOnlyTraverser(std::vector<std::string>& dirs) : m_dirs(dirs) {} - virtual ReturnValue onFile(const DefaultChar* shortName, const Zstring& fullName, const FileInfo& details) + virtual ReturnValue onFile(const DefaultChar* shortName, const Zstring& fullName, bool isSymlink, const FileInfo& details) { return TRAVERSING_CONTINUE; } - virtual ReturnValDir onDir(const DefaultChar* shortName, const Zstring& fullName) + virtual ReturnValDir onDir(const DefaultChar* shortName, const Zstring& fullName, bool isSymlink) { m_dirs.push_back(fullName.c_str()); - return ReturnValDir(Loki::Int2Type<ReturnValDir::TRAVERSING_DIR_CONTINUE>(), this); + + if (isSymlink) //don't traverse into symlinks (analog to windows build) + return ReturnValDir(Loki::Int2Type<ReturnValDir::TRAVERSING_DIR_IGNORE>()); + else + return ReturnValDir(Loki::Int2Type<ReturnValDir::TRAVERSING_DIR_CONTINUE>(), this); } virtual ReturnValue onError(const wxString& errorText) { @@ -286,107 +288,104 @@ private: #endif -class NotifyDirectoryArrival //detect changes to directory availability +class WatchDirectories //detect changes to directory availability { public: + WatchDirectories() : allExistingBuffer(true) {} + //initialization - void addForMonitoring(const Zstring& dirName, bool isExisting) //dir-existence already checked by calling method, avoid double-checking -> consistency! + void addForMonitoring(const Zstring& dirName) { - availablility[dirName] = isExisting; + dirList.insert(dirName); } - //detection - bool changeDetected() //polling explicitly allowed! + bool allExisting() const //polling explicitly allowed! { const int UPDATE_INTERVAL = 1000; //1 second interval - static wxLongLong lastExec = 0; - const wxLongLong newExec = wxGetLocalTimeMillis(); - + const wxLongLong newExec = wxGetLocalTimeMillis(); if (newExec - lastExec >= UPDATE_INTERVAL) { lastExec = newExec; - - for (std::map<Zstring, bool>::iterator i = availablility.begin(); i != availablility.end(); ++i) - if (FreeFileSync::dirExists(i->first) != i->second) //change in availability - { - if (i->second) //directory doesn't exist anymore: no reason to trigger the commandline! (sometimes triggered by ChangeNotifications anyway...) - i->second = false; //update value, so that dir-arrival will be detected next time - else //directory arrival: trigger commandline! - return true; - } + allExistingBuffer = std::find_if(dirList.begin(), dirList.end(), notExisting) == dirList.end(); } - return false; + return allExistingBuffer; } private: - std::map<Zstring, bool> availablility; //save avail. status for each directory, avoid double-entries + static bool notExisting(const Zstring& dirname) + { + return !FreeFileSync::dirExists(dirname); + } + + mutable wxLongLong lastExec; + mutable bool allExistingBuffer; + + std::set<Zstring> dirList; //save avail. directories, avoid double-entries }; -void RealtimeSync::waitForChanges(const std::vector<wxString>& dirNames, WaitCallback* statusHandler) +RealtimeSync::WaitResult RealtimeSync::waitForChanges(const std::vector<Zstring>& dirNames, WaitCallback* statusHandler) //throw(FileError) { - if (dirNames.empty()) //pathological case, but check is needed later - return; + if (dirNames.empty()) //pathological case, but check is needed nevertheless + throw FreeFileSync::FileError(_("At least one directory input field is empty.")); - //new: support for monitoring newly connected directories volumes (e.g.: USB-sticks) - NotifyDirectoryArrival monitorAvailability; + //detect when volumes are removed/are not available anymore + WatchDirectories dirWatcher; #ifdef FFS_WIN ChangeNotifications notifications; - for (std::vector<wxString>::const_iterator i = dirNames.begin(); i != dirNames.end(); ++i) + for (std::vector<Zstring>::const_iterator i = dirNames.begin(); i != dirNames.end(); ++i) { - const Zstring formattedDir = FreeFileSync::getFormattedDirectoryName(i->c_str()); + const Zstring formattedDir = FreeFileSync::getFormattedDirectoryName(*i); if (formattedDir.empty()) throw FreeFileSync::FileError(_("At least one directory input field is empty.")); - const bool isExisting = FreeFileSync::dirExists(formattedDir); - if (isExisting) + dirWatcher.addForMonitoring(formattedDir); + + const HANDLE rv = ::FindFirstChangeNotification( + FreeFileSync::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 HANDLE rv = ::FindFirstChangeNotification( - FreeFileSync::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 wxString errorMessage = wxString(_("Could not initialize directory monitoring:")) + wxT("\n\"") + *i + wxT("\""); - throw FreeFileSync::FileError(errorMessage + wxT("\n\n") + FreeFileSync::getLastErrorFormatted()); - } + if (::GetLastError() == ERROR_FILE_NOT_FOUND) //no need to check this condition any earlier! + return CHANGE_DIR_MISSING; - notifications.addHandle(rv); + const wxString errorMessage = wxString(_("Could not initialize directory monitoring:")) + wxT("\n\"") + zToWx(*i) + wxT("\""); + throw FreeFileSync::FileError(errorMessage + wxT("\n\n") + FreeFileSync::getLastErrorFormatted()); } - //else: we silently ignore this error: it may be that the directory becomes available later, e.g. if it is a USB-stick - monitorAvailability.addForMonitoring(formattedDir, isExisting); //all directories (including not yet existing) are relevant + notifications.addHandle(rv); } + if (notifications.getSize() == 0) + throw FreeFileSync::FileError(_("At least one directory input field is empty.")); + while (true) { //check for changes within directories: - if (notifications.getSize() > 0) - { - const DWORD rv = ::WaitForMultipleObjects( //NOTE: notifications.getArray() returns valid pointer, because it cannot be empty in this context - static_cast<DWORD>(notifications.getSize()), //__in DWORD nCount, - notifications.getArray(), //__in const HANDLE *lpHandles, - false, //__in BOOL bWaitAll, - UI_UPDATE_INTERVAL); //__in DWORD dwMilliseconds - if (WAIT_OBJECT_0 <= rv && rv < WAIT_OBJECT_0 + notifications.getSize()) - return; //directory change detected - else if (rv == WAIT_FAILED) - throw FreeFileSync::FileError(wxString(_("Error when monitoring directories.")) + wxT("\n\n") + FreeFileSync::getLastErrorFormatted()); - //else if (rv == WAIT_TIMEOUT) - } - - if (monitorAvailability.changeDetected()) //check for newly arrived devices: - return; + const DWORD rv = ::WaitForMultipleObjects( //NOTE: notifications.getArray() returns valid pointer, because it cannot be empty in this context + static_cast<DWORD>(notifications.getSize()), //__in DWORD nCount, + notifications.getArray(), //__in const HANDLE *lpHandles, + false, //__in BOOL bWaitAll, + UI_UPDATE_INTERVAL); //__in DWORD dwMilliseconds + if (WAIT_OBJECT_0 <= rv && rv < WAIT_OBJECT_0 + notifications.getSize()) + return CHANGE_DETECTED; //directory change detected + else if (rv == WAIT_FAILED) + throw FreeFileSync::FileError(wxString(_("Error when monitoring directories.")) + wxT("\n\n") + FreeFileSync::getLastErrorFormatted()); + //else if (rv == WAIT_TIMEOUT) + + if (!dirWatcher.allExisting()) //check for removed devices: + return CHANGE_DIR_MISSING; statusHandler->requestUiRefresh(); } @@ -395,24 +394,30 @@ void RealtimeSync::waitForChanges(const std::vector<wxString>& dirNames, WaitCal std::vector<std::string> fullDirList; //including subdirectories! //add all subdirectories - for (std::vector<wxString>::const_iterator i = dirNames.begin(); i != dirNames.end(); ++i) + for (std::vector<Zstring>::const_iterator i = dirNames.begin(); i != dirNames.end(); ++i) { - const Zstring formattedDir = FreeFileSync::getFormattedDirectoryName(wxToZ(*i)); + const Zstring formattedDir = FreeFileSync::getFormattedDirectoryName(*i); if (formattedDir.empty()) throw FreeFileSync::FileError(_("At least one directory input field is empty.")); - const bool isExisting = FreeFileSync::dirExists(formattedDir); - if (isExisting) + dirWatcher.addForMonitoring(formattedDir); + + + fullDirList.push_back(formattedDir.c_str()); + + try //get all subdirectories { - fullDirList.push_back(formattedDir.c_str()); - //get all subdirectories DirsOnlyTraverser traverser(fullDirList); - FreeFileSync::traverseFolder(formattedDir, false, &traverser); //don't traverse into symlinks (analog to windows build) + FreeFileSync::traverseFolder(formattedDir, &traverser); //don't traverse into symlinks (analog to windows build) } - //else: we silently ignore this error: it may be that the directory becomes available later, e.g. if it is a USB-stick + catch (const FreeFileSync::FileError&) + { + if (!FreeFileSync::dirExists(formattedDir)) //that's no good locking behavior, but better than nothing + return CHANGE_DIR_MISSING; - monitorAvailability.addForMonitoring(formattedDir, isExisting); //all directories (including not yet existing) are relevant + throw; + } } try @@ -439,21 +444,27 @@ void RealtimeSync::waitForChanges(const std::vector<wxString>& dirNames, WaitCal } catch (const InotifyException& e) { + if (!FreeFileSync::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 FreeFileSync::FileError(errorMessage + wxT("\n\n") + zToWx(e.GetMessage().c_str())); } } + if (notifications.GetWatchCount() == 0) + throw FreeFileSync::FileError(_("At least one directory input field is empty.")); + while (true) { notifications.WaitForEvents(); //called in non-blocking mode if (notifications.GetEventCount() > 0) - return; //directory change detected + return CHANGE_DETECTED; //directory change detected - if (monitorAvailability.changeDetected()) //check for newly arrived devices: - return; + if (!dirWatcher.allExisting()) //check for removed devices: + return CHANGE_DIR_MISSING; wxMilliSleep(RealtimeSync::UI_UPDATE_INTERVAL); statusHandler->requestUiRefresh(); @@ -470,3 +481,28 @@ void RealtimeSync::waitForChanges(const std::vector<wxString>& dirNames, WaitCal #endif } + +void RealtimeSync::waitForMissingDirs(const std::vector<Zstring>& dirNames, WaitCallback* statusHandler) //throw(FileError) +{ + //new: support for monitoring newly connected directories volumes (e.g.: USB-sticks) + WatchDirectories dirWatcher; + + for (std::vector<Zstring>::const_iterator i = dirNames.begin(); i != dirNames.end(); ++i) + { + const Zstring formattedDir = FreeFileSync::getFormattedDirectoryName(*i); + + if (formattedDir.empty()) + throw FreeFileSync::FileError(_("At least one directory input field is empty.")); + + dirWatcher.addForMonitoring(formattedDir); + } + + while (true) + { + if (dirWatcher.allExisting()) //check for newly arrived devices: + return; + + wxMilliSleep(RealtimeSync::UI_UPDATE_INTERVAL); + statusHandler->requestUiRefresh(); + } +} diff --git a/RealtimeSync/watcher.h b/RealtimeSync/watcher.h index 58b20d99..c0690c33 100644 --- a/RealtimeSync/watcher.h +++ b/RealtimeSync/watcher.h @@ -7,7 +7,7 @@ #ifndef WATCHER_H_INCLUDED #define WATCHER_H_INCLUDED -#include "functions.h" +#include "../shared/zstring.h" #include <vector> #include "../shared/fileError.h" @@ -26,7 +26,17 @@ public: virtual void requestUiRefresh() = 0; //opportunity to abort must be implemented in a frequently executed method like requestUiRefresh() }; -void waitForChanges(const std::vector<wxString>& dirNames, WaitCallback* statusHandler); //throw(FreeFileSync::FileError); + +//wait until changes are detected or if a directory is not available (anymore) +enum WaitResult +{ + CHANGE_DETECTED, + CHANGE_DIR_MISSING + }; +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) } #endif // WATCHER_H_INCLUDED diff --git a/RealtimeSync/xmlProcessing.h b/RealtimeSync/xmlProcessing.h index f50849b1..bcfcf8f2 100644 --- a/RealtimeSync/xmlProcessing.h +++ b/RealtimeSync/xmlProcessing.h @@ -19,7 +19,7 @@ struct XmlRealConfig XmlRealConfig() : delay(5) {} std::vector<wxString> directories; wxString commandline; - unsigned int delay; + size_t delay; }; void readRealConfig(const wxString& filename, XmlRealConfig& config); //throw (xmlAccess::XmlError); |