diff options
Diffstat (limited to 'dep/efsw/src/efsw/FileWatcherWin32.cpp')
-rw-r--r-- | dep/efsw/src/efsw/FileWatcherWin32.cpp | 332 |
1 files changed, 142 insertions, 190 deletions
diff --git a/dep/efsw/src/efsw/FileWatcherWin32.cpp b/dep/efsw/src/efsw/FileWatcherWin32.cpp index 317506fb3e3..37f43cc27da 100644 --- a/dep/efsw/src/efsw/FileWatcherWin32.cpp +++ b/dep/efsw/src/efsw/FileWatcherWin32.cpp @@ -1,41 +1,43 @@ -#include <efsw/FileWatcherWin32.hpp> #include <efsw/FileSystem.hpp> -#include <efsw/System.hpp> -#include <efsw/String.hpp> +#include <efsw/FileWatcherWin32.hpp> #include <efsw/Lock.hpp> +#include <efsw/String.hpp> +#include <efsw/System.hpp> #if EFSW_PLATFORM == EFSW_PLATFORM_WIN32 -namespace efsw -{ +namespace efsw { -FileWatcherWin32::FileWatcherWin32( FileWatcher * parent ) : - FileWatcherImpl( parent ), - mLastWatchID(0), - mThread( NULL ) -{ - mInitOK = true; +FileWatcherWin32::FileWatcherWin32( FileWatcher* parent ) : + FileWatcherImpl( parent ), mLastWatchID( 0 ), mThread( NULL ) { + mIOCP = CreateIoCompletionPort( INVALID_HANDLE_VALUE, NULL, 0, 1 ); + if ( mIOCP && mIOCP != INVALID_HANDLE_VALUE ) + mInitOK = true; } -FileWatcherWin32::~FileWatcherWin32() -{ +FileWatcherWin32::~FileWatcherWin32() { mInitOK = false; + + if ( mIOCP && mIOCP != INVALID_HANDLE_VALUE ) { + PostQueuedCompletionStatus( mIOCP, 0, reinterpret_cast<ULONG_PTR>( this ), NULL ); + } + efSAFE_DELETE( mThread ); + removeAllWatches(); + + CloseHandle( mIOCP ); } -WatchID FileWatcherWin32::addWatch(const std::string& directory, FileWatchListener* watcher, bool recursive) -{ +WatchID FileWatcherWin32::addWatch( const std::string& directory, FileWatchListener* watcher, + bool recursive, const std::vector<WatcherOption> &options ) { std::string dir( directory ); 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 ); } @@ -43,22 +45,22 @@ WatchID FileWatcherWin32::addWatch(const std::string& directory, FileWatchListen Lock lock( mWatchesLock ); - if ( pathInWatches( dir ) ) - { + if ( pathInWatches( dir ) ) { return Errors::Log::createLastError( Errors::FileRepeated, dir ); } WatchID watchid = ++mLastWatchID; - WatcherStructWin32 * watch = CreateWatch( String::fromUtf8( dir ).toWideString().c_str(), recursive, FILE_NOTIFY_CHANGE_CREATION | - FILE_NOTIFY_CHANGE_LAST_WRITE | - FILE_NOTIFY_CHANGE_FILE_NAME | - FILE_NOTIFY_CHANGE_DIR_NAME | - FILE_NOTIFY_CHANGE_SIZE - ); + DWORD bufferSize = static_cast<DWORD>( getOptionValue(options, Option::WinBufferSize, 63 * 1024) ); + DWORD notifyFilter = static_cast<DWORD>( getOptionValue(options, Option::WinNotifyFilter, + FILE_NOTIFY_CHANGE_CREATION | FILE_NOTIFY_CHANGE_LAST_WRITE | + FILE_NOTIFY_CHANGE_FILE_NAME | FILE_NOTIFY_CHANGE_DIR_NAME | + FILE_NOTIFY_CHANGE_SIZE) ); - if( NULL == watch ) - { + WatcherStructWin32* watch = CreateWatch( String::fromUtf8( dir ).toWideString().c_str(), + recursive, bufferSize, notifyFilter, mIOCP ); + + if ( NULL == watch ) { return Errors::Log::createLastError( Errors::FileNotFound, dir ); } @@ -66,241 +68,191 @@ WatchID FileWatcherWin32::addWatch(const std::string& directory, FileWatchListen watch->Watch->ID = watchid; watch->Watch->Watch = this; watch->Watch->Listener = watcher; - watch->Watch->DirName = new char[dir.length()+1]; - strcpy(watch->Watch->DirName, dir.c_str()); + watch->Watch->DirName = new char[dir.length() + 1]; + strcpy( watch->Watch->DirName, dir.c_str() ); - mWatchesNew.insert( watch ); mWatches.insert( watch ); return watchid; } -void FileWatcherWin32::removeWatch(const std::string& directory) -{ +void FileWatcherWin32::removeWatch( const std::string& directory ) { Lock lock( mWatchesLock ); Watches::iterator iter = mWatches.begin(); - for(; iter != mWatches.end(); ++iter) - { - if(directory == (*iter)->Watch->DirName) - { - removeWatch(*iter); + for ( ; iter != mWatches.end(); ++iter ) { + if ( directory == ( *iter )->Watch->DirName ) { + removeWatch( *iter ); break; } } } -void FileWatcherWin32::removeWatch(WatchID watchid) -{ +void FileWatcherWin32::removeWatch( WatchID watchid ) { Lock lock( mWatchesLock ); Watches::iterator iter = mWatches.begin(); - for(; iter != mWatches.end(); ++iter) - { + for ( ; iter != mWatches.end(); ++iter ) { // Find the watch ID - if ( (*iter)->Watch->ID == watchid ) - { - removeWatch(*iter); + if ( ( *iter )->Watch->ID == watchid ) { + removeWatch( *iter ); return; } } } -void FileWatcherWin32::removeWatch(WatcherStructWin32* watch) -{ - mWatchesRemoved.insert(watch); - - if( NULL == mThread ) - { - removeWatches(); - } -} - -void FileWatcherWin32::removeWatches() -{ +void FileWatcherWin32::removeWatch( WatcherStructWin32* watch ) { Lock lock( mWatchesLock ); - Watches::iterator remWatchIter = mWatchesRemoved.begin(); - - for( ; remWatchIter != mWatchesRemoved.end(); ++remWatchIter ) - { - Watches::iterator iter = mWatches.find(*remWatchIter); - - if( iter != mWatches.end() ) - { - DestroyWatch(*iter); - - mWatches.erase( iter ); - } - - iter = mWatchesNew.find(*remWatchIter); - - if( iter != mWatchesNew.end() ) - { - mWatchesNew.erase( iter ); - } - } - - mWatchesRemoved.clear(); + DestroyWatch( watch ); + mWatches.erase( watch ); } -void FileWatcherWin32::watch() -{ - if ( NULL == mThread ) - { +void FileWatcherWin32::watch() { + if ( NULL == mThread ) { mThread = new Thread( &FileWatcherWin32::run, this ); mThread->launch(); } } -void FileWatcherWin32::removeAllWatches() -{ +void FileWatcherWin32::removeAllWatches() { Lock lock( mWatchesLock ); Watches::iterator iter = mWatches.begin(); - for( ; iter != mWatches.end(); ++iter ) - { - DestroyWatch((*iter)); + for ( ; iter != mWatches.end(); ++iter ) { + DestroyWatch( ( *iter ) ); } mWatches.clear(); - mWatchesRemoved.clear(); - mWatchesNew.clear(); } -void FileWatcherWin32::run() -{ - do - { - if ( !mWatches.empty() ) - { - { - Lock lock( mWatchesLock ); - - for( Watches::iterator iter = mWatches.begin() ; iter != mWatches.end(); ++iter ) - { - WatcherStructWin32 * watch = *iter; - - if ( HasOverlappedIoCompleted( &watch->Overlapped ) ) - { - DWORD bytes; - - if ( GetOverlappedResult( watch->Watch->DirHandle, &watch->Overlapped, &bytes, FALSE ) ) - { - WatchCallback( ERROR_SUCCESS, bytes, &watch->Overlapped ); - } - } +void FileWatcherWin32::run() { + do { + if ( mInitOK && !mWatches.empty() ) { + DWORD numOfBytes = 0; + OVERLAPPED* ov = NULL; + ULONG_PTR compKey = 0; + BOOL res = FALSE; + + while ( ( res = GetQueuedCompletionStatus( mIOCP, &numOfBytes, &compKey, &ov, + INFINITE ) ) != FALSE ) { + if ( compKey != 0 && compKey == reinterpret_cast<ULONG_PTR>( this ) ) { + break; + } else { + Lock lock( mWatchesLock ); + WatchCallback( numOfBytes, ov ); } } - - if ( mInitOK ) - { - System::sleep( 10 ); - } - } - else - { - // Wait for a new handle to be added + } else { System::sleep( 10 ); } - - removeWatches(); - - for ( Watches::iterator it = mWatchesNew.begin(); it != mWatchesNew.end(); ++it ) - { - RefreshWatch(*it); - } - - mWatchesNew.clear(); } while ( mInitOK ); removeAllWatches(); } -void FileWatcherWin32::handleAction(Watcher* watch, const std::string& filename, unsigned long action, std::string oldFilename) -{ +void FileWatcherWin32::handleAction( Watcher* watch, const std::string& filename, + unsigned long action, std::string /*oldFilename*/ ) { Action fwAction; - switch(action) - { - case FILE_ACTION_RENAMED_OLD_NAME: - watch->OldFileName = filename; - return; - case FILE_ACTION_ADDED: - fwAction = Actions::Add; - break; - case FILE_ACTION_RENAMED_NEW_NAME: - { - fwAction = Actions::Moved; - - std::string fpath( watch->Directory + filename ); - - // Update the directory path - 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 ( Watches::iterator it = mWatches.begin(); it != mWatches.end(); ++it ) - { - if ( (*it)->Watch->Directory == opath ) - { - (*it)->Watch->Directory = fpath; + switch ( action ) { + case FILE_ACTION_RENAMED_OLD_NAME: + watch->OldFileName = filename; + return; + case FILE_ACTION_ADDED: + fwAction = Actions::Add; + break; + case FILE_ACTION_RENAMED_NEW_NAME: { + fwAction = Actions::Moved; + + std::string fpath( watch->Directory + filename ); - break; + // Update the directory path + 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 ( Watches::iterator it = mWatches.begin(); it != mWatches.end(); ++it ) { + if ( ( *it )->Watch->Directory == opath ) { + ( *it )->Watch->Directory = fpath; + + break; + } } } - } - watch->Listener->handleFileAction(watch->ID, static_cast<WatcherWin32*>( watch )->DirName, filename, fwAction, watch->OldFileName); - return; - } - case FILE_ACTION_REMOVED: - fwAction = Actions::Delete; - break; - case FILE_ACTION_MODIFIED: - fwAction = Actions::Modified; - break; + std::string folderPath( static_cast<WatcherWin32*>( watch )->DirName ); + std::string realFilename = filename; + std::size_t sepPos = filename.find_last_of( "/\\" ); + std::string oldFolderPath = + static_cast<WatcherWin32*>( watch )->DirName + + watch->OldFileName.substr( 0, watch->OldFileName.find_last_of( "/\\" ) ); + + if ( sepPos != std::string::npos ) { + folderPath += + filename.substr( 0, sepPos + 1 < filename.size() ? sepPos + 1 : sepPos ); + realFilename = filename.substr( sepPos + 1 ); + } + + if ( folderPath == oldFolderPath ) { + watch->Listener->handleFileAction( + watch->ID, folderPath, realFilename, fwAction, + FileSystem::fileNameFromPath( watch->OldFileName ) ); + } else { + watch->Listener->handleFileAction( watch->ID, + static_cast<WatcherWin32*>( watch )->DirName, + filename, fwAction, watch->OldFileName ); + } + return; + } + case FILE_ACTION_REMOVED: + fwAction = Actions::Delete; + break; + case FILE_ACTION_MODIFIED: + fwAction = Actions::Modified; + break; + default: + return; }; std::string folderPath( static_cast<WatcherWin32*>( watch )->DirName ); std::string realFilename = filename; - std::size_t sepPos = filename.find_last_of("/\\"); + std::size_t sepPos = filename.find_last_of( "/\\" ); - if ( sepPos != std::string::npos ) - { - folderPath += filename.substr( 0, sepPos ); + if ( sepPos != std::string::npos ) { + folderPath += filename.substr( 0, sepPos + 1 < filename.size() ? sepPos + 1 : sepPos ); realFilename = filename.substr( sepPos + 1 ); } - watch->Listener->handleFileAction(watch->ID, folderPath, realFilename, fwAction); + FileSystem::dirAddSlashAtEnd( folderPath ); + + watch->Listener->handleFileAction( watch->ID, folderPath, realFilename, fwAction ); } -std::list<std::string> FileWatcherWin32::directories() -{ - std::list<std::string> dirs; +std::vector<std::string> FileWatcherWin32::directories() { + std::vector<std::string> dirs; Lock lock( mWatchesLock ); - for ( Watches::iterator it = mWatches.begin(); it != mWatches.end(); ++it ) - { - dirs.push_back( std::string( (*it)->Watch->DirName ) ); + dirs.reserve( mWatches.size() ); + + for ( Watches::iterator it = mWatches.begin(); it != mWatches.end(); ++it ) { + dirs.push_back( std::string( ( *it )->Watch->DirName ) ); } return dirs; } -bool FileWatcherWin32::pathInWatches( const std::string& path ) -{ - for ( Watches::iterator it = mWatches.begin(); it != mWatches.end(); ++it ) - { - if ( (*it)->Watch->DirName == path ) - { +bool FileWatcherWin32::pathInWatches( const std::string& path ) { + Lock lock( mWatchesLock ); + + for ( Watches::iterator it = mWatches.begin(); it != mWatches.end(); ++it ) { + if ( ( *it )->Watch->DirName == path ) { return true; } } @@ -308,6 +260,6 @@ bool FileWatcherWin32::pathInWatches( const std::string& path ) return false; } -} +} // namespace efsw #endif |