xref: /glogg/src/winwatchtowerdriver.h (revision 8b11848fd9995077713535870cee0df00a8eeea0)
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