mirror of
https://github.com/TrinityCore/TrinityCore.git
synced 2026-02-06 00:48:39 +01:00
* Uses system API's which reduces the overhead instead of checking periodically for changes. * Will be used in the hotswap system to reload shared libraries on changes.
292 lines
5.9 KiB
C++
292 lines
5.9 KiB
C++
#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
|