aboutsummaryrefslogtreecommitdiff
path: root/src/3rdParty/efsw/DirWatcherGeneric.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/3rdParty/efsw/DirWatcherGeneric.cpp')
-rwxr-xr-xsrc/3rdParty/efsw/DirWatcherGeneric.cpp388
1 files changed, 388 insertions, 0 deletions
diff --git a/src/3rdParty/efsw/DirWatcherGeneric.cpp b/src/3rdParty/efsw/DirWatcherGeneric.cpp
new file mode 100755
index 0000000..8b6bc8a
--- /dev/null
+++ b/src/3rdParty/efsw/DirWatcherGeneric.cpp
@@ -0,0 +1,388 @@
1#include <efsw/Debug.hpp>
2#include <efsw/DirWatcherGeneric.hpp>
3#include <efsw/FileSystem.hpp>
4#include <efsw/String.hpp>
5
6namespace efsw {
7
8DirWatcherGeneric::DirWatcherGeneric( DirWatcherGeneric* parent, WatcherGeneric* ws,
9 const std::string& directory, bool recursive,
10 bool reportNewFiles ) :
11 Parent( parent ), Watch( ws ), Recursive( recursive ), Deleted( false ) {
12 resetDirectory( directory );
13
14 if ( !reportNewFiles ) {
15 DirSnap.scan();
16 } else {
17 DirectorySnapshotDiff Diff = DirSnap.scan();
18
19 if ( Diff.changed() ) {
20 FileInfoList::iterator it;
21
22 DiffIterator( FilesCreated ) {
23 handleAction( ( *it ).Filepath, Actions::Add );
24 }
25 }
26 }
27}
28
29DirWatcherGeneric::~DirWatcherGeneric() {
30 /// If the directory was deleted mark the files as deleted
31 if ( Deleted ) {
32 DirectorySnapshotDiff Diff = DirSnap.scan();
33
34 if ( !DirSnap.exists() ) {
35 FileInfoList::iterator it;
36
37 DiffIterator( FilesDeleted ) {
38 handleAction( ( *it ).Filepath, Actions::Delete );
39 }
40
41 DiffIterator( DirsDeleted ) {
42 handleAction( ( *it ).Filepath, Actions::Delete );
43 }
44 }
45 }
46
47 DirWatchMap::iterator it = Directories.begin();
48
49 for ( ; it != Directories.end(); ++it ) {
50 if ( Deleted ) {
51 /// If the directory was deleted, mark the flag for file deletion
52 it->second->Deleted = true;
53 }
54
55 efSAFE_DELETE( it->second );
56 }
57}
58
59void DirWatcherGeneric::resetDirectory( std::string directory ) {
60 std::string dir( directory );
61
62 /// Is this a recursive watch?
63 if ( Watch->Directory != directory ) {
64 if ( !( directory.size() &&
65 ( directory.at( 0 ) == FileSystem::getOSSlash() ||
66 directory.at( directory.size() - 1 ) == FileSystem::getOSSlash() ) ) ) {
67 /// Get the real directory
68 if ( NULL != Parent ) {
69 std::string parentPath( Parent->DirSnap.DirectoryInfo.Filepath );
70 FileSystem::dirAddSlashAtEnd( parentPath );
71 FileSystem::dirAddSlashAtEnd( directory );
72
73 dir = parentPath + directory;
74 } else {
75 efDEBUG( "resetDirectory(): Parent is NULL. Fatal error." );
76 }
77 }
78 }
79
80 DirSnap.setDirectoryInfo( dir );
81}
82
83void DirWatcherGeneric::handleAction( const std::string& filename, unsigned long action,
84 std::string oldFilename ) {
85 Watch->Listener->handleFileAction( Watch->ID, DirSnap.DirectoryInfo.Filepath,
86 FileSystem::fileNameFromPath( filename ), (Action)action,
87 oldFilename );
88}
89
90void DirWatcherGeneric::addChilds( bool reportNewFiles ) {
91 if ( Recursive ) {
92 /// Create the subdirectories watchers
93 std::string dir;
94
95 for ( FileInfoMap::iterator it = DirSnap.Files.begin(); it != DirSnap.Files.end(); it++ ) {
96 if ( it->second.isDirectory() && it->second.isReadable() &&
97 !FileSystem::isRemoteFS( it->second.Filepath ) ) {
98 /// Check if the directory is a symbolic link
99 std::string curPath;
100 std::string link( FileSystem::getLinkRealPath( it->second.Filepath, curPath ) );
101
102 dir = it->first;
103
104 if ( "" != link ) {
105 /// Avoid adding symlinks directories if it's now enabled
106 if ( !Watch->WatcherImpl->mFileWatcher->followSymlinks() ) {
107 continue;
108 }
109
110 /// If it's a symlink check if the realpath exists as a watcher, or
111 /// if the path is outside the current dir
112 if ( Watch->WatcherImpl->pathInWatches( link ) ||
113 Watch->pathInWatches( link ) ||
114 !Watch->WatcherImpl->linkAllowed( curPath, link ) ) {
115 continue;
116 } else {
117 dir = link;
118 }
119 } else {
120 if ( Watch->pathInWatches( dir ) || Watch->WatcherImpl->pathInWatches( dir ) ) {
121 continue;
122 }
123 }
124
125 if ( reportNewFiles ) {
126 handleAction( dir, Actions::Add );
127 }
128
129 Directories[dir] =
130 new DirWatcherGeneric( this, Watch, dir, Recursive, reportNewFiles );
131
132 Directories[dir]->addChilds( reportNewFiles );
133 }
134 }
135 }
136}
137
138void DirWatcherGeneric::watch( bool reportOwnChange ) {
139 DirectorySnapshotDiff Diff = DirSnap.scan();
140
141 if ( reportOwnChange && Diff.DirChanged && NULL != Parent ) {
142 Watch->Listener->handleFileAction(
143 Watch->ID, FileSystem::pathRemoveFileName( DirSnap.DirectoryInfo.Filepath ),
144 FileSystem::fileNameFromPath( DirSnap.DirectoryInfo.Filepath ), Actions::Modified );
145 }
146
147 if ( Diff.changed() ) {
148 FileInfoList::iterator it;
149 MovedList::iterator mit;
150
151 /// Files
152 DiffIterator( FilesCreated ) {
153 handleAction( ( *it ).Filepath, Actions::Add );
154 }
155
156 DiffIterator( FilesModified ) {
157 handleAction( ( *it ).Filepath, Actions::Modified );
158 }
159
160 DiffIterator( FilesDeleted ) {
161 handleAction( ( *it ).Filepath, Actions::Delete );
162 }
163
164 DiffMovedIterator( FilesMoved ) {
165 handleAction( ( *mit ).second.Filepath, Actions::Moved, ( *mit ).first );
166 }
167
168 /// Directories
169 DiffIterator( DirsCreated ) {
170 createDirectory( ( *it ).Filepath );
171 }
172
173 DiffIterator( DirsModified ) {
174 handleAction( ( *it ).Filepath, Actions::Modified );
175 }
176
177 DiffIterator( DirsDeleted ) {
178 handleAction( ( *it ).Filepath, Actions::Delete );
179 removeDirectory( ( *it ).Filepath );
180 }
181
182 DiffMovedIterator( DirsMoved ) {
183 handleAction( ( *mit ).second.Filepath, Actions::Moved, ( *mit ).first );
184 moveDirectory( ( *mit ).first, ( *mit ).second.Filepath );
185 }
186 }
187
188 /// Process the subdirectories looking for changes
189 for ( DirWatchMap::iterator dit = Directories.begin(); dit != Directories.end(); ++dit ) {
190 /// Just watch
191 dit->second->watch();
192 }
193}
194
195void DirWatcherGeneric::watchDir( std::string& dir ) {
196 DirWatcherGeneric* watcher = Watch->WatcherImpl->mFileWatcher->allowOutOfScopeLinks()
197 ? findDirWatcher( dir )
198 : findDirWatcherFast( dir );
199
200 if ( NULL != watcher ) {
201 watcher->watch( true );
202 }
203}
204
205DirWatcherGeneric* DirWatcherGeneric::findDirWatcherFast( std::string dir ) {
206 // remove the common base ( dir should always start with the same base as the watcher )
207 efASSERT( !dir.empty() );
208 efASSERT( dir.size() >= DirSnap.DirectoryInfo.Filepath.size() );
209 efASSERT( DirSnap.DirectoryInfo.Filepath ==
210 dir.substr( 0, DirSnap.DirectoryInfo.Filepath.size() ) );
211
212 if ( dir.size() >= DirSnap.DirectoryInfo.Filepath.size() ) {
213 dir = dir.substr( DirSnap.DirectoryInfo.Filepath.size() - 1 );
214 }
215
216 if ( dir.size() == 1 ) {
217 efASSERT( dir[0] == FileSystem::getOSSlash() );
218 return this;
219 }
220
221 size_t level = 0;
222 std::vector<std::string> dirv = String::split( dir, FileSystem::getOSSlash(), false );
223
224 DirWatcherGeneric* watcher = this;
225
226 while ( level < dirv.size() ) {
227 // search the dir level in the current watcher
228 DirWatchMap::iterator it = watcher->Directories.find( dirv[level] );
229
230 // found? continue with the next level
231 if ( it != watcher->Directories.end() ) {
232 watcher = it->second;
233
234 level++;
235 } else {
236 // couldn't found the folder level?
237 // directory not watched
238 return NULL;
239 }
240 }
241
242 return watcher;
243}
244
245DirWatcherGeneric* DirWatcherGeneric::findDirWatcher( std::string dir ) {
246 if ( DirSnap.DirectoryInfo.Filepath == dir ) {
247 return this;
248 } else {
249 DirWatcherGeneric* watcher = NULL;
250
251 for ( DirWatchMap::iterator it = Directories.begin(); it != Directories.end(); ++it ) {
252 watcher = it->second->findDirWatcher( dir );
253
254 if ( NULL != watcher ) {
255 return watcher;
256 }
257 }
258 }
259
260 return NULL;
261}
262
263DirWatcherGeneric* DirWatcherGeneric::createDirectory( std::string newdir ) {
264 FileSystem::dirRemoveSlashAtEnd( newdir );
265 newdir = FileSystem::fileNameFromPath( newdir );
266
267 DirWatcherGeneric* dw = NULL;
268
269 /// Check if the directory is a symbolic link
270 std::string parentPath( DirSnap.DirectoryInfo.Filepath );
271 FileSystem::dirAddSlashAtEnd( parentPath );
272 std::string dir( parentPath + newdir );
273
274 FileSystem::dirAddSlashAtEnd( dir );
275
276 FileInfo fi( dir );
277
278 if ( !fi.isDirectory() || !fi.isReadable() || FileSystem::isRemoteFS( dir ) ) {
279 return NULL;
280 }
281
282 std::string curPath;
283 std::string link( FileSystem::getLinkRealPath( dir, curPath ) );
284 bool skip = false;
285
286 if ( "" != link ) {
287 /// Avoid adding symlinks directories if it's now enabled
288 if ( !Watch->WatcherImpl->mFileWatcher->followSymlinks() ) {
289 skip = true;
290 }
291
292 /// If it's a symlink check if the realpath exists as a watcher, or
293 /// if the path is outside the current dir
294 if ( Watch->WatcherImpl->pathInWatches( link ) || Watch->pathInWatches( link ) ||
295 !Watch->WatcherImpl->linkAllowed( curPath, link ) ) {
296 skip = true;
297 } else {
298 dir = link;
299 }
300 } else {
301 if ( Watch->pathInWatches( dir ) || Watch->WatcherImpl->pathInWatches( dir ) ) {
302 skip = true;
303 }
304 }
305
306 if ( !skip ) {
307 handleAction( newdir, Actions::Add );
308
309 /// Creates the new directory watcher of the subfolder and check for new files
310 dw = new DirWatcherGeneric( this, Watch, dir, Recursive );
311
312 dw->addChilds();
313
314 dw->watch();
315
316 /// Add it to the list of directories
317 Directories[newdir] = dw;
318 }
319
320 return dw;
321}
322
323void DirWatcherGeneric::removeDirectory( std::string dir ) {
324 FileSystem::dirRemoveSlashAtEnd( dir );
325 dir = FileSystem::fileNameFromPath( dir );
326
327 DirWatcherGeneric* dw = NULL;
328 DirWatchMap::iterator dit;
329
330 /// Folder deleted
331
332 /// Search the folder, it should exists
333 dit = Directories.find( dir );
334
335 if ( dit != Directories.end() ) {
336 dw = dit->second;
337
338 /// Flag it as deleted so it fire the event for every file inside deleted
339 dw->Deleted = true;
340
341 /// Delete the DirWatcherGeneric
342 efSAFE_DELETE( dw );
343
344 /// Remove the directory from the map
345 Directories.erase( dit->first );
346 }
347}
348
349void DirWatcherGeneric::moveDirectory( std::string oldDir, std::string newDir ) {
350 FileSystem::dirRemoveSlashAtEnd( oldDir );
351 oldDir = FileSystem::fileNameFromPath( oldDir );
352
353 FileSystem::dirRemoveSlashAtEnd( newDir );
354 newDir = FileSystem::fileNameFromPath( newDir );
355
356 DirWatcherGeneric* dw = NULL;
357 DirWatchMap::iterator dit;
358
359 /// Directory existed?
360 dit = Directories.find( oldDir );
361
362 if ( dit != Directories.end() ) {
363 dw = dit->second;
364
365 /// Remove the directory from the map
366 Directories.erase( dit->first );
367
368 Directories[newDir] = dw;
369
370 dw->resetDirectory( newDir );
371 }
372}
373
374bool DirWatcherGeneric::pathInWatches( std::string path ) {
375 if ( DirSnap.DirectoryInfo.Filepath == path ) {
376 return true;
377 }
378
379 for ( DirWatchMap::iterator it = Directories.begin(); it != Directories.end(); ++it ) {
380 if ( it->second->pathInWatches( path ) ) {
381 return true;
382 }
383 }
384
385 return false;
386}
387
388} // namespace efsw