diff options
Diffstat (limited to '')
| -rwxr-xr-x | src/3rdParty/efsw/FileWatcherInotify.cpp | 599 |
1 files changed, 599 insertions, 0 deletions
diff --git a/src/3rdParty/efsw/FileWatcherInotify.cpp b/src/3rdParty/efsw/FileWatcherInotify.cpp new file mode 100755 index 0000000..e0da76b --- /dev/null +++ b/src/3rdParty/efsw/FileWatcherInotify.cpp | |||
| @@ -0,0 +1,599 @@ | |||
| 1 | #include <efsw/FileWatcherInotify.hpp> | ||
| 2 | |||
| 3 | #if EFSW_PLATFORM == EFSW_PLATFORM_INOTIFY | ||
| 4 | |||
| 5 | #include <errno.h> | ||
| 6 | #include <fcntl.h> | ||
| 7 | #include <stdio.h> | ||
| 8 | #include <string.h> | ||
| 9 | #include <sys/stat.h> | ||
| 10 | #include <unistd.h> | ||
| 11 | |||
| 12 | #ifdef EFSW_INOTIFY_NOSYS | ||
| 13 | #include <efsw/inotify-nosys.h> | ||
| 14 | #else | ||
| 15 | #include <sys/inotify.h> | ||
| 16 | #endif | ||
| 17 | |||
| 18 | #include <efsw/Debug.hpp> | ||
| 19 | #include <efsw/FileSystem.hpp> | ||
| 20 | #include <efsw/Lock.hpp> | ||
| 21 | #include <efsw/String.hpp> | ||
| 22 | #include <efsw/System.hpp> | ||
| 23 | |||
| 24 | #define BUFF_SIZE ( ( sizeof( struct inotify_event ) + FILENAME_MAX ) * 1024 ) | ||
| 25 | |||
| 26 | namespace efsw { | ||
| 27 | |||
| 28 | FileWatcherInotify::FileWatcherInotify( FileWatcher* parent ) : | ||
| 29 | FileWatcherImpl( parent ), mFD( -1 ), mThread( NULL ) { | ||
| 30 | mFD = inotify_init(); | ||
| 31 | |||
| 32 | if ( mFD < 0 ) { | ||
| 33 | efDEBUG( "Error: %s\n", strerror( errno ) ); | ||
| 34 | } else { | ||
| 35 | mInitOK = true; | ||
| 36 | } | ||
| 37 | } | ||
| 38 | |||
| 39 | FileWatcherInotify::~FileWatcherInotify() { | ||
| 40 | mInitOK = false; | ||
| 41 | |||
| 42 | Lock initLock( mInitLock ); | ||
| 43 | |||
| 44 | efSAFE_DELETE( mThread ); | ||
| 45 | |||
| 46 | Lock l( mWatchesLock ); | ||
| 47 | Lock l2( mRealWatchesLock ); | ||
| 48 | WatchMap::iterator iter = mWatches.begin(); | ||
| 49 | WatchMap::iterator end = mWatches.end(); | ||
| 50 | |||
| 51 | for ( ; iter != end; ++iter ) { | ||
| 52 | efSAFE_DELETE( iter->second ); | ||
| 53 | } | ||
| 54 | |||
| 55 | mWatches.clear(); | ||
| 56 | |||
| 57 | if ( mFD != -1 ) { | ||
| 58 | close( mFD ); | ||
| 59 | mFD = -1; | ||
| 60 | } | ||
| 61 | } | ||
| 62 | |||
| 63 | WatchID FileWatcherInotify::addWatch( const std::string& directory, FileWatchListener* watcher, | ||
| 64 | bool recursive ) { | ||
| 65 | if ( !mInitOK ) | ||
| 66 | return Errors::Log::createLastError( Errors::Unspecified, directory ); | ||
| 67 | Lock initLock( mInitLock ); | ||
| 68 | return addWatch( directory, watcher, recursive, NULL ); | ||
| 69 | } | ||
| 70 | |||
| 71 | WatchID FileWatcherInotify::addWatch( const std::string& directory, FileWatchListener* watcher, | ||
| 72 | bool recursive, WatcherInotify* parent ) { | ||
| 73 | std::string dir( directory ); | ||
| 74 | |||
| 75 | FileSystem::dirAddSlashAtEnd( dir ); | ||
| 76 | |||
| 77 | FileInfo fi( dir ); | ||
| 78 | |||
| 79 | if ( !fi.isDirectory() ) { | ||
| 80 | return Errors::Log::createLastError( Errors::FileNotFound, dir ); | ||
| 81 | } else if ( !fi.isReadable() ) { | ||
| 82 | return Errors::Log::createLastError( Errors::FileNotReadable, dir ); | ||
| 83 | } else if ( pathInWatches( dir ) ) { | ||
| 84 | return Errors::Log::createLastError( Errors::FileRepeated, directory ); | ||
| 85 | } else if ( NULL != parent && FileSystem::isRemoteFS( dir ) ) { | ||
| 86 | return Errors::Log::createLastError( Errors::FileRemote, dir ); | ||
| 87 | } | ||
| 88 | |||
| 89 | /// Check if the directory is a symbolic link | ||
| 90 | std::string curPath; | ||
| 91 | std::string link( FileSystem::getLinkRealPath( dir, curPath ) ); | ||
| 92 | |||
| 93 | if ( "" != link ) { | ||
| 94 | /// Avoid adding symlinks directories if it's now enabled | ||
| 95 | if ( NULL != parent && !mFileWatcher->followSymlinks() ) { | ||
| 96 | return Errors::Log::createLastError( Errors::FileOutOfScope, dir ); | ||
| 97 | } | ||
| 98 | |||
| 99 | /// If it's a symlink check if the realpath exists as a watcher, or | ||
| 100 | /// if the path is outside the current dir | ||
| 101 | if ( pathInWatches( link ) ) { | ||
| 102 | return Errors::Log::createLastError( Errors::FileRepeated, directory ); | ||
| 103 | } else if ( !linkAllowed( curPath, link ) ) { | ||
| 104 | return Errors::Log::createLastError( Errors::FileOutOfScope, dir ); | ||
| 105 | } else { | ||
| 106 | dir = link; | ||
| 107 | } | ||
| 108 | } | ||
| 109 | |||
| 110 | int wd = inotify_add_watch( mFD, dir.c_str(), | ||
| 111 | IN_CLOSE_WRITE | IN_MOVED_TO | IN_CREATE | IN_MOVED_FROM | | ||
| 112 | IN_DELETE | IN_MODIFY ); | ||
| 113 | |||
| 114 | if ( wd < 0 ) { | ||
| 115 | if ( errno == ENOENT ) { | ||
| 116 | return Errors::Log::createLastError( Errors::FileNotFound, dir ); | ||
| 117 | } else { | ||
| 118 | return Errors::Log::createLastError( Errors::Unspecified, | ||
| 119 | std::string( strerror( errno ) ) ); | ||
| 120 | } | ||
| 121 | } | ||
| 122 | |||
| 123 | efDEBUG( "Added watch %s with id: %d\n", dir.c_str(), wd ); | ||
| 124 | |||
| 125 | WatcherInotify* pWatch = new WatcherInotify(); | ||
| 126 | pWatch->Listener = watcher; | ||
| 127 | pWatch->ID = parent ? parent->ID : wd; | ||
| 128 | pWatch->InotifyID = wd; | ||
| 129 | pWatch->Directory = dir; | ||
| 130 | pWatch->Recursive = recursive; | ||
| 131 | pWatch->Parent = parent; | ||
| 132 | |||
| 133 | { | ||
| 134 | Lock lock( mWatchesLock ); | ||
| 135 | mWatches.insert( std::make_pair( wd, pWatch ) ); | ||
| 136 | } | ||
| 137 | |||
| 138 | if ( NULL == pWatch->Parent ) { | ||
| 139 | Lock l( mRealWatchesLock ); | ||
| 140 | mRealWatches[pWatch->InotifyID] = pWatch; | ||
| 141 | } | ||
| 142 | |||
| 143 | if ( pWatch->Recursive ) { | ||
| 144 | std::map<std::string, FileInfo> files = FileSystem::filesInfoFromPath( pWatch->Directory ); | ||
| 145 | std::map<std::string, FileInfo>::iterator it = files.begin(); | ||
| 146 | |||
| 147 | for ( ; it != files.end(); ++it ) { | ||
| 148 | if ( !mInitOK ) | ||
| 149 | break; | ||
| 150 | |||
| 151 | const FileInfo& cfi = it->second; | ||
| 152 | |||
| 153 | if ( cfi.isDirectory() && cfi.isReadable() ) { | ||
| 154 | addWatch( cfi.Filepath, watcher, recursive, pWatch ); | ||
| 155 | } | ||
| 156 | } | ||
| 157 | } | ||
| 158 | |||
| 159 | return wd; | ||
| 160 | } | ||
| 161 | |||
| 162 | void FileWatcherInotify::removeWatchLocked( WatchID watchid ) { | ||
| 163 | WatchMap::iterator iter = mWatches.find( watchid ); | ||
| 164 | |||
| 165 | WatcherInotify* watch = iter->second; | ||
| 166 | |||
| 167 | for ( std::vector<std::pair<WatcherInotify*, std::string>>::iterator itm = | ||
| 168 | mMovedOutsideWatches.begin(); | ||
| 169 | mMovedOutsideWatches.end() != itm; ++itm ) { | ||
| 170 | if ( itm->first == watch ) { | ||
| 171 | mMovedOutsideWatches.erase( itm ); | ||
| 172 | break; | ||
| 173 | } | ||
| 174 | } | ||
| 175 | |||
| 176 | if ( watch->Recursive ) { | ||
| 177 | WatchMap::iterator it = mWatches.begin(); | ||
| 178 | std::list<WatchID> eraseWatches; | ||
| 179 | |||
| 180 | for ( ; it != mWatches.end(); ++it ) { | ||
| 181 | if ( it->second != watch && it->second->inParentTree( watch ) ) { | ||
| 182 | eraseWatches.push_back( it->second->InotifyID ); | ||
| 183 | } | ||
| 184 | } | ||
| 185 | |||
| 186 | for ( std::list<WatchID>::iterator eit = eraseWatches.begin(); eit != eraseWatches.end(); | ||
| 187 | ++eit ) { | ||
| 188 | removeWatch( *eit ); | ||
| 189 | } | ||
| 190 | } | ||
| 191 | |||
| 192 | mWatches.erase( iter ); | ||
| 193 | |||
| 194 | if ( NULL == watch->Parent ) { | ||
| 195 | WatchMap::iterator eraseit = mRealWatches.find( watch->InotifyID ); | ||
| 196 | |||
| 197 | if ( eraseit != mRealWatches.end() ) { | ||
| 198 | mRealWatches.erase( eraseit ); | ||
| 199 | } | ||
| 200 | } | ||
| 201 | |||
| 202 | int err = inotify_rm_watch( mFD, watchid ); | ||
| 203 | |||
| 204 | if ( err < 0 ) { | ||
| 205 | efDEBUG( "Error removing watch %d: %s\n", watchid, strerror( errno ) ); | ||
| 206 | } else { | ||
| 207 | efDEBUG( "Removed watch %s with id: %d\n", watch->Directory.c_str(), watchid ); | ||
| 208 | } | ||
| 209 | |||
| 210 | efSAFE_DELETE( watch ); | ||
| 211 | } | ||
| 212 | |||
| 213 | void FileWatcherInotify::removeWatch( const std::string& directory ) { | ||
| 214 | if ( !mInitOK ) | ||
| 215 | return; | ||
| 216 | Lock initLock( mInitLock ); | ||
| 217 | Lock lock( mWatchesLock ); | ||
| 218 | Lock l( mRealWatchesLock ); | ||
| 219 | |||
| 220 | WatchMap::iterator iter = mWatches.begin(); | ||
| 221 | |||
| 222 | for ( ; iter != mWatches.end(); ++iter ) { | ||
| 223 | if ( directory == iter->second->Directory ) { | ||
| 224 | WatcherInotify* watch = iter->second; | ||
| 225 | |||
| 226 | if ( watch->Recursive ) { | ||
| 227 | WatchMap::iterator it = mWatches.begin(); | ||
| 228 | std::list<WatchID> eraseWatches; | ||
| 229 | |||
| 230 | for ( ; it != mWatches.end(); ++it ) { | ||
| 231 | if ( it->second->inParentTree( watch ) ) { | ||
| 232 | eraseWatches.push_back( it->second->InotifyID ); | ||
| 233 | } | ||
| 234 | } | ||
| 235 | |||
| 236 | for ( std::list<WatchID>::iterator eit = eraseWatches.begin(); | ||
| 237 | eit != eraseWatches.end(); ++eit ) { | ||
| 238 | removeWatchLocked( *eit ); | ||
| 239 | } | ||
| 240 | } | ||
| 241 | |||
| 242 | mWatches.erase( iter ); | ||
| 243 | |||
| 244 | if ( NULL == watch->Parent ) { | ||
| 245 | WatchMap::iterator eraseit = mRealWatches.find( watch->InotifyID ); | ||
| 246 | |||
| 247 | if ( eraseit != mRealWatches.end() ) { | ||
| 248 | mRealWatches.erase( eraseit ); | ||
| 249 | } | ||
| 250 | } | ||
| 251 | |||
| 252 | int err = inotify_rm_watch( mFD, watch->InotifyID ); | ||
| 253 | |||
| 254 | if ( err < 0 ) { | ||
| 255 | efDEBUG( "Error removing watch %d: %s\n", watch->InotifyID, strerror( errno ) ); | ||
| 256 | } else { | ||
| 257 | efDEBUG( "Removed watch %s with id: %d\n", watch->Directory.c_str(), | ||
| 258 | watch->InotifyID ); | ||
| 259 | } | ||
| 260 | |||
| 261 | efSAFE_DELETE( watch ); | ||
| 262 | |||
| 263 | break; | ||
| 264 | } | ||
| 265 | } | ||
| 266 | } | ||
| 267 | |||
| 268 | void FileWatcherInotify::removeWatch( WatchID watchid ) { | ||
| 269 | if ( !mInitOK ) | ||
| 270 | return; | ||
| 271 | Lock initLock( mInitLock ); | ||
| 272 | Lock lock( mWatchesLock ); | ||
| 273 | |||
| 274 | WatchMap::iterator iter = mWatches.find( watchid ); | ||
| 275 | |||
| 276 | if ( iter == mWatches.end() ) { | ||
| 277 | return; | ||
| 278 | } | ||
| 279 | |||
| 280 | removeWatchLocked( watchid ); | ||
| 281 | } | ||
| 282 | |||
| 283 | void FileWatcherInotify::watch() { | ||
| 284 | if ( NULL == mThread ) { | ||
| 285 | mThread = new Thread( &FileWatcherInotify::run, this ); | ||
| 286 | mThread->launch(); | ||
| 287 | } | ||
| 288 | } | ||
| 289 | |||
| 290 | Watcher* FileWatcherInotify::watcherContainsDirectory( std::string dir ) { | ||
| 291 | FileSystem::dirRemoveSlashAtEnd( dir ); | ||
| 292 | std::string watcherPath = FileSystem::pathRemoveFileName( dir ); | ||
| 293 | FileSystem::dirAddSlashAtEnd( watcherPath ); | ||
| 294 | Lock lock( mWatchesLock ); | ||
| 295 | |||
| 296 | for ( WatchMap::iterator it = mWatches.begin(); it != mWatches.end(); ++it ) { | ||
| 297 | Watcher* watcher = it->second; | ||
| 298 | |||
| 299 | if ( watcher->Directory == watcherPath ) { | ||
| 300 | return watcher; | ||
| 301 | } | ||
| 302 | } | ||
| 303 | |||
| 304 | return NULL; | ||
| 305 | } | ||
| 306 | |||
| 307 | void FileWatcherInotify::run() { | ||
| 308 | char* buff = new char[BUFF_SIZE]; | ||
| 309 | memset( buff, 0, BUFF_SIZE ); | ||
| 310 | WatchMap::iterator wit; | ||
| 311 | |||
| 312 | WatcherInotify* currentMoveFrom = NULL; | ||
| 313 | u_int32_t currentMoveCookie = -1; | ||
| 314 | bool lastWasMovedFrom = false; | ||
| 315 | std::string prevOldFileName; | ||
| 316 | |||
| 317 | do { | ||
| 318 | fd_set rfds; | ||
| 319 | FD_ZERO( &rfds ); | ||
| 320 | FD_SET( mFD, &rfds ); | ||
| 321 | timeval timeout; | ||
| 322 | timeout.tv_sec = 0; | ||
| 323 | timeout.tv_usec = 100000; | ||
| 324 | |||
| 325 | if ( select( FD_SETSIZE, &rfds, NULL, NULL, &timeout ) > 0 ) { | ||
| 326 | ssize_t len; | ||
| 327 | |||
| 328 | len = read( mFD, buff, BUFF_SIZE ); | ||
| 329 | |||
| 330 | if ( len != -1 ) { | ||
| 331 | ssize_t i = 0; | ||
| 332 | |||
| 333 | while ( i < len ) { | ||
| 334 | struct inotify_event* pevent = (struct inotify_event*)&buff[i]; | ||
| 335 | |||
| 336 | { | ||
| 337 | { | ||
| 338 | Lock lock( mWatchesLock ); | ||
| 339 | |||
| 340 | wit = mWatches.find( pevent->wd ); | ||
| 341 | } | ||
| 342 | |||
| 343 | if ( wit != mWatches.end() ) { | ||
| 344 | handleAction( wit->second, (char*)pevent->name, pevent->mask ); | ||
| 345 | |||
| 346 | if ( ( pevent->mask & IN_MOVED_TO ) && wit->second == currentMoveFrom && | ||
| 347 | pevent->cookie == currentMoveCookie ) { | ||
| 348 | /// make pair success | ||
| 349 | currentMoveFrom = NULL; | ||
| 350 | currentMoveCookie = -1; | ||
| 351 | } else if ( pevent->mask & IN_MOVED_FROM ) { | ||
| 352 | // Previous event was moved from and current event is moved from | ||
| 353 | // Treat it as a DELETE or moved ouside watches | ||
| 354 | if ( lastWasMovedFrom && currentMoveFrom ) { | ||
| 355 | mMovedOutsideWatches.push_back( | ||
| 356 | std::make_pair( currentMoveFrom, prevOldFileName ) ); | ||
| 357 | } | ||
| 358 | |||
| 359 | currentMoveFrom = wit->second; | ||
| 360 | currentMoveCookie = pevent->cookie; | ||
| 361 | } else { | ||
| 362 | /// Keep track of the IN_MOVED_FROM events to know | ||
| 363 | /// if the IN_MOVED_TO event is also fired | ||
| 364 | if ( currentMoveFrom ) { | ||
| 365 | mMovedOutsideWatches.push_back( | ||
| 366 | std::make_pair( currentMoveFrom, prevOldFileName ) ); | ||
| 367 | } | ||
| 368 | |||
| 369 | currentMoveFrom = NULL; | ||
| 370 | currentMoveCookie = -1; | ||
| 371 | } | ||
| 372 | } | ||
| 373 | |||
| 374 | lastWasMovedFrom = ( pevent->mask & IN_MOVED_FROM ) != 0; | ||
| 375 | if ( pevent->mask & IN_MOVED_FROM ) | ||
| 376 | prevOldFileName = std::string( (char*)pevent->name ); | ||
| 377 | } | ||
| 378 | |||
| 379 | i += sizeof( struct inotify_event ) + pevent->len; | ||
| 380 | } | ||
| 381 | } | ||
| 382 | } else { | ||
| 383 | // Here means no event received | ||
| 384 | // If last event is IN_MOVED_FROM, we assume no IN_MOVED_TO | ||
| 385 | if ( currentMoveFrom ) { | ||
| 386 | mMovedOutsideWatches.push_back( | ||
| 387 | std::make_pair( currentMoveFrom, currentMoveFrom->OldFileName ) ); | ||
| 388 | } | ||
| 389 | |||
| 390 | currentMoveFrom = NULL; | ||
| 391 | currentMoveCookie = -1; | ||
| 392 | } | ||
| 393 | |||
| 394 | if ( !mMovedOutsideWatches.empty() ) { | ||
| 395 | // We need to make a copy since the element mMovedOutsideWatches could be modified | ||
| 396 | // during the iteration. | ||
| 397 | std::vector<std::pair<WatcherInotify*, std::string>> movedOutsideWatches( | ||
| 398 | mMovedOutsideWatches ); | ||
| 399 | |||
| 400 | /// In case that the IN_MOVED_TO is never fired means that the file was moved to other | ||
| 401 | /// folder | ||
| 402 | for ( std::vector<std::pair<WatcherInotify*, std::string>>::iterator it = | ||
| 403 | movedOutsideWatches.begin(); | ||
| 404 | it != movedOutsideWatches.end(); ++it ) { | ||
| 405 | |||
| 406 | // Skip if the watch has already being removed | ||
| 407 | if ( mMovedOutsideWatches.size() != movedOutsideWatches.size() ) { | ||
| 408 | bool found = false; | ||
| 409 | for ( std::vector<std::pair<WatcherInotify*, std::string>>::iterator itm = | ||
| 410 | mMovedOutsideWatches.begin(); | ||
| 411 | mMovedOutsideWatches.end() != itm; ++itm ) { | ||
| 412 | if ( itm->first == it->first ) { | ||
| 413 | found = true; | ||
| 414 | break; | ||
| 415 | } | ||
| 416 | } | ||
| 417 | if ( !found ) | ||
| 418 | continue; | ||
| 419 | } | ||
| 420 | |||
| 421 | Watcher* watch = ( *it ).first; | ||
| 422 | const std::string& oldFileName = ( *it ).second; | ||
| 423 | |||
| 424 | /// Check if the file move was a folder already being watched | ||
| 425 | std::list<Watcher*> eraseWatches; | ||
| 426 | |||
| 427 | { | ||
| 428 | Lock lock( mWatchesLock ); | ||
| 429 | |||
| 430 | for ( ; wit != mWatches.end(); ++wit ) { | ||
| 431 | Watcher* oldWatch = wit->second; | ||
| 432 | |||
| 433 | if ( oldWatch != watch && | ||
| 434 | -1 != String::strStartsWith( watch->Directory + oldFileName + "/", | ||
| 435 | oldWatch->Directory ) ) { | ||
| 436 | eraseWatches.push_back( oldWatch ); | ||
| 437 | } | ||
| 438 | } | ||
| 439 | } | ||
| 440 | |||
| 441 | /// Remove invalid watches | ||
| 442 | eraseWatches.sort(); | ||
| 443 | |||
| 444 | if ( eraseWatches.empty() ) { | ||
| 445 | handleAction( watch, oldFileName, IN_DELETE ); | ||
| 446 | } else { | ||
| 447 | for ( std::list<Watcher*>::reverse_iterator eit = eraseWatches.rbegin(); | ||
| 448 | eit != eraseWatches.rend(); ++eit ) { | ||
| 449 | Watcher* rmWatch = *eit; | ||
| 450 | |||
| 451 | /// Create Delete event for removed watches that have been moved too | ||
| 452 | if ( Watcher* cntWatch = watcherContainsDirectory( rmWatch->Directory ) ) { | ||
| 453 | handleAction( cntWatch, | ||
| 454 | FileSystem::fileNameFromPath( rmWatch->Directory ), | ||
| 455 | IN_DELETE ); | ||
| 456 | } | ||
| 457 | } | ||
| 458 | } | ||
| 459 | } | ||
| 460 | |||
| 461 | mMovedOutsideWatches.clear(); | ||
| 462 | } | ||
| 463 | } while ( mInitOK ); | ||
| 464 | |||
| 465 | delete[] buff; | ||
| 466 | } | ||
| 467 | |||
| 468 | void FileWatcherInotify::checkForNewWatcher( Watcher* watch, std::string fpath ) { | ||
| 469 | FileSystem::dirAddSlashAtEnd( fpath ); | ||
| 470 | |||
| 471 | /// If the watcher is recursive, checks if the new file is a folder, and creates a watcher | ||
| 472 | if ( watch->Recursive && FileSystem::isDirectory( fpath ) ) { | ||
| 473 | bool found = false; | ||
| 474 | |||
| 475 | { | ||
| 476 | Lock lock( mWatchesLock ); | ||
| 477 | |||
| 478 | /// First check if exists | ||
| 479 | for ( WatchMap::iterator it = mWatches.begin(); it != mWatches.end(); ++it ) { | ||
| 480 | if ( it->second->Directory == fpath ) { | ||
| 481 | found = true; | ||
| 482 | break; | ||
| 483 | } | ||
| 484 | } | ||
| 485 | } | ||
| 486 | |||
| 487 | if ( !found ) { | ||
| 488 | addWatch( fpath, watch->Listener, watch->Recursive, | ||
| 489 | static_cast<WatcherInotify*>( watch ) ); | ||
| 490 | } | ||
| 491 | } | ||
| 492 | } | ||
| 493 | |||
| 494 | void FileWatcherInotify::handleAction( Watcher* watch, const std::string& filename, | ||
| 495 | unsigned long action, std::string ) { | ||
| 496 | if ( !watch || !watch->Listener || !mInitOK ) { | ||
| 497 | return; | ||
| 498 | } | ||
| 499 | |||
| 500 | Lock initLock( mInitLock ); | ||
| 501 | |||
| 502 | std::string fpath( watch->Directory + filename ); | ||
| 503 | |||
| 504 | if ( ( IN_CLOSE_WRITE & action ) || ( IN_MODIFY & action ) ) { | ||
| 505 | watch->Listener->handleFileAction( watch->ID, watch->Directory, filename, | ||
| 506 | Actions::Modified ); | ||
| 507 | } else if ( IN_MOVED_TO & action ) { | ||
| 508 | /// If OldFileName doesn't exist means that the file has been moved from other folder, so we | ||
| 509 | /// just send the Add event | ||
| 510 | if ( watch->OldFileName.empty() ) { | ||
| 511 | watch->Listener->handleFileAction( watch->ID, watch->Directory, filename, | ||
| 512 | Actions::Add ); | ||
| 513 | |||
| 514 | watch->Listener->handleFileAction( watch->ID, watch->Directory, filename, | ||
| 515 | Actions::Modified ); | ||
| 516 | |||
| 517 | checkForNewWatcher( watch, fpath ); | ||
| 518 | } else { | ||
| 519 | watch->Listener->handleFileAction( watch->ID, watch->Directory, filename, | ||
| 520 | Actions::Moved, watch->OldFileName ); | ||
| 521 | } | ||
| 522 | |||
| 523 | if ( watch->Recursive && FileSystem::isDirectory( fpath ) ) { | ||
| 524 | /// Update the new directory path | ||
| 525 | std::string opath( watch->Directory + watch->OldFileName ); | ||
| 526 | FileSystem::dirAddSlashAtEnd( opath ); | ||
| 527 | FileSystem::dirAddSlashAtEnd( fpath ); | ||
| 528 | |||
| 529 | Lock lock( mWatchesLock ); | ||
| 530 | |||
| 531 | for ( WatchMap::iterator it = mWatches.begin(); it != mWatches.end(); ++it ) { | ||
| 532 | if ( it->second->Directory == opath ) { | ||
| 533 | it->second->Directory = fpath; | ||
| 534 | it->second->DirInfo = FileInfo( fpath ); | ||
| 535 | } else if ( -1 != String::strStartsWith( opath, it->second->Directory ) ) { | ||
| 536 | it->second->Directory = fpath + it->second->Directory.substr( opath.size() ); | ||
| 537 | it->second->DirInfo.Filepath = it->second->Directory; | ||
| 538 | } | ||
| 539 | } | ||
| 540 | } | ||
| 541 | |||
| 542 | watch->OldFileName = ""; | ||
| 543 | } else if ( IN_CREATE & action ) { | ||
| 544 | watch->Listener->handleFileAction( watch->ID, watch->Directory, filename, Actions::Add ); | ||
| 545 | |||
| 546 | checkForNewWatcher( watch, fpath ); | ||
| 547 | } else if ( IN_MOVED_FROM & action ) { | ||
| 548 | watch->OldFileName = filename; | ||
| 549 | } else if ( IN_DELETE & action ) { | ||
| 550 | watch->Listener->handleFileAction( watch->ID, watch->Directory, filename, Actions::Delete ); | ||
| 551 | |||
| 552 | FileSystem::dirAddSlashAtEnd( fpath ); | ||
| 553 | |||
| 554 | /// If the file erased is a directory and recursive is enabled, removes the directory erased | ||
| 555 | if ( watch->Recursive ) { | ||
| 556 | Lock l( mWatchesLock ); | ||
| 557 | |||
| 558 | for ( WatchMap::iterator it = mWatches.begin(); it != mWatches.end(); ++it ) { | ||
| 559 | if ( it->second->Directory == fpath ) { | ||
| 560 | removeWatchLocked( it->second->InotifyID ); | ||
| 561 | break; | ||
| 562 | } | ||
| 563 | } | ||
| 564 | } | ||
| 565 | } | ||
| 566 | } | ||
| 567 | |||
| 568 | std::list<std::string> FileWatcherInotify::directories() { | ||
| 569 | std::list<std::string> dirs; | ||
| 570 | |||
| 571 | Lock l( mRealWatchesLock ); | ||
| 572 | |||
| 573 | WatchMap::iterator it = mRealWatches.begin(); | ||
| 574 | |||
| 575 | for ( ; it != mRealWatches.end(); ++it ) { | ||
| 576 | dirs.push_back( it->second->Directory ); | ||
| 577 | } | ||
| 578 | |||
| 579 | return dirs; | ||
| 580 | } | ||
| 581 | |||
| 582 | bool FileWatcherInotify::pathInWatches( const std::string& path ) { | ||
| 583 | Lock l( mRealWatchesLock ); | ||
| 584 | |||
| 585 | /// Search in the real watches, since it must allow adding a watch already watched as a subdir | ||
| 586 | WatchMap::iterator it = mRealWatches.begin(); | ||
| 587 | |||
| 588 | for ( ; it != mRealWatches.end(); ++it ) { | ||
| 589 | if ( it->second->Directory == path ) { | ||
| 590 | return true; | ||
| 591 | } | ||
| 592 | } | ||
| 593 | |||
| 594 | return false; | ||
| 595 | } | ||
| 596 | |||
| 597 | } // namespace efsw | ||
| 598 | |||
| 599 | #endif | ||
