1*f09fa651SNicolas Bonnefon #ifndef WINWATCHTOWERDRIVER_H 2*f09fa651SNicolas Bonnefon #define WINWATCHTOWERDRIVER_H 3*f09fa651SNicolas Bonnefon 4*f09fa651SNicolas Bonnefon #include <atomic> 5*f09fa651SNicolas Bonnefon #include <thread> 6*f09fa651SNicolas Bonnefon #include <mutex> 7*f09fa651SNicolas Bonnefon #include <condition_variable> 8*f09fa651SNicolas Bonnefon #include <iterator> 9*f09fa651SNicolas Bonnefon #include <vector> 10*f09fa651SNicolas Bonnefon 11*f09fa651SNicolas Bonnefon #define WIN32_LEAN_AND_MEAN 12*f09fa651SNicolas Bonnefon #include <windows.h> 13*f09fa651SNicolas Bonnefon 14*f09fa651SNicolas Bonnefon // Utility class 15*f09fa651SNicolas Bonnefon 16*f09fa651SNicolas Bonnefon // Encapsulate a directory notification returned by Windows' 17*f09fa651SNicolas Bonnefon // ReadDirectoryChangesW. 18*f09fa651SNicolas Bonnefon class WinNotificationInfo { 19*f09fa651SNicolas Bonnefon public: 20*f09fa651SNicolas Bonnefon enum class Action { UNDEF, 21*f09fa651SNicolas Bonnefon ADDED, 22*f09fa651SNicolas Bonnefon REMOVED, 23*f09fa651SNicolas Bonnefon MODIFIED, 24*f09fa651SNicolas Bonnefon RENAMED_OLD_NAME, 25*f09fa651SNicolas Bonnefon RENAMED_NEW_NAME }; 26*f09fa651SNicolas Bonnefon 27*f09fa651SNicolas Bonnefon WinNotificationInfo() { action_ = Action::UNDEF; } 28*f09fa651SNicolas Bonnefon WinNotificationInfo( Action action, std::wstring file_name ) 29*f09fa651SNicolas Bonnefon { action_ = action; file_name_ = file_name; } 30*f09fa651SNicolas Bonnefon 31*f09fa651SNicolas Bonnefon Action action() const { return action_; } 32*f09fa651SNicolas Bonnefon std::wstring fileName() const { return file_name_; } 33*f09fa651SNicolas Bonnefon 34*f09fa651SNicolas Bonnefon private: 35*f09fa651SNicolas Bonnefon Action action_; 36*f09fa651SNicolas Bonnefon std::wstring file_name_; 37*f09fa651SNicolas Bonnefon }; 38*f09fa651SNicolas Bonnefon 39*f09fa651SNicolas Bonnefon class WinNotificationInfoList { 40*f09fa651SNicolas Bonnefon public: 41*f09fa651SNicolas Bonnefon WinNotificationInfoList( const char* buffer, size_t buffer_size ); 42*f09fa651SNicolas Bonnefon 43*f09fa651SNicolas Bonnefon // Iterator 44*f09fa651SNicolas Bonnefon class iterator : std::iterator<std::input_iterator_tag, WinNotificationInfo> { 45*f09fa651SNicolas Bonnefon public: 46*f09fa651SNicolas Bonnefon iterator( WinNotificationInfoList* list, const char* position ) 47*f09fa651SNicolas Bonnefon { list_ = list; position_ = position; } 48*f09fa651SNicolas Bonnefon 49*f09fa651SNicolas Bonnefon const WinNotificationInfo& operator*() const 50*f09fa651SNicolas Bonnefon { return list_->current_notification_; } 51*f09fa651SNicolas Bonnefon 52*f09fa651SNicolas Bonnefon const WinNotificationInfo* operator->() const 53*f09fa651SNicolas Bonnefon { return &( list_->current_notification_ ); } 54*f09fa651SNicolas Bonnefon 55*f09fa651SNicolas Bonnefon const WinNotificationInfo& operator++() { 56*f09fa651SNicolas Bonnefon position_ = list_->advanceToNext(); 57*f09fa651SNicolas Bonnefon return list_->current_notification_; 58*f09fa651SNicolas Bonnefon } 59*f09fa651SNicolas Bonnefon 60*f09fa651SNicolas Bonnefon WinNotificationInfo operator++( int ) { 61*f09fa651SNicolas Bonnefon WinNotificationInfo tmp { list_->current_notification_ }; 62*f09fa651SNicolas Bonnefon operator++(); 63*f09fa651SNicolas Bonnefon return tmp; 64*f09fa651SNicolas Bonnefon } 65*f09fa651SNicolas Bonnefon 66*f09fa651SNicolas Bonnefon bool operator!=( const iterator& other ) const { 67*f09fa651SNicolas Bonnefon return ( list_ != other.list_ ) || ( position_ != other.position_ ); 68*f09fa651SNicolas Bonnefon } 69*f09fa651SNicolas Bonnefon 70*f09fa651SNicolas Bonnefon private: 71*f09fa651SNicolas Bonnefon WinNotificationInfoList* list_; 72*f09fa651SNicolas Bonnefon const char* position_; 73*f09fa651SNicolas Bonnefon }; 74*f09fa651SNicolas Bonnefon 75*f09fa651SNicolas Bonnefon iterator begin() { return iterator( this, pointer_ ); } 76*f09fa651SNicolas Bonnefon iterator end() { return iterator( this, nullptr ); } 77*f09fa651SNicolas Bonnefon 78*f09fa651SNicolas Bonnefon private: 79*f09fa651SNicolas Bonnefon const char* advanceToNext(); 80*f09fa651SNicolas Bonnefon 81*f09fa651SNicolas Bonnefon // Current notification (in the byte stream) 82*f09fa651SNicolas Bonnefon const char* pointer_; 83*f09fa651SNicolas Bonnefon // Next notification (in the byte stream) 84*f09fa651SNicolas Bonnefon const char* next_; 85*f09fa651SNicolas Bonnefon WinNotificationInfo current_notification_; 86*f09fa651SNicolas Bonnefon 87*f09fa651SNicolas Bonnefon const char* updateCurrentNotification( const char* new_position ); 88*f09fa651SNicolas Bonnefon }; 89*f09fa651SNicolas Bonnefon 90*f09fa651SNicolas Bonnefon template <typename Driver> 91*f09fa651SNicolas Bonnefon class ObservedFile; 92*f09fa651SNicolas Bonnefon template <typename Driver> 93*f09fa651SNicolas Bonnefon class ObservedFileList; 94*f09fa651SNicolas Bonnefon 95*f09fa651SNicolas Bonnefon class WinWatchTowerDriver { 96*f09fa651SNicolas Bonnefon public: 97*f09fa651SNicolas Bonnefon struct WinWatchedDirRecord { 98*f09fa651SNicolas Bonnefon WinWatchedDirRecord( const std::string& file_name ) 99*f09fa651SNicolas Bonnefon : path_( file_name ) { } 100*f09fa651SNicolas Bonnefon 101*f09fa651SNicolas Bonnefon static const int READ_DIR_CHANGE_BUFFER_SIZE = 4096; 102*f09fa651SNicolas Bonnefon 103*f09fa651SNicolas Bonnefon std::string path_; 104*f09fa651SNicolas Bonnefon void* handle_ = nullptr; 105*f09fa651SNicolas Bonnefon static const unsigned long buffer_length_ = READ_DIR_CHANGE_BUFFER_SIZE; 106*f09fa651SNicolas Bonnefon char buffer_[buffer_length_]; 107*f09fa651SNicolas Bonnefon }; 108*f09fa651SNicolas Bonnefon 109*f09fa651SNicolas Bonnefon class FileId { }; 110*f09fa651SNicolas Bonnefon class SymlinkId { }; 111*f09fa651SNicolas Bonnefon class DirId { 112*f09fa651SNicolas Bonnefon public: 113*f09fa651SNicolas Bonnefon friend class WinWatchTowerDriver; 114*f09fa651SNicolas Bonnefon 115*f09fa651SNicolas Bonnefon DirId() {} 116*f09fa651SNicolas Bonnefon bool operator==( const DirId& other ) const 117*f09fa651SNicolas Bonnefon { return dir_record_ == other.dir_record_; } 118*f09fa651SNicolas Bonnefon private: 119*f09fa651SNicolas Bonnefon std::shared_ptr<WinWatchedDirRecord> dir_record_; 120*f09fa651SNicolas Bonnefon }; 121*f09fa651SNicolas Bonnefon 122*f09fa651SNicolas Bonnefon // Default constructor 123*f09fa651SNicolas Bonnefon WinWatchTowerDriver(); 124*f09fa651SNicolas Bonnefon ~WinWatchTowerDriver(); 125*f09fa651SNicolas Bonnefon 126*f09fa651SNicolas Bonnefon FileId addFile( const std::string& file_name ); 127*f09fa651SNicolas Bonnefon SymlinkId addSymlink( const std::string& file_name ); 128*f09fa651SNicolas Bonnefon DirId addDir( const std::string& file_name ); 129*f09fa651SNicolas Bonnefon 130*f09fa651SNicolas Bonnefon void removeFile( const FileId& file_id ); 131*f09fa651SNicolas Bonnefon void removeSymlink( const SymlinkId& symlink_id ); 132*f09fa651SNicolas Bonnefon 133*f09fa651SNicolas Bonnefon std::vector<ObservedFile<WinWatchTowerDriver>*> waitAndProcessEvents( 134*f09fa651SNicolas Bonnefon ObservedFileList<WinWatchTowerDriver>* list, 135*f09fa651SNicolas Bonnefon std::mutex* list_mutex ); 136*f09fa651SNicolas Bonnefon 137*f09fa651SNicolas Bonnefon void interruptWait(); 138*f09fa651SNicolas Bonnefon 139*f09fa651SNicolas Bonnefon private: 140*f09fa651SNicolas Bonnefon // An action which will be picked up by the worker thread. 141*f09fa651SNicolas Bonnefon class Action { 142*f09fa651SNicolas Bonnefon public: 143*f09fa651SNicolas Bonnefon Action( std::function<void()> function ) : function_ { function } {} 144*f09fa651SNicolas Bonnefon ~Action() {} 145*f09fa651SNicolas Bonnefon 146*f09fa651SNicolas Bonnefon void operator()() { function_(); } 147*f09fa651SNicolas Bonnefon 148*f09fa651SNicolas Bonnefon private: 149*f09fa651SNicolas Bonnefon std::function<void()> function_; 150*f09fa651SNicolas Bonnefon }; 151*f09fa651SNicolas Bonnefon 152*f09fa651SNicolas Bonnefon // Action 153*f09fa651SNicolas Bonnefon std::mutex action_mutex_; 154*f09fa651SNicolas Bonnefon std::condition_variable action_done_cv_; 155*f09fa651SNicolas Bonnefon std::unique_ptr<Action> scheduled_action_ = nullptr; 156*f09fa651SNicolas Bonnefon 157*f09fa651SNicolas Bonnefon // Win32 notification variables 158*f09fa651SNicolas Bonnefon HANDLE hCompPort_; 159*f09fa651SNicolas Bonnefon OVERLAPPED overlapped_; 160*f09fa651SNicolas Bonnefon unsigned long buffer_length_; 161*f09fa651SNicolas Bonnefon 162*f09fa651SNicolas Bonnefon // List of directory records 163*f09fa651SNicolas Bonnefon // Accessed exclusively in the worker thread context 164*f09fa651SNicolas Bonnefon std::vector<std::weak_ptr<WinWatchedDirRecord>> dir_records_ { }; 165*f09fa651SNicolas Bonnefon 166*f09fa651SNicolas Bonnefon // Private member functions 167*f09fa651SNicolas Bonnefon void serialisedAddDir( 168*f09fa651SNicolas Bonnefon const std::string& file_name, 169*f09fa651SNicolas Bonnefon DirId& dir_id ); 170*f09fa651SNicolas Bonnefon }; 171*f09fa651SNicolas Bonnefon 172*f09fa651SNicolas Bonnefon #endif 173