1*a0936e1eSNicolas Bonnefon #include "watchtower.h" 2*a0936e1eSNicolas Bonnefon 3*a0936e1eSNicolas Bonnefon #include <algorithm> 4*a0936e1eSNicolas Bonnefon 5*a0936e1eSNicolas Bonnefon #include "log.h" 6*a0936e1eSNicolas Bonnefon 7*a0936e1eSNicolas Bonnefon namespace { 8*a0936e1eSNicolas Bonnefon std::string directory_path( const std::string& path ); 9*a0936e1eSNicolas Bonnefon }; 10*a0936e1eSNicolas Bonnefon 11*a0936e1eSNicolas Bonnefon // ObservedFileList class 12*a0936e1eSNicolas Bonnefon WatchTower::ObservedFile* 13*a0936e1eSNicolas Bonnefon WatchTower::ObservedFileList::searchByName( const std::string& file_name ) 14*a0936e1eSNicolas Bonnefon { 15*a0936e1eSNicolas Bonnefon // Look for an existing observer on this file 16*a0936e1eSNicolas Bonnefon auto existing_observer = observed_files_.begin(); 17*a0936e1eSNicolas Bonnefon for ( ; existing_observer != observed_files_.end(); ++existing_observer ) 18*a0936e1eSNicolas Bonnefon { 19*a0936e1eSNicolas Bonnefon if ( existing_observer->file_name_ == file_name ) 20*a0936e1eSNicolas Bonnefon { 21*a0936e1eSNicolas Bonnefon LOG(logDEBUG) << "Found " << file_name; 22*a0936e1eSNicolas Bonnefon break; 23*a0936e1eSNicolas Bonnefon } 24*a0936e1eSNicolas Bonnefon } 25*a0936e1eSNicolas Bonnefon 26*a0936e1eSNicolas Bonnefon if ( existing_observer != observed_files_.end() ) 27*a0936e1eSNicolas Bonnefon return &( *existing_observer ); 28*a0936e1eSNicolas Bonnefon else 29*a0936e1eSNicolas Bonnefon return nullptr; 30*a0936e1eSNicolas Bonnefon } 31*a0936e1eSNicolas Bonnefon 32*a0936e1eSNicolas Bonnefon WatchTower::ObservedFile* 33*a0936e1eSNicolas Bonnefon WatchTower::ObservedFileList::searchByFileOrSymlinkWd( int wd ) 34*a0936e1eSNicolas Bonnefon { 35*a0936e1eSNicolas Bonnefon auto result = find_if( observed_files_.begin(), observed_files_.end(), 36*a0936e1eSNicolas Bonnefon [wd] (ObservedFile file) -> bool { 37*a0936e1eSNicolas Bonnefon return ( wd == file.file_wd_ ) || ( wd == file.symlink_wd_ ); } ); 38*a0936e1eSNicolas Bonnefon 39*a0936e1eSNicolas Bonnefon if ( result != observed_files_.end() ) 40*a0936e1eSNicolas Bonnefon return &( *result ); 41*a0936e1eSNicolas Bonnefon else 42*a0936e1eSNicolas Bonnefon return nullptr; 43*a0936e1eSNicolas Bonnefon } 44*a0936e1eSNicolas Bonnefon 45*a0936e1eSNicolas Bonnefon WatchTower::ObservedFile* 46*a0936e1eSNicolas Bonnefon WatchTower::ObservedFileList::searchByDirWdAndName( int wd, const char* name ) 47*a0936e1eSNicolas Bonnefon { 48*a0936e1eSNicolas Bonnefon auto dir = find_if( observed_dirs_.begin(), observed_dirs_.end(), 49*a0936e1eSNicolas Bonnefon [wd] (std::pair<std::string,std::weak_ptr<ObservedDir>> d) -> bool { 50*a0936e1eSNicolas Bonnefon return ( wd == std::shared_ptr<ObservedDir>(d.second)->dir_wd_ ); } ); 51*a0936e1eSNicolas Bonnefon 52*a0936e1eSNicolas Bonnefon std::string path = dir->first + "/" + name; 53*a0936e1eSNicolas Bonnefon 54*a0936e1eSNicolas Bonnefon // LOG(logDEBUG) << "Testing path: " << path; 55*a0936e1eSNicolas Bonnefon 56*a0936e1eSNicolas Bonnefon // Looking for the path in the files we are watching 57*a0936e1eSNicolas Bonnefon return searchByName( path ); 58*a0936e1eSNicolas Bonnefon } 59*a0936e1eSNicolas Bonnefon 60*a0936e1eSNicolas Bonnefon WatchTower::ObservedFile* 61*a0936e1eSNicolas Bonnefon WatchTower::ObservedFileList::addNewObservedFile( ObservedFile new_observed ) 62*a0936e1eSNicolas Bonnefon { 63*a0936e1eSNicolas Bonnefon auto new_file = observed_files_.insert( std::begin( observed_files_ ), new_observed ); 64*a0936e1eSNicolas Bonnefon 65*a0936e1eSNicolas Bonnefon return &( *new_file ); 66*a0936e1eSNicolas Bonnefon } 67*a0936e1eSNicolas Bonnefon 68*a0936e1eSNicolas Bonnefon std::shared_ptr<WatchTower::ObservedFile> 69*a0936e1eSNicolas Bonnefon WatchTower::ObservedFileList::removeCallback( 70*a0936e1eSNicolas Bonnefon std::shared_ptr<void> callback ) 71*a0936e1eSNicolas Bonnefon { 72*a0936e1eSNicolas Bonnefon std::shared_ptr<ObservedFile> returned_file = nullptr; 73*a0936e1eSNicolas Bonnefon 74*a0936e1eSNicolas Bonnefon for ( auto observer = begin( observed_files_ ); 75*a0936e1eSNicolas Bonnefon observer != end( observed_files_ ); ) 76*a0936e1eSNicolas Bonnefon { 77*a0936e1eSNicolas Bonnefon LOG(logDEBUG) << "Examining entry for " << observer->file_name_; 78*a0936e1eSNicolas Bonnefon 79*a0936e1eSNicolas Bonnefon std::vector<std::shared_ptr<void>>& callbacks = observer->callbacks; 80*a0936e1eSNicolas Bonnefon callbacks.erase( std::remove( 81*a0936e1eSNicolas Bonnefon std::begin( callbacks ), std::end( callbacks ), callback ), 82*a0936e1eSNicolas Bonnefon std::end( callbacks ) ); 83*a0936e1eSNicolas Bonnefon 84*a0936e1eSNicolas Bonnefon /* See if all notifications have been deleted for this file */ 85*a0936e1eSNicolas Bonnefon if ( callbacks.empty() ) { 86*a0936e1eSNicolas Bonnefon LOG(logDEBUG) << "Empty notification list, removing the watched file"; 87*a0936e1eSNicolas Bonnefon returned_file = std::make_shared<ObservedFile>( *observer ); 88*a0936e1eSNicolas Bonnefon observer = observed_files_.erase( observer ); 89*a0936e1eSNicolas Bonnefon } 90*a0936e1eSNicolas Bonnefon else { 91*a0936e1eSNicolas Bonnefon ++observer; 92*a0936e1eSNicolas Bonnefon } 93*a0936e1eSNicolas Bonnefon } 94*a0936e1eSNicolas Bonnefon 95*a0936e1eSNicolas Bonnefon return returned_file; 96*a0936e1eSNicolas Bonnefon } 97*a0936e1eSNicolas Bonnefon 98*a0936e1eSNicolas Bonnefon std::shared_ptr<WatchTower::ObservedDir> 99*a0936e1eSNicolas Bonnefon WatchTower::ObservedFileList::watchedDirectory( const std::string& dir_name ) 100*a0936e1eSNicolas Bonnefon { 101*a0936e1eSNicolas Bonnefon std::shared_ptr<ObservedDir> dir = nullptr; 102*a0936e1eSNicolas Bonnefon 103*a0936e1eSNicolas Bonnefon if ( observed_dirs_.find( dir_name ) != std::end( observed_dirs_ ) ) 104*a0936e1eSNicolas Bonnefon dir = observed_dirs_[ dir_name ].lock(); 105*a0936e1eSNicolas Bonnefon 106*a0936e1eSNicolas Bonnefon return dir; 107*a0936e1eSNicolas Bonnefon } 108*a0936e1eSNicolas Bonnefon 109*a0936e1eSNicolas Bonnefon std::shared_ptr<WatchTower::ObservedDir> 110*a0936e1eSNicolas Bonnefon WatchTower::ObservedFileList::addWatchedDirectory( const std::string& dir_name ) 111*a0936e1eSNicolas Bonnefon { 112*a0936e1eSNicolas Bonnefon auto dir = std::make_shared<ObservedDir>( dir_name ); 113*a0936e1eSNicolas Bonnefon 114*a0936e1eSNicolas Bonnefon observed_dirs_[ dir_name ] = std::weak_ptr<ObservedDir>( dir ); 115*a0936e1eSNicolas Bonnefon 116*a0936e1eSNicolas Bonnefon return dir; 117*a0936e1eSNicolas Bonnefon } 118*a0936e1eSNicolas Bonnefon 119*a0936e1eSNicolas Bonnefon std::shared_ptr<WatchTower::ObservedDir> 120*a0936e1eSNicolas Bonnefon WatchTower::ObservedFileList::watchedDirectoryForFile( const std::string& file_name ) 121*a0936e1eSNicolas Bonnefon { 122*a0936e1eSNicolas Bonnefon return watchedDirectory( directory_path( file_name ) ); 123*a0936e1eSNicolas Bonnefon } 124*a0936e1eSNicolas Bonnefon 125*a0936e1eSNicolas Bonnefon std::shared_ptr<WatchTower::ObservedDir> 126*a0936e1eSNicolas Bonnefon WatchTower::ObservedFileList::addWatchedDirectoryForFile( const std::string& file_name ) 127*a0936e1eSNicolas Bonnefon { 128*a0936e1eSNicolas Bonnefon return addWatchedDirectory( directory_path( file_name ) ); 129*a0936e1eSNicolas Bonnefon } 130*a0936e1eSNicolas Bonnefon 131*a0936e1eSNicolas Bonnefon namespace { 132*a0936e1eSNicolas Bonnefon std::string directory_path( const std::string& path ) 133*a0936e1eSNicolas Bonnefon { 134*a0936e1eSNicolas Bonnefon size_t slash_pos = path.rfind( '/' ); 135*a0936e1eSNicolas Bonnefon 136*a0936e1eSNicolas Bonnefon #ifdef _WIN32 137*a0936e1eSNicolas Bonnefon if ( slash_pos == std::string::npos ) { 138*a0936e1eSNicolas Bonnefon slash_pos = path.rfind( '\\' ) + 1; 139*a0936e1eSNicolas Bonnefon LOG(logDEBUG) << "Pos = " << slash_pos; 140*a0936e1eSNicolas Bonnefon } 141*a0936e1eSNicolas Bonnefon #endif 142*a0936e1eSNicolas Bonnefon 143*a0936e1eSNicolas Bonnefon return std::string( path, 0, slash_pos ); 144*a0936e1eSNicolas Bonnefon } 145*a0936e1eSNicolas Bonnefon }; 146