xref: /glogg/src/watchtower.cpp (revision a0b17fd1d64cb02deab654616fb1af697b64851c)
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