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