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