diff options
Diffstat (limited to 'src/3rdParty/efsw/DirWatcherGeneric.cpp')
-rwxr-xr-x | src/3rdParty/efsw/DirWatcherGeneric.cpp | 388 |
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 | |||
6 | namespace efsw { | ||
7 | |||
8 | DirWatcherGeneric::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 | |||
29 | DirWatcherGeneric::~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 | |||
59 | void 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 | |||
83 | void 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 | |||
90 | void 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 | |||
138 | void 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 | |||
195 | void 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 | |||
205 | DirWatcherGeneric* 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 | |||
245 | DirWatcherGeneric* 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 | |||
263 | DirWatcherGeneric* 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 | |||
323 | void 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 | |||
349 | void 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 | |||
374 | bool 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 | ||