187e05652SNicolas Bonnefon #include <memory> 287e05652SNicolas Bonnefon #include <functional> 387e05652SNicolas Bonnefon #include <string> 4*a0936e1eSNicolas Bonnefon #include <vector> 5*a0936e1eSNicolas Bonnefon #include <map> 6*a0936e1eSNicolas Bonnefon #include <list> 787e05652SNicolas Bonnefon 887e05652SNicolas Bonnefon class WatchTower { 987e05652SNicolas Bonnefon public: 1087e05652SNicolas Bonnefon // Registration object to implement RAII 1187e05652SNicolas Bonnefon using Registration = std::shared_ptr<void>; 1287e05652SNicolas Bonnefon 1387e05652SNicolas Bonnefon // Create an empty watchtower 1487e05652SNicolas Bonnefon WatchTower() {}; 1587e05652SNicolas Bonnefon // Destroy the object 1687e05652SNicolas Bonnefon virtual ~WatchTower() {}; 1787e05652SNicolas Bonnefon 1887e05652SNicolas Bonnefon // Add a file to the notification list. notification will be called when 1987e05652SNicolas Bonnefon // the file is modified, moved or deleted. 2087e05652SNicolas Bonnefon // Lifetime of the notification is tied to the Registration object returned. 2187e05652SNicolas Bonnefon // Note the notification function is called with a mutex held and in a 2287e05652SNicolas Bonnefon // third party thread, beware of races! 2387e05652SNicolas Bonnefon virtual Registration addFile( const std::string& file_name, 2487e05652SNicolas Bonnefon std::function<void()> notification ) = 0; 25*a0936e1eSNicolas Bonnefon 26*a0936e1eSNicolas Bonnefon protected: 27*a0936e1eSNicolas Bonnefon // Utility classes 28*a0936e1eSNicolas Bonnefon 29*a0936e1eSNicolas Bonnefon // List of files and observers 30*a0936e1eSNicolas Bonnefon struct ObservedDir { 31*a0936e1eSNicolas Bonnefon ObservedDir( const std::string this_path ) : path { this_path } {} 32*a0936e1eSNicolas Bonnefon std::string path; 33*a0936e1eSNicolas Bonnefon int dir_wd_; 34*a0936e1eSNicolas Bonnefon }; 35*a0936e1eSNicolas Bonnefon 36*a0936e1eSNicolas Bonnefon struct ObservedFile { 37*a0936e1eSNicolas Bonnefon ObservedFile( 38*a0936e1eSNicolas Bonnefon const std::string& file_name, 39*a0936e1eSNicolas Bonnefon std::shared_ptr<void> callback, 40*a0936e1eSNicolas Bonnefon int file_wd, 41*a0936e1eSNicolas Bonnefon int symlink_wd ) : file_name_( file_name ) { 42*a0936e1eSNicolas Bonnefon callbacks.push_back( callback ); 43*a0936e1eSNicolas Bonnefon 44*a0936e1eSNicolas Bonnefon file_wd_ = file_wd; 45*a0936e1eSNicolas Bonnefon symlink_wd_ = symlink_wd; 46*a0936e1eSNicolas Bonnefon dir_ = nullptr; 47*a0936e1eSNicolas Bonnefon } 48*a0936e1eSNicolas Bonnefon 49*a0936e1eSNicolas Bonnefon void addCallback( std::shared_ptr<void> callback ) { 50*a0936e1eSNicolas Bonnefon callbacks.push_back( callback ); 51*a0936e1eSNicolas Bonnefon } 52*a0936e1eSNicolas Bonnefon 53*a0936e1eSNicolas Bonnefon std::string file_name_; 54*a0936e1eSNicolas Bonnefon // List of callbacks for this file 55*a0936e1eSNicolas Bonnefon std::vector<std::shared_ptr<void>> callbacks; 56*a0936e1eSNicolas Bonnefon 57*a0936e1eSNicolas Bonnefon // watch descriptor for the file itself 58*a0936e1eSNicolas Bonnefon int file_wd_; 59*a0936e1eSNicolas Bonnefon // watch descriptor for the symlink (if file is a symlink) 60*a0936e1eSNicolas Bonnefon int symlink_wd_; 61*a0936e1eSNicolas Bonnefon 62*a0936e1eSNicolas Bonnefon // link to the dir containing the file 63*a0936e1eSNicolas Bonnefon std::shared_ptr<ObservedDir> dir_; 64*a0936e1eSNicolas Bonnefon }; 65*a0936e1eSNicolas Bonnefon 66*a0936e1eSNicolas Bonnefon // A list of the observed files and directories 67*a0936e1eSNicolas Bonnefon // This class is not thread safe 68*a0936e1eSNicolas Bonnefon class ObservedFileList { 69*a0936e1eSNicolas Bonnefon public: 70*a0936e1eSNicolas Bonnefon ObservedFileList() = default; 71*a0936e1eSNicolas Bonnefon ~ObservedFileList() = default; 72*a0936e1eSNicolas Bonnefon 73*a0936e1eSNicolas Bonnefon ObservedFile* searchByName( const std::string& file_name ); 74*a0936e1eSNicolas Bonnefon ObservedFile* searchByFileOrSymlinkWd( int wd ); 75*a0936e1eSNicolas Bonnefon ObservedFile* searchByDirWdAndName( int wd, const char* name ); 76*a0936e1eSNicolas Bonnefon 77*a0936e1eSNicolas Bonnefon ObservedFile* addNewObservedFile( ObservedFile new_observed ); 78*a0936e1eSNicolas Bonnefon // Remove a callback, remove and returns the file object if 79*a0936e1eSNicolas Bonnefon // it was the last callback on this object, nullptr if not. 80*a0936e1eSNicolas Bonnefon // The caller has ownership of the object. 81*a0936e1eSNicolas Bonnefon std::shared_ptr<ObservedFile> removeCallback( 82*a0936e1eSNicolas Bonnefon std::shared_ptr<void> callback ); 83*a0936e1eSNicolas Bonnefon 84*a0936e1eSNicolas Bonnefon // Return the watched directory if it is watched, or nullptr 85*a0936e1eSNicolas Bonnefon std::shared_ptr<ObservedDir> watchedDirectory( const std::string& dir_name ); 86*a0936e1eSNicolas Bonnefon // Create a new watched directory for dir_name 87*a0936e1eSNicolas Bonnefon std::shared_ptr<ObservedDir> addWatchedDirectory( const std::string& dir_name ); 88*a0936e1eSNicolas Bonnefon 89*a0936e1eSNicolas Bonnefon std::shared_ptr<ObservedDir> watchedDirectoryForFile( const std::string& file_name ); 90*a0936e1eSNicolas Bonnefon std::shared_ptr<ObservedDir> addWatchedDirectoryForFile( const std::string& file_name ); 91*a0936e1eSNicolas Bonnefon 92*a0936e1eSNicolas Bonnefon private: 93*a0936e1eSNicolas Bonnefon // List of observed files 94*a0936e1eSNicolas Bonnefon std::list<ObservedFile> observed_files_; 95*a0936e1eSNicolas Bonnefon 96*a0936e1eSNicolas Bonnefon // List of observed dirs, key-ed by name 97*a0936e1eSNicolas Bonnefon std::map<std::string, std::weak_ptr<ObservedDir>> observed_dirs_; 98*a0936e1eSNicolas Bonnefon 99*a0936e1eSNicolas Bonnefon // Map the inotify file (including symlinks) wds to the observed file 100*a0936e1eSNicolas Bonnefon std::map<int, ObservedFile*> by_file_wd_; 101*a0936e1eSNicolas Bonnefon // Map the inotify directory wds to the observed files 102*a0936e1eSNicolas Bonnefon std::map<int, ObservedFile*> by_dir_wd_; 103*a0936e1eSNicolas Bonnefon }; 10487e05652SNicolas Bonnefon }; 105