aboutsummaryrefslogtreecommitdiffstats
path: root/contrib/libs/poco/Foundation/include/Poco/DirectoryWatcher.h
blob: 6e3a492fd593116a5a220453815c62797345fbae (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
//
// DirectoryWatcher.h
//
// Library: Foundation
// Package: Filesystem
// Module:  DirectoryWatcher
//
// Definition of the DirectoryWatcher class.
//
// Copyright (c) 2012, Applied Informatics Software Engineering GmbH.
// and Contributors.
//
// SPDX-License-Identifier:	BSL-1.0
//


#ifndef Foundation_DirectoryWatcher_INCLUDED
#define Foundation_DirectoryWatcher_INCLUDED


#include "Poco/Foundation.h"


#ifndef POCO_NO_INOTIFY


#include "Poco/File.h"
#include "Poco/BasicEvent.h"
#include "Poco/Runnable.h"
#include "Poco/Thread.h"
#include "Poco/AtomicCounter.h"


namespace Poco {


class DirectoryWatcherStrategy;


class Foundation_API DirectoryWatcher: protected Runnable
	/// This class is used to get notifications about changes
	/// to the filesystem, more specifically, to a specific
	/// directory. Changes to a directory are reported via
	/// events.
	///
	/// A thread will be created that watches the specified
	/// directory for changes. Events are reported in the context
	/// of this thread. 
	///
	/// Note that changes to files in subdirectories of the watched
	/// directory are not reported. Separate DirectoryWatcher objects
	/// must be created for these directories if they should be watched.
	///
	/// Changes to file attributes are not reported.
	///
	/// On Windows, this class is implemented using FindFirstChangeNotification()/FindNextChangeNotification().
	/// On Linux, this class is implemented using inotify.
	/// On FreeBSD and Darwin (Mac OS X, iOS), this class uses kevent/kqueue.
	/// On all other platforms, the watched directory is periodically scanned
	/// for changes. This can negatively affect performance if done too often.
	/// Therefore, the interval in which scans are done can be specified in
	/// the constructor. Note that periodic scanning will also be done on FreeBSD
	/// and Darwin if events for changes to files (DW_ITEM_MODIFIED) are enabled.
	///
	/// DW_ITEM_MOVED_FROM and DW_ITEM_MOVED_TO events will only be reported
	/// on Linux. On other platforms, a file rename or move operation
	/// will be reported via a DW_ITEM_REMOVED and a DW_ITEM_ADDED event.
	/// The order of these two events is not defined.
	///
	/// An event mask can be specified to enable only certain events.
{
public:
	enum DirectoryEventType
	{
		DW_ITEM_ADDED = 1,
			/// A new item has been created and added to the directory.
			
		DW_ITEM_REMOVED = 2,
			/// An item has been removed from the directory.

		DW_ITEM_MODIFIED = 4,
			/// An item has been modified.

		DW_ITEM_MOVED_FROM = 8,
			/// An item has been renamed or moved. This event delivers the old name.

		DW_ITEM_MOVED_TO = 16
			/// An item has been renamed or moved. This event delivers the new name.
	};

	enum DirectoryEventMask
	{
		DW_FILTER_ENABLE_ALL = 31,
			/// Enables all event types.

		DW_FILTER_DISABLE_ALL = 0
			/// Disables all event types.
	};
	
	enum
	{
		DW_DEFAULT_SCAN_INTERVAL = 5 /// Default scan interval for platforms that don't provide a native notification mechanism.
	};
	
	struct DirectoryEvent
	{
		DirectoryEvent(const File& f, DirectoryEventType ev):
			item(f),
			event(ev)
		{
		}

		const File& item;          /// The directory or file that has been changed.
		DirectoryEventType event;  /// The kind of event.
	};
	
	BasicEvent<const DirectoryEvent> itemAdded;
		/// Fired when a file or directory has been created or added to the directory.
		
	BasicEvent<const DirectoryEvent> itemRemoved;
		/// Fired when a file or directory has been removed from the directory.
		
	BasicEvent<const DirectoryEvent> itemModified;
		/// Fired when a file or directory has been modified.

	BasicEvent<const DirectoryEvent> itemMovedFrom;
		/// Fired when a file or directory has been renamed. This event delivers the old name.

	BasicEvent<const DirectoryEvent> itemMovedTo;
		/// Fired when a file or directory has been moved. This event delivers the new name.
		
	BasicEvent<const Exception> scanError;
		/// Fired when an error occurs while scanning for changes.
	
	DirectoryWatcher(const std::string& path, int eventMask = DW_FILTER_ENABLE_ALL, int scanInterval = DW_DEFAULT_SCAN_INTERVAL);
		/// Creates a DirectoryWatcher for the directory given in path.
		/// To enable only specific events, an eventMask can be specified by
		/// OR-ing the desired event IDs (e.g., DW_ITEM_ADDED | DW_ITEM_MODIFIED).
		/// On platforms where no native filesystem notifications are available,
		/// scanInterval specifies the interval in seconds between scans
		/// of the directory.
		
	DirectoryWatcher(const File& directory, int eventMask = DW_FILTER_ENABLE_ALL, int scanInterval = DW_DEFAULT_SCAN_INTERVAL);
		/// Creates a DirectoryWatcher for the specified directory
		/// To enable only specific events, an eventMask can be specified by
		/// OR-ing the desired event IDs (e.g., DW_ITEM_ADDED | DW_ITEM_MODIFIED).
		/// On platforms where no native filesystem notifications are available,
		/// scanInterval specifies the interval in seconds between scans
		/// of the directory.

	~DirectoryWatcher();
		/// Destroys the DirectoryWatcher.
		
	void suspendEvents();
		/// Suspends sending of events. Can be called multiple times, but every
		/// call to suspendEvent() must be matched by a call to resumeEvents().
		
	void resumeEvents();
		/// Resumes events, after they have been suspended with a call to suspendEvents().
		
	bool eventsSuspended() const;
		/// Returns true iff events are suspended.
		
	int eventMask() const;
		/// Returns the value of the eventMask passed to the constructor.
		
	int scanInterval() const;
		/// Returns the scan interval in seconds.
		
	const File& directory() const;
		/// Returns the directory being watched.
		
	bool supportsMoveEvents() const;
		/// Returns true iff the platform supports DW_ITEM_MOVED_FROM/itemMovedFrom and
		/// DW_ITEM_MOVED_TO/itemMovedTo events.
	
protected:
	void init();
	void stop();
	void run();

private:
	DirectoryWatcher();
	DirectoryWatcher(const DirectoryWatcher&);
	DirectoryWatcher& operator = (const DirectoryWatcher&);

	Thread _thread;
	File _directory;
	int _eventMask;
	AtomicCounter _eventsSuspended;
	int _scanInterval;
	DirectoryWatcherStrategy* _pStrategy;
};


//
// inlines
//


inline bool DirectoryWatcher::eventsSuspended() const
{
	return _eventsSuspended.value() > 0;
}


inline int DirectoryWatcher::eventMask() const
{
	return _eventMask;
}


inline int DirectoryWatcher::scanInterval() const
{
	return _scanInterval;
}


inline const File& DirectoryWatcher::directory() const
{
	return _directory;
}


} // namespace Poco


#endif // POCO_NO_INOTIFY


#endif // Foundation_DirectoryWatcher_INCLUDED