diff options
Diffstat (limited to 'dep/efsw/src/efsw/FileWatcherInotify.cpp')
-rw-r--r-- | dep/efsw/src/efsw/FileWatcherInotify.cpp | 630 |
1 files changed, 308 insertions, 322 deletions
diff --git a/dep/efsw/src/efsw/FileWatcherInotify.cpp b/dep/efsw/src/efsw/FileWatcherInotify.cpp index 71ae3bcd97d..29be12b6262 100644 --- a/dep/efsw/src/efsw/FileWatcherInotify.cpp +++ b/dep/efsw/src/efsw/FileWatcherInotify.cpp @@ -1,13 +1,14 @@ +#include <algorithm> #include <efsw/FileWatcherInotify.hpp> #if EFSW_PLATFORM == EFSW_PLATFORM_INOTIFY -#include <unistd.h> -#include <sys/stat.h> +#include <errno.h> #include <fcntl.h> -#include <string.h> #include <stdio.h> -#include <errno.h> +#include <string.h> +#include <sys/stat.h> +#include <unistd.h> #ifdef EFSW_INOTIFY_NOSYS #include <efsw/inotify-nosys.h> @@ -15,84 +16,81 @@ #include <sys/inotify.h> #endif -#include <efsw/FileSystem.hpp> -#include <efsw/System.hpp> #include <efsw/Debug.hpp> +#include <efsw/FileSystem.hpp> #include <efsw/Lock.hpp> #include <efsw/String.hpp> +#include <efsw/System.hpp> -#define BUFF_SIZE ((sizeof(struct inotify_event)+FILENAME_MAX)*1024) +#define BUFF_SIZE ( ( sizeof( struct inotify_event ) + FILENAME_MAX ) * 1024 ) -namespace efsw -{ +namespace efsw { -FileWatcherInotify::FileWatcherInotify( FileWatcher * parent ) : - FileWatcherImpl( parent ), - mFD(-1), - mThread(NULL) -{ +FileWatcherInotify::FileWatcherInotify( FileWatcher* parent ) : + FileWatcherImpl( parent ), mFD( -1 ), mThread( NULL ), mIsTakingAction( false ) { mFD = inotify_init(); - if (mFD < 0) - { - efDEBUG( "Error: %s\n", strerror(errno) ); - } - else - { + if ( mFD < 0 ) { + efDEBUG( "Error: %s\n", strerror( errno ) ); + } else { mInitOK = true; } } -FileWatcherInotify::~FileWatcherInotify() -{ +FileWatcherInotify::~FileWatcherInotify() { mInitOK = false; + // There is deadlock when release FileWatcherInotify instance since its handAction + // function is still running and hangs in requiring lock without init lock captured. + while ( mIsTakingAction ) { + // It'd use condition-wait instead of sleep. Actually efsw has no such + // implementation so we just skip and sleep while for that to avoid deadlock. + usleep( 1000 ); + }; + Lock initLock( mInitLock ); efSAFE_DELETE( mThread ); - + + Lock l( mWatchesLock ); + Lock l2( mRealWatchesLock ); + WatchMap::iterator iter = mWatches.begin(); WatchMap::iterator end = mWatches.end(); - for(; iter != end; ++iter) - { + for ( ; iter != end; ++iter ) { efSAFE_DELETE( iter->second ); } mWatches.clear(); - if ( mFD != -1 ) - { - close(mFD); + if ( mFD != -1 ) { + close( mFD ); mFD = -1; } } -WatchID FileWatcherInotify::addWatch( const std::string& directory, FileWatchListener* watcher, bool recursive ) -{ +WatchID FileWatcherInotify::addWatch( const std::string& directory, FileWatchListener* watcher, + bool recursive, const std::vector<WatcherOption>& ) { + if ( !mInitOK ) + return Errors::Log::createLastError( Errors::Unspecified, directory ); + Lock initLock( mInitLock ); return addWatch( directory, watcher, recursive, NULL ); } -WatchID FileWatcherInotify::addWatch( const std::string& directory, FileWatchListener* watcher, bool recursive, WatcherInotify * parent ) -{ +WatchID FileWatcherInotify::addWatch( const std::string& directory, FileWatchListener* watcher, + bool recursive, WatcherInotify* parent ) { std::string dir( directory ); FileSystem::dirAddSlashAtEnd( dir ); FileInfo fi( dir ); - if ( !fi.isDirectory() ) - { + if ( !fi.isDirectory() ) { return Errors::Log::createLastError( Errors::FileNotFound, dir ); - } - else if ( !fi.isReadable() ) - { + } else if ( !fi.isReadable() ) { return Errors::Log::createLastError( Errors::FileNotReadable, dir ); - } - else if ( pathInWatches( dir ) ) - { + } else if ( pathInWatches( dir ) ) { return Errors::Log::createLastError( Errors::FileRepeated, directory ); - } - else if ( NULL != parent && FileSystem::isRemoteFS( dir ) ) - { + } else if ( NULL != parent && FileSystem::isRemoteFS( dir ) ) { return Errors::Log::createLastError( Errors::FileRemote, dir ); } @@ -100,74 +98,68 @@ WatchID FileWatcherInotify::addWatch( const std::string& directory, FileWatchLis std::string curPath; std::string link( FileSystem::getLinkRealPath( dir, curPath ) ); - if ( "" != link ) - { + if ( "" != link ) { /// Avoid adding symlinks directories if it's now enabled - if ( NULL != parent && !mFileWatcher->followSymlinks() ) - { + if ( NULL != parent && !mFileWatcher->followSymlinks() ) { return Errors::Log::createLastError( Errors::FileOutOfScope, dir ); } /// If it's a symlink check if the realpath exists as a watcher, or /// if the path is outside the current dir - if ( pathInWatches( link ) ) - { + if ( pathInWatches( link ) ) { return Errors::Log::createLastError( Errors::FileRepeated, directory ); - } - else if ( !linkAllowed( curPath, link ) ) - { + } else if ( !linkAllowed( curPath, link ) ) { return Errors::Log::createLastError( Errors::FileOutOfScope, dir ); - } - else - { + } else { dir = link; } } - int wd = inotify_add_watch (mFD, dir.c_str(), IN_CLOSE_WRITE | IN_MOVED_TO | IN_CREATE | IN_MOVED_FROM | IN_DELETE | IN_MODIFY); + int wd = inotify_add_watch( mFD, dir.c_str(), + IN_CLOSE_WRITE | IN_MOVED_TO | IN_CREATE | IN_MOVED_FROM | + IN_DELETE | IN_MODIFY ); - if ( wd < 0 ) - { - if( errno == ENOENT ) - { + if ( wd < 0 ) { + if ( errno == ENOENT ) { return Errors::Log::createLastError( Errors::FileNotFound, dir ); - } - else - { - return Errors::Log::createLastError( Errors::Unspecified, std::string(strerror(errno)) ); + } else { + return Errors::Log::createLastError( Errors::Unspecified, + std::string( strerror( errno ) ) ); } } efDEBUG( "Added watch %s with id: %d\n", dir.c_str(), wd ); - WatcherInotify * pWatch = new WatcherInotify(); - pWatch->Listener = watcher; - pWatch->ID = wd; - pWatch->Directory = dir; - pWatch->Recursive = recursive; - pWatch->Parent = parent; + WatcherInotify* pWatch = new WatcherInotify(); + pWatch->Listener = watcher; + pWatch->ID = parent ? parent->ID : wd; + pWatch->InotifyID = wd; + pWatch->Directory = dir; + pWatch->Recursive = recursive; + pWatch->Parent = parent; { Lock lock( mWatchesLock ); - mWatches.insert(std::make_pair(wd, pWatch)); + mWatches.insert( std::make_pair( wd, pWatch ) ); + mWatchesRef[pWatch->Directory] = wd; } - if ( NULL == pWatch->Parent ) - { - mRealWatches[ pWatch->ID ] = pWatch; + if ( NULL == pWatch->Parent ) { + Lock l( mRealWatchesLock ); + mRealWatches[pWatch->InotifyID] = pWatch; } - if ( pWatch->Recursive ) - { + if ( pWatch->Recursive ) { std::map<std::string, FileInfo> files = FileSystem::filesInfoFromPath( pWatch->Directory ); std::map<std::string, FileInfo>::iterator it = files.begin(); - for ( ; it != files.end(); ++it ) - { + for ( ; it != files.end(); ++it ) { + if ( !mInitOK ) + break; + const FileInfo& cfi = it->second; - if ( cfi.isDirectory() && cfi.isReadable() ) - { + if ( cfi.isDirectory() && cfi.isReadable() ) { addWatch( cfi.Filepath, watcher, recursive, pWatch ); } } @@ -176,401 +168,395 @@ WatchID FileWatcherInotify::addWatch( const std::string& directory, FileWatchLis return wd; } -void FileWatcherInotify::removeWatchLocked(WatchID watchid) -{ +void FileWatcherInotify::removeWatchLocked( WatchID watchid ) { WatchMap::iterator iter = mWatches.find( watchid ); + if ( iter == mWatches.end() ) + return; - WatcherInotify * watch = iter->second; + WatcherInotify* watch = iter->second; - if ( watch->Recursive ) - { + for ( std::vector<std::pair<WatcherInotify*, std::string>>::iterator itm = + mMovedOutsideWatches.begin(); + mMovedOutsideWatches.end() != itm; ++itm ) { + if ( itm->first == watch ) { + mMovedOutsideWatches.erase( itm ); + break; + } + } + + if ( watch->Recursive && NULL == watch->Parent ) { WatchMap::iterator it = mWatches.begin(); - std::list<WatchID> eraseWatches; + std::vector<WatchID> eraseWatches; - for(; it != mWatches.end(); ++it) - { - if ( it->second != watch && - it->second->inParentTree( watch ) - ) - { - eraseWatches.push_back( it->second->ID ); - } - } + for ( ; it != mWatches.end(); ++it ) + if ( it->second != watch && it->second->inParentTree( watch ) ) + eraseWatches.push_back( it->second->InotifyID ); - for ( std::list<WatchID>::iterator eit = eraseWatches.begin(); eit != eraseWatches.end(); ++eit ) - { + for ( std::vector<WatchID>::iterator eit = eraseWatches.begin(); eit != eraseWatches.end(); + ++eit ) { removeWatch( *eit ); } } + mWatchesRef.erase( watch->Directory ); mWatches.erase( iter ); - if ( NULL == watch->Parent ) - { - WatchMap::iterator eraseit = mRealWatches.find( watch->ID ); + if ( NULL == watch->Parent ) { + WatchMap::iterator eraseit = mRealWatches.find( watch->InotifyID ); - if ( eraseit != mRealWatches.end() ) - { + if ( eraseit != mRealWatches.end() ) { mRealWatches.erase( eraseit ); } } - int err = inotify_rm_watch(mFD, watchid); + int err = inotify_rm_watch( mFD, watchid ); - if ( err < 0 ) - { - efDEBUG( "Error removing watch %d: %s\n", watchid, strerror(errno) ); - } - else - { + if ( err < 0 ) { + efDEBUG( "Error removing watch %d: %s\n", watchid, strerror( errno ) ); + } else { efDEBUG( "Removed watch %s with id: %d\n", watch->Directory.c_str(), watchid ); } efSAFE_DELETE( watch ); } -void FileWatcherInotify::removeWatch(const std::string& directory) -{ +void FileWatcherInotify::removeWatch( const std::string& directory ) { + if ( !mInitOK ) + return; + Lock initLock( mInitLock ); Lock lock( mWatchesLock ); + Lock l( mRealWatchesLock ); - WatchMap::iterator iter = mWatches.begin(); - - for(; iter != mWatches.end(); ++iter) - { - if( directory == iter->second->Directory ) - { - WatcherInotify * watch = iter->second; - - if ( watch->Recursive ) - { - WatchMap::iterator it = mWatches.begin(); - std::list<WatchID> eraseWatches; - - for(; it != mWatches.end(); ++it) - { - if ( it->second->inParentTree( watch ) ) - { - eraseWatches.push_back( it->second->ID ); - } - } - - for ( std::list<WatchID>::iterator eit = eraseWatches.begin(); eit != eraseWatches.end(); ++eit ) - { - removeWatchLocked( *eit ); - } - } - - mWatches.erase( iter ); - - if ( NULL == watch->Parent ) - { - WatchMap::iterator eraseit = mRealWatches.find( watch->ID ); - - if ( eraseit != mRealWatches.end() ) - { - mRealWatches.erase( eraseit ); - } - } - - int err = inotify_rm_watch(mFD, watch->ID); - - if ( err < 0 ) - { - efDEBUG( "Error removing watch %d: %s\n", watch->ID, strerror(errno) ); - } - else - { - efDEBUG( "Removed watch %s with id: %d\n", watch->Directory.c_str(), watch->ID ); - } - - efSAFE_DELETE( watch ); + std::unordered_map<std::string, WatchID>::iterator ref = mWatchesRef.find( directory ); + if ( ref == mWatchesRef.end() ) + return; - break; - } - } + removeWatchLocked( ref->second ); } -void FileWatcherInotify::removeWatch( WatchID watchid ) -{ - Lock lock( mWatchesLock ); - - WatchMap::iterator iter = mWatches.find( watchid ); - - if( iter == mWatches.end() ) - { +void FileWatcherInotify::removeWatch( WatchID watchid ) { + if ( !mInitOK ) return; - } - + Lock initLock( mInitLock ); + Lock lock( mWatchesLock ); removeWatchLocked( watchid ); } -void FileWatcherInotify::watch() -{ - if ( NULL == mThread ) - { +void FileWatcherInotify::watch() { + if ( NULL == mThread ) { mThread = new Thread( &FileWatcherInotify::run, this ); mThread->launch(); } } -Watcher * FileWatcherInotify::watcherContainsDirectory( std::string dir ) -{ +Watcher* FileWatcherInotify::watcherContainsDirectory( std::string dir ) { FileSystem::dirRemoveSlashAtEnd( dir ); std::string watcherPath = FileSystem::pathRemoveFileName( dir ); FileSystem::dirAddSlashAtEnd( watcherPath ); + Lock lock( mWatchesLock ); - for ( WatchMap::iterator it = mWatches.begin(); it != mWatches.end(); ++it ) - { - Watcher * watcher = it->second; - + for ( WatchMap::iterator it = mWatches.begin(); it != mWatches.end(); ++it ) { + Watcher* watcher = it->second; if ( watcher->Directory == watcherPath ) - { return watcher; - } } return NULL; } -void FileWatcherInotify::run() -{ - static char buff[BUFF_SIZE] = {0}; +void FileWatcherInotify::run() { + char* buff = new char[BUFF_SIZE]; + memset( buff, 0, BUFF_SIZE ); WatchMap::iterator wit; - std::list<WatcherInotify*> movedOutsideWatches; - do - { + WatcherInotify* currentMoveFrom = NULL; + u_int32_t currentMoveCookie = -1; + bool lastWasMovedFrom = false; + std::string prevOldFileName; + + do { fd_set rfds; - FD_ZERO (&rfds); - FD_SET (mFD, &rfds); + FD_ZERO( &rfds ); + FD_SET( mFD, &rfds ); timeval timeout; - timeout.tv_sec=0; - timeout.tv_usec=100000; + timeout.tv_sec = 0; + timeout.tv_usec = 100000; - if( select (FD_SETSIZE, &rfds, NULL, NULL, &timeout) > 0 ) - { + if ( select( FD_SETSIZE, &rfds, NULL, NULL, &timeout ) > 0 ) { ssize_t len; - len = read (mFD, buff, BUFF_SIZE); + len = read( mFD, buff, BUFF_SIZE ); - if (len != -1) - { + if ( len != -1 ) { ssize_t i = 0; - while (i < len) - { - struct inotify_event *pevent = (struct inotify_event *)&buff[i]; + while ( i < len ) { + struct inotify_event* pevent = (struct inotify_event*)&buff[i]; { - Lock lock( mWatchesLock ); + { + Lock lock( mWatchesLock ); - wit = mWatches.find( pevent->wd ); + wit = mWatches.find( pevent->wd ); + } - if ( wit != mWatches.end() ) - { - handleAction(wit->second, pevent->name, pevent->mask); + if ( wit != mWatches.end() ) { + handleAction( wit->second, (char*)pevent->name, pevent->mask ); + + if ( ( pevent->mask & IN_MOVED_TO ) && wit->second == currentMoveFrom && + pevent->cookie == currentMoveCookie ) { + /// make pair success + currentMoveFrom = NULL; + currentMoveCookie = -1; + } else if ( pevent->mask & IN_MOVED_FROM ) { + // Previous event was moved from and current event is moved from + // Treat it as a DELETE or moved ouside watches + if ( lastWasMovedFrom && currentMoveFrom ) { + mMovedOutsideWatches.push_back( + std::make_pair( currentMoveFrom, prevOldFileName ) ); + } + + currentMoveFrom = wit->second; + currentMoveCookie = pevent->cookie; + } else { + /// Keep track of the IN_MOVED_FROM events to know + /// if the IN_MOVED_TO event is also fired + if ( currentMoveFrom ) { + mMovedOutsideWatches.push_back( + std::make_pair( currentMoveFrom, prevOldFileName ) ); + } - /// Keep track of the IN_MOVED_FROM events to know if the IN_MOVED_TO event is also fired - if ( !wit->second->OldFileName.empty() ) - { - movedOutsideWatches.push_back( wit->second ); + currentMoveFrom = NULL; + currentMoveCookie = -1; } } + + lastWasMovedFrom = ( pevent->mask & IN_MOVED_FROM ) != 0; + if ( pevent->mask & IN_MOVED_FROM ) + prevOldFileName = std::string( (char*)pevent->name ); } - i += sizeof(struct inotify_event) + pevent->len; + i += sizeof( struct inotify_event ) + pevent->len; } + } + } else { + // Here means no event received + // If last event is IN_MOVED_FROM, we assume no IN_MOVED_TO + if ( currentMoveFrom ) { + mMovedOutsideWatches.push_back( + std::make_pair( currentMoveFrom, currentMoveFrom->OldFileName ) ); + } - if ( !movedOutsideWatches.empty() ) - { - /// In case that the IN_MOVED_TO is never fired means that the file was moved to other folder - for ( std::list<WatcherInotify*>::iterator it = movedOutsideWatches.begin(); it != movedOutsideWatches.end(); ++it ) - { - Watcher * watch = (*it); - - if ( !watch->OldFileName.empty() ) - { - /// Check if the file move was a folder already being watched - std::list<Watcher*> eraseWatches; - - for(; wit != mWatches.end(); ++wit) - { - Watcher * oldWatch = wit->second; + currentMoveFrom = NULL; + currentMoveCookie = -1; + } - if ( oldWatch != watch && - -1 != String::strStartsWith( watch->Directory + watch->OldFileName + "/", oldWatch->Directory ) ) - { - eraseWatches.push_back( oldWatch ); - } - } + if ( !mMovedOutsideWatches.empty() ) { + // We need to make a copy since the element mMovedOutsideWatches could be modified + // during the iteration. + std::vector<std::pair<WatcherInotify*, std::string>> movedOutsideWatches( + mMovedOutsideWatches ); + + /// In case that the IN_MOVED_TO is never fired means that the file was moved to other + /// folder + for ( std::vector<std::pair<WatcherInotify*, std::string>>::iterator it = + movedOutsideWatches.begin(); + it != movedOutsideWatches.end(); ++it ) { + + // Skip if the watch has already being removed + if ( mMovedOutsideWatches.size() != movedOutsideWatches.size() ) { + bool found = false; + for ( std::vector<std::pair<WatcherInotify*, std::string>>::iterator itm = + mMovedOutsideWatches.begin(); + mMovedOutsideWatches.end() != itm; ++itm ) { + if ( itm->first == it->first ) { + found = true; + break; + } + } + if ( !found ) + continue; + } - /// Remove invalid watches - eraseWatches.sort(); + Watcher* watch = ( *it ).first; + const std::string& oldFileName = ( *it ).second; - for ( std::list<Watcher*>::reverse_iterator eit = eraseWatches.rbegin(); eit != eraseWatches.rend(); ++eit ) - { - Watcher * rmWatch = *eit; + /// Check if the file move was a folder already being watched + std::vector<Watcher*> eraseWatches; - /// Create Delete event for removed watches that have been moved too - if ( Watcher * cntWatch = watcherContainsDirectory( rmWatch->Directory ) ) - { - handleAction( cntWatch, FileSystem::fileNameFromPath( rmWatch->Directory ), IN_DELETE ); - } + { + Lock lock( mWatchesLock ); - removeWatch( rmWatch->ID ); - } + for ( ; wit != mWatches.end(); ++wit ) { + Watcher* oldWatch = wit->second; - /// Remove the OldFileName - watch->OldFileName = ""; + if ( oldWatch != watch && + -1 != String::strStartsWith( watch->Directory + oldFileName + "/", + oldWatch->Directory ) ) { + eraseWatches.push_back( oldWatch ); } } + } - movedOutsideWatches.clear(); + /// Remove invalid watches + std::stable_sort( eraseWatches.begin(), eraseWatches.end(), + []( const Watcher* left, const Watcher* right ) { + return left->Directory < right->Directory; + } ); + + if ( eraseWatches.empty() ) { + handleAction( watch, oldFileName, IN_DELETE ); + } else { + for ( std::vector<Watcher*>::reverse_iterator eit = eraseWatches.rbegin(); + eit != eraseWatches.rend(); ++eit ) { + Watcher* rmWatch = *eit; + + /// Create Delete event for removed watches that have been moved too + if ( Watcher* cntWatch = watcherContainsDirectory( rmWatch->Directory ) ) { + handleAction( cntWatch, + FileSystem::fileNameFromPath( rmWatch->Directory ), + IN_DELETE ); + } + } } } + + mMovedOutsideWatches.clear(); } - } while( mInitOK ); + } while ( mInitOK ); + + delete[] buff; } -void FileWatcherInotify::checkForNewWatcher( Watcher* watch, std::string fpath ) -{ +void FileWatcherInotify::checkForNewWatcher( Watcher* watch, std::string fpath ) { FileSystem::dirAddSlashAtEnd( fpath ); /// If the watcher is recursive, checks if the new file is a folder, and creates a watcher - if ( watch->Recursive && FileSystem::isDirectory( fpath ) ) - { + if ( watch->Recursive && FileSystem::isDirectory( fpath ) ) { bool found = false; - /// First check if exists - for ( WatchMap::iterator it = mWatches.begin(); it != mWatches.end(); ++it ) { - if ( it->second->Directory == fpath ) - { - found = true; - break; + Lock lock( mWatchesLock ); + + /// First check if exists + for ( WatchMap::iterator it = mWatches.begin(); it != mWatches.end(); ++it ) { + if ( it->second->Directory == fpath ) { + found = true; + break; + } } } - if ( !found ) - { - addWatch( fpath, watch->Listener, watch->Recursive, static_cast<WatcherInotify*>( watch ) ); + if ( !found ) { + addWatch( fpath, watch->Listener, watch->Recursive, + static_cast<WatcherInotify*>( watch ) ); } } } -void FileWatcherInotify::handleAction( Watcher* watch, const std::string& filename, unsigned long action, std::string ) -{ - if ( !watch || !watch->Listener ) - { +void FileWatcherInotify::handleAction( Watcher* watch, const std::string& filename, + unsigned long action, std::string ) { + if ( !watch || !watch->Listener || !mInitOK ) { return; } + mIsTakingAction = true; + Lock initLock( mInitLock ); std::string fpath( watch->Directory + filename ); - if ( ( IN_CLOSE_WRITE & action ) || ( IN_MODIFY & action ) ) - { - watch->Listener->handleFileAction( watch->ID, watch->Directory, filename, Actions::Modified ); - } - else if( IN_MOVED_TO & action ) - { - /// If OldFileName doesn't exist means that the file has been moved from other folder, so we just send the Add event - if ( watch->OldFileName.empty() ) - { - watch->Listener->handleFileAction( watch->ID, watch->Directory, filename, Actions::Add ); + if ( ( IN_CLOSE_WRITE & action ) || ( IN_MODIFY & action ) ) { + watch->Listener->handleFileAction( watch->ID, watch->Directory, filename, + Actions::Modified ); + } else if ( IN_MOVED_TO & action ) { + /// If OldFileName doesn't exist means that the file has been moved from other folder, so we + /// just send the Add event + if ( watch->OldFileName.empty() ) { + watch->Listener->handleFileAction( watch->ID, watch->Directory, filename, + Actions::Add ); - watch->Listener->handleFileAction( watch->ID, watch->Directory, filename, Actions::Modified ); + watch->Listener->handleFileAction( watch->ID, watch->Directory, filename, + Actions::Modified ); checkForNewWatcher( watch, fpath ); - } - else - { - watch->Listener->handleFileAction( watch->ID, watch->Directory, filename, Actions::Moved, watch->OldFileName ); + } else { + watch->Listener->handleFileAction( watch->ID, watch->Directory, filename, + Actions::Moved, watch->OldFileName ); } - if ( watch->Recursive && FileSystem::isDirectory( fpath ) ) - { + if ( watch->Recursive && FileSystem::isDirectory( fpath ) ) { /// Update the new directory path std::string opath( watch->Directory + watch->OldFileName ); FileSystem::dirAddSlashAtEnd( opath ); FileSystem::dirAddSlashAtEnd( fpath ); - for ( WatchMap::iterator it = mWatches.begin(); it != mWatches.end(); ++it ) - { - if ( it->second->Directory == opath && it->second->DirInfo.Inode == FileInfo( opath ).Inode ) - { - it->second->Directory = fpath; - it->second->DirInfo = FileInfo( fpath ); + Lock lock( mWatchesLock ); - break; + for ( WatchMap::iterator it = mWatches.begin(); it != mWatches.end(); ++it ) { + if ( it->second->Directory == opath ) { + it->second->Directory = fpath; + it->second->DirInfo = FileInfo( fpath ); + } else if ( -1 != String::strStartsWith( opath, it->second->Directory ) ) { + it->second->Directory = fpath + it->second->Directory.substr( opath.size() ); + it->second->DirInfo.Filepath = it->second->Directory; } } } watch->OldFileName = ""; - } - else if( IN_CREATE & action ) - { + } else if ( IN_CREATE & action ) { watch->Listener->handleFileAction( watch->ID, watch->Directory, filename, Actions::Add ); checkForNewWatcher( watch, fpath ); - } - else if ( IN_MOVED_FROM & action ) - { + } else if ( IN_MOVED_FROM & action ) { watch->OldFileName = filename; - } - else if( IN_DELETE & action ) - { + } else if ( IN_DELETE & action ) { watch->Listener->handleFileAction( watch->ID, watch->Directory, filename, Actions::Delete ); FileSystem::dirAddSlashAtEnd( fpath ); /// If the file erased is a directory and recursive is enabled, removes the directory erased - if ( watch->Recursive ) - { - for ( WatchMap::iterator it = mWatches.begin(); it != mWatches.end(); ++it ) - { - if ( it->second->Directory == fpath ) - { - removeWatch( it->second->ID ); + if ( watch->Recursive ) { + Lock l( mWatchesLock ); + + for ( WatchMap::iterator it = mWatches.begin(); it != mWatches.end(); ++it ) { + if ( it->second->Directory == fpath ) { + removeWatchLocked( it->second->InotifyID ); break; } } } } + mIsTakingAction = false; } -std::list<std::string> FileWatcherInotify::directories() -{ - std::list<std::string> dirs; +std::vector<std::string> FileWatcherInotify::directories() { + std::vector<std::string> dirs; - Lock lock( mWatchesLock ); + Lock l( mRealWatchesLock ); + + dirs.reserve( mRealWatches.size() ); WatchMap::iterator it = mRealWatches.begin(); for ( ; it != mRealWatches.end(); ++it ) - { dirs.push_back( it->second->Directory ); - } return dirs; } -bool FileWatcherInotify::pathInWatches( const std::string& path ) -{ +bool FileWatcherInotify::pathInWatches( const std::string& path ) { + Lock l( mRealWatchesLock ); + /// Search in the real watches, since it must allow adding a watch already watched as a subdir WatchMap::iterator it = mRealWatches.begin(); for ( ; it != mRealWatches.end(); ++it ) - { if ( it->second->Directory == path ) - { return true; - } - } return false; } -} +} // namespace efsw #endif |