1//
2// DirectoryWatcher.h
3//
4// Library: Foundation
5// Package: Filesystem
6// Module: DirectoryWatcher
7//
8// Definition of the DirectoryWatcher class.
9//
10// Copyright (c) 2012, Applied Informatics Software Engineering GmbH.
11// and Contributors.
12//
13// SPDX-License-Identifier: BSL-1.0
14//
15
16
17#ifndef Foundation_DirectoryWatcher_INCLUDED
18#define Foundation_DirectoryWatcher_INCLUDED
19
20
21#include "Poco/Foundation.h"
22
23
24#ifndef POCO_NO_INOTIFY
25
26
27#include "Poco/File.h"
28#include "Poco/BasicEvent.h"
29#include "Poco/Runnable.h"
30#include "Poco/Thread.h"
31#include "Poco/AtomicCounter.h"
32
33
34namespace Poco {
35
36
37class DirectoryWatcherStrategy;
38
39
40class Foundation_API DirectoryWatcher: protected Runnable
41 /// This class is used to get notifications about changes
42 /// to the filesystem, more specifically, to a specific
43 /// directory. Changes to a directory are reported via
44 /// events.
45 ///
46 /// A thread will be created that watches the specified
47 /// directory for changes. Events are reported in the context
48 /// of this thread.
49 ///
50 /// Note that changes to files in subdirectories of the watched
51 /// directory are not reported. Separate DirectoryWatcher objects
52 /// must be created for these directories if they should be watched.
53 ///
54 /// Changes to file attributes are not reported.
55 ///
56 /// On Windows, this class is implemented using FindFirstChangeNotification()/FindNextChangeNotification().
57 /// On Linux, this class is implemented using inotify.
58 /// On FreeBSD and Darwin (Mac OS X, iOS), this class uses kevent/kqueue.
59 /// On all other platforms, the watched directory is periodically scanned
60 /// for changes. This can negatively affect performance if done too often.
61 /// Therefore, the interval in which scans are done can be specified in
62 /// the constructor. Note that periodic scanning will also be done on FreeBSD
63 /// and Darwin if events for changes to files (DW_ITEM_MODIFIED) are enabled.
64 /// To avoid problems (e.g. with network shares notifications), scanning
65 /// can be forced as the only mechanism, regardless of platform default.
66 ///
67 /// DW_ITEM_MOVED_FROM and DW_ITEM_MOVED_TO events will only be reported
68 /// on Linux. On other platforms, a file rename or move operation
69 /// will be reported via a DW_ITEM_REMOVED and a DW_ITEM_ADDED event.
70 /// The order of these two events is not defined.
71 ///
72 /// An event mask can be specified to enable only certain events.
73{
74public:
75 enum DirectoryEventType
76 {
77 DW_ITEM_ADDED = 1,
78 /// A new item has been created and added to the directory.
79
80 DW_ITEM_REMOVED = 2,
81 /// An item has been removed from the directory.
82
83 DW_ITEM_MODIFIED = 4,
84 /// An item has been modified.
85
86 DW_ITEM_MOVED_FROM = 8,
87 /// An item has been renamed or moved. This event delivers the old name.
88
89 DW_ITEM_MOVED_TO = 16
90 /// An item has been renamed or moved. This event delivers the new name.
91 };
92
93 enum DirectoryEventMask
94 {
95 DW_FILTER_ENABLE_ALL = 31,
96 /// Enables all event types.
97
98 DW_FILTER_DISABLE_ALL = 0
99 /// Disables all event types.
100 };
101
102 enum
103 {
104 DW_DEFAULT_SCAN_INTERVAL = 5 /// Default scan interval for platforms that don't provide a native notification mechanism.
105 };
106
107 struct DirectoryEvent
108 {
109 DirectoryEvent(const File& f, DirectoryEventType ev):
110 item(f),
111 event(ev)
112 {
113 }
114
115 const File& item; /// The directory or file that has been changed.
116 DirectoryEventType event; /// The kind of event.
117 };
118
119 BasicEvent<const DirectoryEvent> itemAdded;
120 /// Fired when a file or directory has been created or added to the directory.
121
122 BasicEvent<const DirectoryEvent> itemRemoved;
123 /// Fired when a file or directory has been removed from the directory.
124
125 BasicEvent<const DirectoryEvent> itemModified;
126 /// Fired when a file or directory has been modified.
127
128 BasicEvent<const DirectoryEvent> itemMovedFrom;
129 /// Fired when a file or directory has been renamed. This event delivers the old name.
130
131 BasicEvent<const DirectoryEvent> itemMovedTo;
132 /// Fired when a file or directory has been moved. This event delivers the new name.
133
134 BasicEvent<const Exception> scanError;
135 /// Fired when an error occurs while scanning for changes.
136
137 DirectoryWatcher(const std::string& path,
138 int eventMask = DW_FILTER_ENABLE_ALL,
139 int scanInterval = DW_DEFAULT_SCAN_INTERVAL,
140 bool forceScan = false);
141 /// Creates a DirectoryWatcher for the directory given in path.
142 /// To enable only specific events, an eventMask can be specified by
143 /// OR-ing the desired event IDs (e.g., DW_ITEM_ADDED | DW_ITEM_MODIFIED).
144 /// On platforms where no native filesystem notifications are available,
145 /// scanInterval specifies the interval in seconds between scans
146 /// of the directory. Native notification mechanism can also be disabled
147 /// (i.e. replaced with scanning) by setting forceScan to true.
148
149 DirectoryWatcher(const File& directory,
150 int eventMask = DW_FILTER_ENABLE_ALL,
151 int scanInterval = DW_DEFAULT_SCAN_INTERVAL,
152 bool forceScan = false);
153 /// Creates a DirectoryWatcher for the specified directory
154 /// To enable only specific events, an eventMask can be specified by
155 /// OR-ing the desired event IDs (e.g., DW_ITEM_ADDED | DW_ITEM_MODIFIED).
156 /// On platforms where no native filesystem notifications are available,
157 /// scanInterval specifies the interval in seconds between scans
158 /// of the directory. Native notification mechanism can also be disabled
159 /// (i.e. replaced with scanning) by setting forceScan to true.
160
161 ~DirectoryWatcher();
162 /// Destroys the DirectoryWatcher.
163
164 void suspendEvents();
165 /// Suspends sending of events. Can be called multiple times, but every
166 /// call to suspendEvent() must be matched by a call to resumeEvents().
167
168 void resumeEvents();
169 /// Resumes events, after they have been suspended with a call to suspendEvents().
170
171 bool eventsSuspended() const;
172 /// Returns true iff events are suspended.
173
174 int eventMask() const;
175 /// Returns the value of the eventMask passed to the constructor.
176
177 int scanInterval() const;
178 /// Returns the scan interval in seconds.
179
180 const File& directory() const;
181 /// Returns the directory being watched.
182
183 bool supportsMoveEvents() const;
184 /// Returns true iff the platform supports DW_ITEM_MOVED_FROM/itemMovedFrom and
185 /// DW_ITEM_MOVED_TO/itemMovedTo events.
186
187protected:
188 void init();
189 void stop();
190 void run();
191
192private:
193 DirectoryWatcher();
194 DirectoryWatcher(const DirectoryWatcher&);
195 DirectoryWatcher& operator = (const DirectoryWatcher&);
196
197 Thread _thread;
198 File _directory;
199 int _eventMask;
200 AtomicCounter _eventsSuspended;
201 int _scanInterval;
202 bool _forceScan;
203 DirectoryWatcherStrategy* _pStrategy;
204};
205
206
207//
208// inlines
209//
210
211
212inline bool DirectoryWatcher::eventsSuspended() const
213{
214 return _eventsSuspended.value() > 0;
215}
216
217
218inline int DirectoryWatcher::eventMask() const
219{
220 return _eventMask;
221}
222
223
224inline int DirectoryWatcher::scanInterval() const
225{
226 return _scanInterval;
227}
228
229
230inline const File& DirectoryWatcher::directory() const
231{
232 return _directory;
233}
234
235
236} // namespace Poco
237
238
239#endif // POCO_NO_INOTIFY
240
241
242#endif // Foundation_DirectoryWatcher_INCLUDED
243
244