aboutsummaryrefslogtreecommitdiff
path: root/src/3rdParty/efsw/FileWatcherWin32.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/3rdParty/efsw/FileWatcherWin32.cpp')
-rwxr-xr-xsrc/3rdParty/efsw/FileWatcherWin32.cpp257
1 files changed, 257 insertions, 0 deletions
diff --git a/src/3rdParty/efsw/FileWatcherWin32.cpp b/src/3rdParty/efsw/FileWatcherWin32.cpp
new file mode 100755
index 0000000..963dc98
--- /dev/null
+++ b/src/3rdParty/efsw/FileWatcherWin32.cpp
@@ -0,0 +1,257 @@
1#include <efsw/FileSystem.hpp>
2#include <efsw/FileWatcherWin32.hpp>
3#include <efsw/Lock.hpp>
4#include <efsw/String.hpp>
5#include <efsw/System.hpp>
6
7#if EFSW_PLATFORM == EFSW_PLATFORM_WIN32
8
9namespace efsw {
10
11FileWatcherWin32::FileWatcherWin32( FileWatcher* parent ) :
12 FileWatcherImpl( parent ), mLastWatchID( 0 ), mThread( NULL ) {
13 mIOCP = CreateIoCompletionPort( INVALID_HANDLE_VALUE, NULL, 0, 1 );
14 if ( mIOCP && mIOCP != INVALID_HANDLE_VALUE )
15 mInitOK = true;
16}
17
18FileWatcherWin32::~FileWatcherWin32() {
19 mInitOK = false;
20
21 if ( mIOCP && mIOCP != INVALID_HANDLE_VALUE ) {
22 PostQueuedCompletionStatus( mIOCP, 0, reinterpret_cast<ULONG_PTR>( this ), NULL );
23 }
24
25 efSAFE_DELETE( mThread );
26
27 removeAllWatches();
28
29 CloseHandle( mIOCP );
30}
31
32WatchID FileWatcherWin32::addWatch( const std::string& directory, FileWatchListener* watcher,
33 bool recursive ) {
34 std::string dir( directory );
35
36 FileInfo fi( dir );
37
38 if ( !fi.isDirectory() ) {
39 return Errors::Log::createLastError( Errors::FileNotFound, dir );
40 } else if ( !fi.isReadable() ) {
41 return Errors::Log::createLastError( Errors::FileNotReadable, dir );
42 }
43
44 FileSystem::dirAddSlashAtEnd( dir );
45
46 Lock lock( mWatchesLock );
47
48 if ( pathInWatches( dir ) ) {
49 return Errors::Log::createLastError( Errors::FileRepeated, dir );
50 }
51
52 WatchID watchid = ++mLastWatchID;
53
54 WatcherStructWin32* watch = CreateWatch(
55 String::fromUtf8( dir ).toWideString().c_str(), recursive,
56 FILE_NOTIFY_CHANGE_CREATION | FILE_NOTIFY_CHANGE_LAST_WRITE | FILE_NOTIFY_CHANGE_FILE_NAME |
57 FILE_NOTIFY_CHANGE_DIR_NAME | FILE_NOTIFY_CHANGE_SIZE,
58 mIOCP );
59
60 if ( NULL == watch ) {
61 return Errors::Log::createLastError( Errors::FileNotFound, dir );
62 }
63
64 // Add the handle to the handles vector
65 watch->Watch->ID = watchid;
66 watch->Watch->Watch = this;
67 watch->Watch->Listener = watcher;
68 watch->Watch->DirName = new char[dir.length() + 1];
69 strcpy( watch->Watch->DirName, dir.c_str() );
70
71 mWatches.insert( watch );
72
73 return watchid;
74}
75
76void FileWatcherWin32::removeWatch( const std::string& directory ) {
77 Lock lock( mWatchesLock );
78
79 Watches::iterator iter = mWatches.begin();
80
81 for ( ; iter != mWatches.end(); ++iter ) {
82 if ( directory == ( *iter )->Watch->DirName ) {
83 removeWatch( *iter );
84 break;
85 }
86 }
87}
88
89void FileWatcherWin32::removeWatch( WatchID watchid ) {
90 Lock lock( mWatchesLock );
91
92 Watches::iterator iter = mWatches.begin();
93
94 for ( ; iter != mWatches.end(); ++iter ) {
95 // Find the watch ID
96 if ( ( *iter )->Watch->ID == watchid ) {
97 removeWatch( *iter );
98 return;
99 }
100 }
101}
102
103void FileWatcherWin32::removeWatch( WatcherStructWin32* watch ) {
104 Lock lock( mWatchesLock );
105
106 DestroyWatch( watch );
107 mWatches.erase( watch );
108}
109
110void FileWatcherWin32::watch() {
111 if ( NULL == mThread ) {
112 mThread = new Thread( &FileWatcherWin32::run, this );
113 mThread->launch();
114 }
115}
116
117void FileWatcherWin32::removeAllWatches() {
118 Lock lock( mWatchesLock );
119
120 Watches::iterator iter = mWatches.begin();
121
122 for ( ; iter != mWatches.end(); ++iter ) {
123 DestroyWatch( ( *iter ) );
124 }
125
126 mWatches.clear();
127}
128
129void FileWatcherWin32::run() {
130 do {
131 if ( mInitOK && !mWatches.empty() ) {
132 DWORD numOfBytes = 0;
133 OVERLAPPED* ov = NULL;
134 ULONG_PTR compKey = 0;
135 BOOL res = FALSE;
136
137 while ( ( res = GetQueuedCompletionStatus( mIOCP, &numOfBytes, &compKey, &ov,
138 INFINITE ) ) != FALSE ) {
139 if ( compKey != 0 && compKey == reinterpret_cast<ULONG_PTR>( this ) ) {
140 break;
141 } else {
142 Lock lock( mWatchesLock );
143 WatchCallback( numOfBytes, ov );
144 }
145 }
146 } else {
147 System::sleep( 10 );
148 }
149 } while ( mInitOK );
150
151 removeAllWatches();
152}
153
154void FileWatcherWin32::handleAction( Watcher* watch, const std::string& filename,
155 unsigned long action, std::string /*oldFilename*/ ) {
156 Action fwAction;
157
158 switch ( action ) {
159 case FILE_ACTION_RENAMED_OLD_NAME:
160 watch->OldFileName = filename;
161 return;
162 case FILE_ACTION_ADDED:
163 fwAction = Actions::Add;
164 break;
165 case FILE_ACTION_RENAMED_NEW_NAME: {
166 fwAction = Actions::Moved;
167
168 std::string fpath( watch->Directory + filename );
169
170 // Update the directory path
171 if ( watch->Recursive && FileSystem::isDirectory( fpath ) ) {
172 // Update the new directory path
173 std::string opath( watch->Directory + watch->OldFileName );
174 FileSystem::dirAddSlashAtEnd( opath );
175 FileSystem::dirAddSlashAtEnd( fpath );
176
177 for ( Watches::iterator it = mWatches.begin(); it != mWatches.end(); ++it ) {
178 if ( ( *it )->Watch->Directory == opath ) {
179 ( *it )->Watch->Directory = fpath;
180
181 break;
182 }
183 }
184 }
185
186 std::string folderPath( static_cast<WatcherWin32*>( watch )->DirName );
187 std::string realFilename = filename;
188 std::size_t sepPos = filename.find_last_of( "/\\" );
189 std::string oldFolderPath =
190 static_cast<WatcherWin32*>( watch )->DirName +
191 watch->OldFileName.substr( 0, watch->OldFileName.find_last_of( "/\\" ) );
192
193 if ( sepPos != std::string::npos ) {
194 folderPath += filename.substr( 0, sepPos );
195 realFilename = filename.substr( sepPos + 1 );
196 }
197
198 if ( folderPath == oldFolderPath ) {
199 watch->Listener->handleFileAction(
200 watch->ID, folderPath, realFilename, fwAction,
201 FileSystem::fileNameFromPath( watch->OldFileName ) );
202 } else {
203 watch->Listener->handleFileAction( watch->ID,
204 static_cast<WatcherWin32*>( watch )->DirName,
205 filename, fwAction, watch->OldFileName );
206 }
207 return;
208 }
209 case FILE_ACTION_REMOVED:
210 fwAction = Actions::Delete;
211 break;
212 case FILE_ACTION_MODIFIED:
213 fwAction = Actions::Modified;
214 break;
215 default:
216 return;
217 };
218
219 std::string folderPath( static_cast<WatcherWin32*>( watch )->DirName );
220 std::string realFilename = filename;
221 std::size_t sepPos = filename.find_last_of( "/\\" );
222
223 if ( sepPos != std::string::npos ) {
224 folderPath += filename.substr( 0, sepPos );
225 realFilename = filename.substr( sepPos + 1 );
226 }
227
228 watch->Listener->handleFileAction( watch->ID, folderPath, realFilename, fwAction );
229}
230
231std::list<std::string> FileWatcherWin32::directories() {
232 std::list<std::string> dirs;
233
234 Lock lock( mWatchesLock );
235
236 for ( Watches::iterator it = mWatches.begin(); it != mWatches.end(); ++it ) {
237 dirs.push_back( std::string( ( *it )->Watch->DirName ) );
238 }
239
240 return dirs;
241}
242
243bool FileWatcherWin32::pathInWatches( const std::string& path ) {
244 Lock lock( mWatchesLock );
245
246 for ( Watches::iterator it = mWatches.begin(); it != mWatches.end(); ++it ) {
247 if ( ( *it )->Watch->DirName == path ) {
248 return true;
249 }
250 }
251
252 return false;
253}
254
255} // namespace efsw
256
257#endif