diff options
| author | Li Jin <dragon-fly@qq.com> | 2022-11-15 17:23:46 +0800 |
|---|---|---|
| committer | Li Jin <dragon-fly@qq.com> | 2022-11-15 17:52:09 +0800 |
| commit | 94f8330613877b3582d32bd11abd83a97b4399ad (patch) | |
| tree | 5359de314be1ebde17f8d1e48632a97d18f9e50f /src/3rdParty/efsw/DirWatcherGeneric.cpp | |
| parent | 60f8f00a022ac08701792b2897b72d8c99b50f52 (diff) | |
| download | yuescript-94f8330613877b3582d32bd11abd83a97b4399ad.tar.gz yuescript-94f8330613877b3582d32bd11abd83a97b4399ad.tar.bz2 yuescript-94f8330613877b3582d32bd11abd83a97b4399ad.zip | |
adding -w option to Yuescript tool.
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 | ||
