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