1c540156cSNicolas Bonnefon #ifndef WATCHTOWERLIST_H
2c540156cSNicolas Bonnefon #define WATCHTOWERLIST_H
3c540156cSNicolas Bonnefon
4c540156cSNicolas Bonnefon // Utility classes for the WatchTower implementations
5c540156cSNicolas Bonnefon
6c540156cSNicolas Bonnefon #include <functional>
7c540156cSNicolas Bonnefon #include <string>
8c540156cSNicolas Bonnefon #include <vector>
9c540156cSNicolas Bonnefon #include <map>
10c540156cSNicolas Bonnefon #include <list>
11c540156cSNicolas Bonnefon #include <memory>
12c540156cSNicolas Bonnefon #include <algorithm>
13fcaa7557SNicolas Bonnefon #include <chrono>
14c540156cSNicolas Bonnefon
15f09fa651SNicolas Bonnefon #include "log.h"
16b278d183SNicolas Bonnefon
17c540156cSNicolas Bonnefon // Utility classes
18c540156cSNicolas Bonnefon struct ProtocolInfo {
19c540156cSNicolas Bonnefon // Win32 notification variables
20c540156cSNicolas Bonnefon static const int READ_DIR_CHANGE_BUFFER_SIZE = 4096;
21c540156cSNicolas Bonnefon
22c540156cSNicolas Bonnefon void* handle_;
23c540156cSNicolas Bonnefon static const unsigned long buffer_length_ = READ_DIR_CHANGE_BUFFER_SIZE;
24c540156cSNicolas Bonnefon char buffer_[buffer_length_];
25c540156cSNicolas Bonnefon };
26c540156cSNicolas Bonnefon
27c540156cSNicolas Bonnefon // List of files and observers
28f09fa651SNicolas Bonnefon template <typename Driver>
29c540156cSNicolas Bonnefon struct ObservedDir {
ObservedDirObservedDir30c540156cSNicolas Bonnefon ObservedDir( const std::string this_path ) : path { this_path } {}
31c540156cSNicolas Bonnefon
32c540156cSNicolas Bonnefon // Returns the address of the protocol specific informations
protocolInfoObservedDir33c540156cSNicolas Bonnefon ProtocolInfo* protocolInfo() { return &protocol_info_; }
34c540156cSNicolas Bonnefon
35c540156cSNicolas Bonnefon std::string path;
36f09fa651SNicolas Bonnefon typename Driver::DirId dir_id_;
37c540156cSNicolas Bonnefon // Contains data specific to the protocol (inotify/Win32...)
38c540156cSNicolas Bonnefon ProtocolInfo protocol_info_;
39c540156cSNicolas Bonnefon };
40c540156cSNicolas Bonnefon
41f09fa651SNicolas Bonnefon template <typename Driver>
42c540156cSNicolas Bonnefon struct ObservedFile {
ObservedFileObservedFile43c540156cSNicolas Bonnefon ObservedFile(
44c540156cSNicolas Bonnefon const std::string& file_name,
45c540156cSNicolas Bonnefon std::shared_ptr<void> callback,
46f09fa651SNicolas Bonnefon typename Driver::FileId file_id,
47f09fa651SNicolas Bonnefon typename Driver::SymlinkId symlink_id )
48b278d183SNicolas Bonnefon : file_name_( file_name ) {
49c540156cSNicolas Bonnefon addCallback( callback );
50c540156cSNicolas Bonnefon
51b278d183SNicolas Bonnefon file_id_ = file_id;
52b278d183SNicolas Bonnefon symlink_id_ = symlink_id;
53c540156cSNicolas Bonnefon dir_ = nullptr;
54fcaa7557SNicolas Bonnefon
55fcaa7557SNicolas Bonnefon markAsChanged();
56c540156cSNicolas Bonnefon }
57c540156cSNicolas Bonnefon
addCallbackObservedFile58c540156cSNicolas Bonnefon void addCallback( std::shared_ptr<void> callback ) {
59c540156cSNicolas Bonnefon callbacks.push_back( callback );
60c540156cSNicolas Bonnefon }
61c540156cSNicolas Bonnefon
62fcaa7557SNicolas Bonnefon // Records the file has changed
markAsChangedObservedFile63fcaa7557SNicolas Bonnefon void markAsChanged() {
64fcaa7557SNicolas Bonnefon change_token_.readFromFile( file_name_ );
65fcaa7557SNicolas Bonnefon last_check_time_ = std::chrono::steady_clock::now();
66fcaa7557SNicolas Bonnefon }
67fcaa7557SNicolas Bonnefon
68fcaa7557SNicolas Bonnefon // Returns whether a file has changed
69fcaa7557SNicolas Bonnefon // (for polling)
hasChangedObservedFile70fcaa7557SNicolas Bonnefon bool hasChanged() {
71fcaa7557SNicolas Bonnefon typename Driver::FileChangeToken new_token( file_name_ );
72fcaa7557SNicolas Bonnefon last_check_time_ = std::chrono::steady_clock::now();
73fcaa7557SNicolas Bonnefon return change_token_ != new_token;
74fcaa7557SNicolas Bonnefon }
75fcaa7557SNicolas Bonnefon
timeForLastCheckObservedFile76fcaa7557SNicolas Bonnefon std::chrono::steady_clock::time_point timeForLastCheck() {
77fcaa7557SNicolas Bonnefon return last_check_time_;
78fcaa7557SNicolas Bonnefon }
79fcaa7557SNicolas Bonnefon
80c540156cSNicolas Bonnefon std::string file_name_;
81c540156cSNicolas Bonnefon // List of callbacks for this file
82c540156cSNicolas Bonnefon std::vector<std::shared_ptr<void>> callbacks;
83c540156cSNicolas Bonnefon
84c540156cSNicolas Bonnefon // watch descriptor for the file itself
85f09fa651SNicolas Bonnefon typename Driver::FileId file_id_;
86c540156cSNicolas Bonnefon // watch descriptor for the symlink (if file is a symlink)
87f09fa651SNicolas Bonnefon typename Driver::SymlinkId symlink_id_;
88c540156cSNicolas Bonnefon
89c540156cSNicolas Bonnefon // link to the dir containing the file
90f09fa651SNicolas Bonnefon std::shared_ptr<ObservedDir<Driver>> dir_;
91fcaa7557SNicolas Bonnefon
92fcaa7557SNicolas Bonnefon // token to identify modification
93fcaa7557SNicolas Bonnefon // (the token change when the file is modified, this is used when polling)
94fcaa7557SNicolas Bonnefon typename Driver::FileChangeToken change_token_;
95fcaa7557SNicolas Bonnefon
96fcaa7557SNicolas Bonnefon // Last time a check has been done
97fcaa7557SNicolas Bonnefon std::chrono::steady_clock::time_point last_check_time_ =
98fcaa7557SNicolas Bonnefon std::chrono::steady_clock::time_point::min();
99c540156cSNicolas Bonnefon };
100c540156cSNicolas Bonnefon
101c540156cSNicolas Bonnefon // A list of the observed files and directories
102c540156cSNicolas Bonnefon // This class is not thread safe
103f09fa651SNicolas Bonnefon template<typename Driver>
104c540156cSNicolas Bonnefon class ObservedFileList {
105c540156cSNicolas Bonnefon public:
ObservedFileList()1063104b268SNicolas Bonnefon ObservedFileList() :
107*5751f354SAlexander Hirsch // Use an empty deleter since we don't really own this.
108*5751f354SAlexander Hirsch heartBeat_ { this, [] (void*) {} }
1093104b268SNicolas Bonnefon { }
110*5751f354SAlexander Hirsch ObservedFileList( const ObservedFileList& ) = delete;
111c540156cSNicolas Bonnefon ~ObservedFileList() = default;
112c540156cSNicolas Bonnefon
1133104b268SNicolas Bonnefon // The functions return a pointer to the existing file (if exists)
1143104b268SNicolas Bonnefon // but keep ownership of the object.
115f09fa651SNicolas Bonnefon ObservedFile<Driver>* searchByName( const std::string& file_name );
116f09fa651SNicolas Bonnefon ObservedFile<Driver>* searchByFileOrSymlinkWd(
117f09fa651SNicolas Bonnefon typename Driver::FileId file_id,
118f09fa651SNicolas Bonnefon typename Driver::SymlinkId symlink_id );
119f09fa651SNicolas Bonnefon ObservedFile<Driver>* searchByDirWdAndName(
120f09fa651SNicolas Bonnefon typename Driver::DirId id, const char* name );
121933a5744SNicolas Bonnefon std::vector<ObservedFile<Driver>*> searchByDirWd(
122933a5744SNicolas Bonnefon typename Driver::DirId id );
123c540156cSNicolas Bonnefon
1243104b268SNicolas Bonnefon // Add a new file, the list returns a pointer to the added file,
1253104b268SNicolas Bonnefon // but has ownership of the file.
126f09fa651SNicolas Bonnefon ObservedFile<Driver>* addNewObservedFile( ObservedFile<Driver> new_observed );
127c540156cSNicolas Bonnefon // Remove a callback, remove and returns the file object if
128c540156cSNicolas Bonnefon // it was the last callback on this object, nullptr if not.
129c540156cSNicolas Bonnefon // The caller has ownership of the object.
130f09fa651SNicolas Bonnefon std::shared_ptr<ObservedFile<Driver>> removeCallback(
131c540156cSNicolas Bonnefon std::shared_ptr<void> callback );
132c540156cSNicolas Bonnefon
133c540156cSNicolas Bonnefon // Return the watched directory if it is watched, or nullptr
134f09fa651SNicolas Bonnefon std::shared_ptr<ObservedDir<Driver>> watchedDirectory( const std::string& dir_name );
1353104b268SNicolas Bonnefon // Create a new watched directory for dir_name, the client is passed
1363104b268SNicolas Bonnefon // shared ownership and have to keep the shared_ptr (the list only
1373104b268SNicolas Bonnefon // maintain a weak link).
1383104b268SNicolas Bonnefon // The remove notification is called just before the reference to
1393104b268SNicolas Bonnefon // the directory is destroyed.
1403104b268SNicolas Bonnefon std::shared_ptr<ObservedDir<Driver>> addWatchedDirectory(
1413104b268SNicolas Bonnefon const std::string& dir_name,
1423104b268SNicolas Bonnefon std::function<void( ObservedDir<Driver>* )> remove_notification );
143c540156cSNicolas Bonnefon
1443104b268SNicolas Bonnefon // Similar to previous functions but extract the name of the
1453104b268SNicolas Bonnefon // directory from the file name.
146f09fa651SNicolas Bonnefon std::shared_ptr<ObservedDir<Driver>> watchedDirectoryForFile( const std::string& file_name );
1473104b268SNicolas Bonnefon std::shared_ptr<ObservedDir<Driver>> addWatchedDirectoryForFile( const std::string& file_name,
1483104b268SNicolas Bonnefon std::function<void( ObservedDir<Driver>* )> remove_notification );
1493104b268SNicolas Bonnefon
1503104b268SNicolas Bonnefon // Removal of directories is done when there is no shared reference
1513104b268SNicolas Bonnefon // left (RAII)
1523104b268SNicolas Bonnefon
1533104b268SNicolas Bonnefon // Number of watched directories (for tests)
1543104b268SNicolas Bonnefon unsigned int numberWatchedDirectories() const;
155c540156cSNicolas Bonnefon
156fcaa7557SNicolas Bonnefon // Iterator
157fcaa7557SNicolas Bonnefon template<typename Container>
158fcaa7557SNicolas Bonnefon class iterator : std::iterator<std::input_iterator_tag, ObservedFile<Driver>> {
159fcaa7557SNicolas Bonnefon public:
iterator(Container * list,const typename Container::iterator & iter)160fcaa7557SNicolas Bonnefon iterator( Container* list,
161fcaa7557SNicolas Bonnefon const typename Container::iterator& iter )
162fcaa7557SNicolas Bonnefon { list_ = list; pos_ = iter; }
163fcaa7557SNicolas Bonnefon
164fcaa7557SNicolas Bonnefon iterator operator++()
165fcaa7557SNicolas Bonnefon { ++pos_; return *this; }
166fcaa7557SNicolas Bonnefon
167fcaa7557SNicolas Bonnefon bool operator==( const iterator& other )
168fcaa7557SNicolas Bonnefon { return ( pos_ == other.pos_ ); }
169fcaa7557SNicolas Bonnefon
170fcaa7557SNicolas Bonnefon bool operator!=( const iterator& other )
171fcaa7557SNicolas Bonnefon { return ! operator==( other ); }
172fcaa7557SNicolas Bonnefon
173fcaa7557SNicolas Bonnefon typename Container::iterator operator*()
174fcaa7557SNicolas Bonnefon { return pos_; }
175fcaa7557SNicolas Bonnefon
176fcaa7557SNicolas Bonnefon private:
177fcaa7557SNicolas Bonnefon Container* list_;
178fcaa7557SNicolas Bonnefon typename Container::iterator pos_;
179fcaa7557SNicolas Bonnefon };
180fcaa7557SNicolas Bonnefon
begin()181fcaa7557SNicolas Bonnefon iterator<std::list<ObservedFile<Driver>>> begin()
182fcaa7557SNicolas Bonnefon { return iterator<std::list<ObservedFile<Driver>>>( &observed_files_, observed_files_.begin() ); }
end()183fcaa7557SNicolas Bonnefon iterator<std::list<ObservedFile<Driver>>> end()
184fcaa7557SNicolas Bonnefon { return iterator<std::list<ObservedFile<Driver>>>( &observed_files_, observed_files_.end() ); }
185fcaa7557SNicolas Bonnefon
186c540156cSNicolas Bonnefon private:
187c540156cSNicolas Bonnefon // List of observed files
188f09fa651SNicolas Bonnefon std::list<ObservedFile<Driver>> observed_files_;
189c540156cSNicolas Bonnefon
190c540156cSNicolas Bonnefon // List of observed dirs, key-ed by name
191f09fa651SNicolas Bonnefon std::map<std::string, std::weak_ptr<ObservedDir<Driver>>> observed_dirs_;
192c540156cSNicolas Bonnefon
193c540156cSNicolas Bonnefon // Map the inotify file (including symlinks) wds to the observed file
194f09fa651SNicolas Bonnefon std::map<int, ObservedFile<Driver>*> by_file_wd_;
195c540156cSNicolas Bonnefon // Map the inotify directory wds to the observed files
196f09fa651SNicolas Bonnefon std::map<int, ObservedFile<Driver>*> by_dir_wd_;
1973104b268SNicolas Bonnefon
198*5751f354SAlexander Hirsch // A shared_ptr to self.
199*5751f354SAlexander Hirsch // weak_ptr's from this can check if the list is still alive.
200*5751f354SAlexander Hirsch // This probably shouldn't be copied.
201*5751f354SAlexander Hirsch std::shared_ptr<ObservedFileList> heartBeat_;
2023104b268SNicolas Bonnefon
2033104b268SNicolas Bonnefon // Clean all reference to any expired directory
2043104b268SNicolas Bonnefon void cleanRefsToExpiredDirs();
205c540156cSNicolas Bonnefon };
206c540156cSNicolas Bonnefon
207f09fa651SNicolas Bonnefon namespace {
208f09fa651SNicolas Bonnefon std::string directory_path( const std::string& path );
209f09fa651SNicolas Bonnefon };
210f09fa651SNicolas Bonnefon
211f09fa651SNicolas Bonnefon // ObservedFileList class
212f09fa651SNicolas Bonnefon template <typename Driver>
searchByName(const std::string & file_name)213f09fa651SNicolas Bonnefon ObservedFile<Driver>* ObservedFileList<Driver>::searchByName(
214f09fa651SNicolas Bonnefon const std::string& file_name )
215f09fa651SNicolas Bonnefon {
216f09fa651SNicolas Bonnefon // Look for an existing observer on this file
217f09fa651SNicolas Bonnefon auto existing_observer = observed_files_.begin();
218f09fa651SNicolas Bonnefon for ( ; existing_observer != observed_files_.end(); ++existing_observer )
219f09fa651SNicolas Bonnefon {
220f09fa651SNicolas Bonnefon if ( existing_observer->file_name_ == file_name )
221f09fa651SNicolas Bonnefon {
222f09fa651SNicolas Bonnefon LOG(logDEBUG) << "Found " << file_name;
223f09fa651SNicolas Bonnefon break;
224f09fa651SNicolas Bonnefon }
225f09fa651SNicolas Bonnefon }
226f09fa651SNicolas Bonnefon
227f09fa651SNicolas Bonnefon if ( existing_observer != observed_files_.end() )
228f09fa651SNicolas Bonnefon return &( *existing_observer );
229f09fa651SNicolas Bonnefon else
230f09fa651SNicolas Bonnefon return nullptr;
231f09fa651SNicolas Bonnefon }
232f09fa651SNicolas Bonnefon
233f09fa651SNicolas Bonnefon template <typename Driver>
searchByFileOrSymlinkWd(typename Driver::FileId file_id,typename Driver::SymlinkId symlink_id)234f09fa651SNicolas Bonnefon ObservedFile<Driver>* ObservedFileList<Driver>::searchByFileOrSymlinkWd(
235f09fa651SNicolas Bonnefon typename Driver::FileId file_id,
236f09fa651SNicolas Bonnefon typename Driver::SymlinkId symlink_id )
237f09fa651SNicolas Bonnefon {
238f09fa651SNicolas Bonnefon auto result = find_if( observed_files_.begin(), observed_files_.end(),
239f09fa651SNicolas Bonnefon [file_id, symlink_id] (ObservedFile<Driver> file) -> bool {
240f09fa651SNicolas Bonnefon return ( file_id == file.file_id_ ) ||
241f09fa651SNicolas Bonnefon ( symlink_id == file.symlink_id_ );
242f09fa651SNicolas Bonnefon } );
243f09fa651SNicolas Bonnefon
244f09fa651SNicolas Bonnefon if ( result != observed_files_.end() )
245f09fa651SNicolas Bonnefon return &( *result );
246f09fa651SNicolas Bonnefon else
247f09fa651SNicolas Bonnefon return nullptr;
248f09fa651SNicolas Bonnefon }
249f09fa651SNicolas Bonnefon
250f09fa651SNicolas Bonnefon template <typename Driver>
searchByDirWdAndName(typename Driver::DirId id,const char * name)251f09fa651SNicolas Bonnefon ObservedFile<Driver>* ObservedFileList<Driver>::searchByDirWdAndName(
252f09fa651SNicolas Bonnefon typename Driver::DirId id, const char* name )
253f09fa651SNicolas Bonnefon {
254f09fa651SNicolas Bonnefon auto dir = find_if( observed_dirs_.begin(), observed_dirs_.end(),
255f09fa651SNicolas Bonnefon [id] (std::pair<std::string,std::weak_ptr<ObservedDir<Driver>>> d) -> bool {
256f09fa651SNicolas Bonnefon if ( auto dir = d.second.lock() ) {
257f09fa651SNicolas Bonnefon return ( id == dir->dir_id_ );
258f09fa651SNicolas Bonnefon }
259f09fa651SNicolas Bonnefon else {
260f09fa651SNicolas Bonnefon return false; } } );
261f09fa651SNicolas Bonnefon
262f09fa651SNicolas Bonnefon if ( dir != observed_dirs_.end() ) {
263f09fa651SNicolas Bonnefon std::string path = dir->first + "/" + name;
264f09fa651SNicolas Bonnefon
265f09fa651SNicolas Bonnefon // LOG(logDEBUG) << "Testing path: " << path;
266f09fa651SNicolas Bonnefon
267f09fa651SNicolas Bonnefon // Looking for the path in the files we are watching
268f09fa651SNicolas Bonnefon return searchByName( path );
269f09fa651SNicolas Bonnefon }
270f09fa651SNicolas Bonnefon else {
271f09fa651SNicolas Bonnefon return nullptr;
272f09fa651SNicolas Bonnefon }
273f09fa651SNicolas Bonnefon }
274f09fa651SNicolas Bonnefon
275f09fa651SNicolas Bonnefon template <typename Driver>
searchByDirWd(typename Driver::DirId id)276933a5744SNicolas Bonnefon std::vector<ObservedFile<Driver>*> ObservedFileList<Driver>::searchByDirWd(
277933a5744SNicolas Bonnefon typename Driver::DirId id )
278933a5744SNicolas Bonnefon {
279933a5744SNicolas Bonnefon std::vector<ObservedFile<Driver>*> result;
280933a5744SNicolas Bonnefon
281933a5744SNicolas Bonnefon auto dir = find_if( observed_dirs_.begin(), observed_dirs_.end(),
282933a5744SNicolas Bonnefon [id] (std::pair<std::string,std::weak_ptr<ObservedDir<Driver>>> d) -> bool {
283933a5744SNicolas Bonnefon if ( auto dir = d.second.lock() ) {
284933a5744SNicolas Bonnefon return ( id == dir->dir_id_ );
285933a5744SNicolas Bonnefon }
286933a5744SNicolas Bonnefon else {
287933a5744SNicolas Bonnefon return false; } } );
288933a5744SNicolas Bonnefon
289933a5744SNicolas Bonnefon if ( dir != observed_dirs_.end() ) {
290933a5744SNicolas Bonnefon for ( auto i = observed_files_.begin(); i != observed_files_.end(); ++i ) {
291933a5744SNicolas Bonnefon if ( auto d = dir->second.lock() ) {
292933a5744SNicolas Bonnefon if ( d.get() == i->dir_.get() ) {
293933a5744SNicolas Bonnefon result.push_back( &(*i) );
294933a5744SNicolas Bonnefon }
295933a5744SNicolas Bonnefon }
296933a5744SNicolas Bonnefon }
297933a5744SNicolas Bonnefon }
298933a5744SNicolas Bonnefon
299933a5744SNicolas Bonnefon return result;
300933a5744SNicolas Bonnefon }
301933a5744SNicolas Bonnefon
302933a5744SNicolas Bonnefon template <typename Driver>
addNewObservedFile(ObservedFile<Driver> new_observed)303f09fa651SNicolas Bonnefon ObservedFile<Driver>* ObservedFileList<Driver>::addNewObservedFile(
304f09fa651SNicolas Bonnefon ObservedFile<Driver> new_observed )
305f09fa651SNicolas Bonnefon {
306f09fa651SNicolas Bonnefon auto new_file = observed_files_.insert( std::begin( observed_files_ ), new_observed );
307f09fa651SNicolas Bonnefon
308f09fa651SNicolas Bonnefon return &( *new_file );
309f09fa651SNicolas Bonnefon }
310f09fa651SNicolas Bonnefon
311f09fa651SNicolas Bonnefon template <typename Driver>
removeCallback(std::shared_ptr<void> callback)312f09fa651SNicolas Bonnefon std::shared_ptr<ObservedFile<Driver>> ObservedFileList<Driver>::removeCallback(
313f09fa651SNicolas Bonnefon std::shared_ptr<void> callback )
314f09fa651SNicolas Bonnefon {
315f09fa651SNicolas Bonnefon std::shared_ptr<ObservedFile<Driver>> returned_file = nullptr;
316f09fa651SNicolas Bonnefon
317fcaa7557SNicolas Bonnefon for ( auto observer = std::begin( observed_files_ );
318fcaa7557SNicolas Bonnefon observer != std::end( observed_files_ ); )
319f09fa651SNicolas Bonnefon {
320f09fa651SNicolas Bonnefon std::vector<std::shared_ptr<void>>& callbacks = observer->callbacks;
321f09fa651SNicolas Bonnefon callbacks.erase( std::remove(
322f09fa651SNicolas Bonnefon std::begin( callbacks ), std::end( callbacks ), callback ),
323f09fa651SNicolas Bonnefon std::end( callbacks ) );
324f09fa651SNicolas Bonnefon
325f09fa651SNicolas Bonnefon /* See if all notifications have been deleted for this file */
326f09fa651SNicolas Bonnefon if ( callbacks.empty() ) {
3273104b268SNicolas Bonnefon LOG(logDEBUG) << "Empty notification list for " << observer->file_name_
3283104b268SNicolas Bonnefon << ", removing the watched file";
329f09fa651SNicolas Bonnefon returned_file = std::make_shared<ObservedFile<Driver>>( *observer );
330f09fa651SNicolas Bonnefon observer = observed_files_.erase( observer );
331f09fa651SNicolas Bonnefon }
332f09fa651SNicolas Bonnefon else {
333f09fa651SNicolas Bonnefon ++observer;
334f09fa651SNicolas Bonnefon }
335f09fa651SNicolas Bonnefon }
336f09fa651SNicolas Bonnefon
337f09fa651SNicolas Bonnefon return returned_file;
338f09fa651SNicolas Bonnefon }
339f09fa651SNicolas Bonnefon
340f09fa651SNicolas Bonnefon template <typename Driver>
watchedDirectory(const std::string & dir_name)341f09fa651SNicolas Bonnefon std::shared_ptr<ObservedDir<Driver>> ObservedFileList<Driver>::watchedDirectory(
342f09fa651SNicolas Bonnefon const std::string& dir_name )
343f09fa651SNicolas Bonnefon {
344f09fa651SNicolas Bonnefon std::shared_ptr<ObservedDir<Driver>> dir = nullptr;
345f09fa651SNicolas Bonnefon
346f09fa651SNicolas Bonnefon if ( observed_dirs_.find( dir_name ) != std::end( observed_dirs_ ) )
347f09fa651SNicolas Bonnefon dir = observed_dirs_[ dir_name ].lock();
348f09fa651SNicolas Bonnefon
349f09fa651SNicolas Bonnefon return dir;
350f09fa651SNicolas Bonnefon }
351f09fa651SNicolas Bonnefon
352f09fa651SNicolas Bonnefon template <typename Driver>
addWatchedDirectory(const std::string & dir_name,std::function<void (ObservedDir<Driver> *)> remove_notification)353f09fa651SNicolas Bonnefon std::shared_ptr<ObservedDir<Driver>> ObservedFileList<Driver>::addWatchedDirectory(
3543104b268SNicolas Bonnefon const std::string& dir_name,
3553104b268SNicolas Bonnefon std::function<void( ObservedDir<Driver>* )> remove_notification )
356f09fa651SNicolas Bonnefon {
357*5751f354SAlexander Hirsch std::weak_ptr<ObservedFileList> weakHeartBeat(heartBeat_);
3583104b268SNicolas Bonnefon
3593104b268SNicolas Bonnefon std::shared_ptr<ObservedDir<Driver>> dir = {
3603104b268SNicolas Bonnefon new ObservedDir<Driver>( dir_name ),
361*5751f354SAlexander Hirsch [remove_notification, weakHeartBeat] (ObservedDir<Driver>* d) {
362*5751f354SAlexander Hirsch if ( auto list = weakHeartBeat.lock() ) {
3633104b268SNicolas Bonnefon remove_notification( d );
364*5751f354SAlexander Hirsch list->cleanRefsToExpiredDirs();
3653104b268SNicolas Bonnefon }
3663104b268SNicolas Bonnefon delete d; } };
367f09fa651SNicolas Bonnefon
368f09fa651SNicolas Bonnefon observed_dirs_[ dir_name ] = std::weak_ptr<ObservedDir<Driver>>( dir );
369f09fa651SNicolas Bonnefon
370f09fa651SNicolas Bonnefon return dir;
371f09fa651SNicolas Bonnefon }
372f09fa651SNicolas Bonnefon
373f09fa651SNicolas Bonnefon template <typename Driver>
watchedDirectoryForFile(const std::string & file_name)374f09fa651SNicolas Bonnefon std::shared_ptr<ObservedDir<Driver>> ObservedFileList<Driver>::watchedDirectoryForFile(
375f09fa651SNicolas Bonnefon const std::string& file_name )
376f09fa651SNicolas Bonnefon {
377f09fa651SNicolas Bonnefon return watchedDirectory( directory_path( file_name ) );
378f09fa651SNicolas Bonnefon }
379f09fa651SNicolas Bonnefon
380f09fa651SNicolas Bonnefon template <typename Driver>
addWatchedDirectoryForFile(const std::string & file_name,std::function<void (ObservedDir<Driver> *)> remove_notification)381f09fa651SNicolas Bonnefon std::shared_ptr<ObservedDir<Driver>> ObservedFileList<Driver>::addWatchedDirectoryForFile(
3823104b268SNicolas Bonnefon const std::string& file_name,
3833104b268SNicolas Bonnefon std::function<void( ObservedDir<Driver>* )> remove_notification )
384f09fa651SNicolas Bonnefon {
3853104b268SNicolas Bonnefon return addWatchedDirectory( directory_path( file_name ),
3863104b268SNicolas Bonnefon remove_notification );
3873104b268SNicolas Bonnefon }
3883104b268SNicolas Bonnefon
3893104b268SNicolas Bonnefon template <typename Driver>
numberWatchedDirectories()3903104b268SNicolas Bonnefon unsigned int ObservedFileList<Driver>::numberWatchedDirectories() const
3913104b268SNicolas Bonnefon {
3923104b268SNicolas Bonnefon return observed_dirs_.size();
3933104b268SNicolas Bonnefon }
3943104b268SNicolas Bonnefon
3953104b268SNicolas Bonnefon // Private functions
3963104b268SNicolas Bonnefon template <typename Driver>
cleanRefsToExpiredDirs()3973104b268SNicolas Bonnefon void ObservedFileList<Driver>::cleanRefsToExpiredDirs()
3983104b268SNicolas Bonnefon {
3993104b268SNicolas Bonnefon for ( auto it = std::begin( observed_dirs_ );
4003104b268SNicolas Bonnefon it != std::end( observed_dirs_ ); )
4013104b268SNicolas Bonnefon {
4023104b268SNicolas Bonnefon if ( it->second.expired() ) {
4033104b268SNicolas Bonnefon it = observed_dirs_.erase( it );
4043104b268SNicolas Bonnefon }
4053104b268SNicolas Bonnefon else {
4063104b268SNicolas Bonnefon ++it;
4073104b268SNicolas Bonnefon }
4083104b268SNicolas Bonnefon }
409f09fa651SNicolas Bonnefon }
410f09fa651SNicolas Bonnefon
411f09fa651SNicolas Bonnefon namespace {
directory_path(const std::string & path)412f09fa651SNicolas Bonnefon std::string directory_path( const std::string& path )
413f09fa651SNicolas Bonnefon {
414f09fa651SNicolas Bonnefon size_t slash_pos = path.rfind( '/' );
415f09fa651SNicolas Bonnefon
416f09fa651SNicolas Bonnefon #ifdef _WIN32
417f09fa651SNicolas Bonnefon if ( slash_pos == std::string::npos ) {
418f09fa651SNicolas Bonnefon slash_pos = path.rfind( '\\' );
419f09fa651SNicolas Bonnefon }
420f09fa651SNicolas Bonnefon
421f09fa651SNicolas Bonnefon // We need to include the final slash on Windows
422f09fa651SNicolas Bonnefon ++slash_pos;
423f09fa651SNicolas Bonnefon #endif
424f09fa651SNicolas Bonnefon
425f09fa651SNicolas Bonnefon return std::string( path, 0, slash_pos );
426f09fa651SNicolas Bonnefon }
427f09fa651SNicolas Bonnefon };
428c540156cSNicolas Bonnefon #endif
429