diff options
Diffstat (limited to 'dep/efsw/src/efsw/FileWatcherWin32.cpp')
-rw-r--r-- | dep/efsw/src/efsw/FileWatcherWin32.cpp | 291 |
1 files changed, 291 insertions, 0 deletions
diff --git a/dep/efsw/src/efsw/FileWatcherWin32.cpp b/dep/efsw/src/efsw/FileWatcherWin32.cpp new file mode 100644 index 00000000000..fe78dd122cf --- /dev/null +++ b/dep/efsw/src/efsw/FileWatcherWin32.cpp @@ -0,0 +1,291 @@ +#include <efsw/FileWatcherWin32.hpp> +#include <efsw/FileSystem.hpp> +#include <efsw/System.hpp> +#include <efsw/String.hpp> + +#if EFSW_PLATFORM == EFSW_PLATFORM_WIN32 + +namespace efsw +{ + +FileWatcherWin32::FileWatcherWin32( FileWatcher * parent ) : + FileWatcherImpl( parent ), + mLastWatchID(0), + mThread( NULL ) +{ + mInitOK = true; +} + +FileWatcherWin32::~FileWatcherWin32() +{ + WatchVector::iterator iter = mWatches.begin(); + + mWatchesLock.lock(); + + for(; iter != mWatches.end(); ++iter) + { + DestroyWatch((*iter)); + } + + mHandles.clear(); + mWatches.clear(); + + mInitOK = false; + + mWatchesLock.unlock(); + + efSAFE_DELETE( mThread ); +} + +WatchID FileWatcherWin32::addWatch(const std::string& directory, FileWatchListener* watcher, bool recursive) +{ + std::string dir( directory ); + + FileInfo fi( dir ); + + if ( !fi.isDirectory() ) + { + return Errors::Log::createLastError( Errors::FileNotFound, dir ); + } + else if ( !fi.isReadable() ) + { + return Errors::Log::createLastError( Errors::FileNotReadable, dir ); + } + + FileSystem::dirAddSlashAtEnd( dir ); + + WatchID watchid = ++mLastWatchID; + + mWatchesLock.lock(); + + 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 + ); + + if( NULL == watch ) + { + return Errors::Log::createLastError( Errors::FileNotFound, dir ); + } + + if ( pathInWatches( dir ) ) + { + return Errors::Log::createLastError( Errors::FileRepeated, dir ); + } + + // Add the handle to the handles vector + 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()); + + mHandles.push_back( watch->Watch->DirHandle ); + mWatches.push_back( watch ); + mWatchesLock.unlock(); + + return watchid; +} + +void FileWatcherWin32::removeWatch(const std::string& directory) +{ + mWatchesLock.lock(); + + WatchVector::iterator iter = mWatches.begin(); + + for(; iter != mWatches.end(); ++iter) + { + if(directory == (*iter)->Watch->DirName) + { + removeWatch((*iter)->Watch->ID); + return; + } + } + + mWatchesLock.unlock(); +} + +void FileWatcherWin32::removeWatch(WatchID watchid) +{ + mWatchesLock.lock(); + + WatchVector::iterator iter = mWatches.begin(); + + WatcherStructWin32* watch = NULL; + + for(; iter != mWatches.end(); ++iter) + { + // Find the watch ID + if ( (*iter)->Watch->ID == watchid ) + { + watch = (*iter); + + mWatches.erase( iter ); + + // Remove handle from the handle vector + HandleVector::iterator it = mHandles.begin(); + + for ( ; it != mHandles.end(); it++ ) + { + if ( watch->Watch->DirHandle == (*it) ) + { + mHandles.erase( it ); + break; + } + } + + DestroyWatch(watch); + + break; + } + } + + mWatchesLock.unlock(); +} + +void FileWatcherWin32::watch() +{ + if ( NULL == mThread ) + { + mThread = new Thread( &FileWatcherWin32::run, this ); + mThread->launch(); + } +} + +void FileWatcherWin32::run() +{ + if ( mHandles.empty() ) + { + return; + } + + do + { + if ( !mHandles.empty() ) + { + mWatchesLock.lock(); + + for ( std::size_t i = 0; i < mWatches.size(); i++ ) + { + WatcherStructWin32 * watch = mWatches[ i ]; + + // If the overlapped struct was cancelled ( because the creator thread doesn't exists anymore ), + // we recreate the overlapped in the current thread and refresh the watch + if ( /*STATUS_CANCELED*/0xC0000120 == watch->Overlapped.Internal ) + { + watch->Overlapped = OVERLAPPED(); + RefreshWatch(watch); + } + + // First ensure that the handle is the same, this means that the watch was not removed. + if ( HasOverlappedIoCompleted( &watch->Overlapped ) && mHandles[ i ] == watch->Watch->DirHandle ) + { + DWORD bytes; + + if ( GetOverlappedResult( watch->Watch->DirHandle, &watch->Overlapped, &bytes, FALSE ) ) + { + WatchCallback( ERROR_SUCCESS, bytes, &watch->Overlapped ); + } + } + } + + mWatchesLock.unlock(); + + if ( mInitOK ) + { + System::sleep( 10 ); + } + } + else + { + // Wait for a new handle to be added + System::sleep( 10 ); + } + } while ( mInitOK ); +} + +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 ( WatchVector::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; + }; + + watch->Listener->handleFileAction(watch->ID, static_cast<WatcherWin32*>( watch )->DirName, filename, fwAction); +} + +std::list<std::string> FileWatcherWin32::directories() +{ + std::list<std::string> dirs; + + mWatchesLock.lock(); + + for ( WatchVector::iterator it = mWatches.begin(); it != mWatches.end(); it++ ) + { + dirs.push_back( std::string( (*it)->Watch->DirName ) ); + } + + mWatchesLock.unlock(); + + return dirs; +} + +bool FileWatcherWin32::pathInWatches( const std::string& path ) +{ + for ( WatchVector::iterator it = mWatches.begin(); it != mWatches.end(); it++ ) + { + if ( (*it)->Watch->DirName == path ) + { + return true; + } + } + + return false; +} + +} + +#endif |