aboutsummaryrefslogtreecommitdiff
path: root/src/3rdParty/efsw/WatcherWin32.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/3rdParty/efsw/WatcherWin32.cpp')
-rw-r--r--[-rwxr-xr-x]src/3rdParty/efsw/WatcherWin32.cpp214
1 files changed, 184 insertions, 30 deletions
diff --git a/src/3rdParty/efsw/WatcherWin32.cpp b/src/3rdParty/efsw/WatcherWin32.cpp
index 3e8bcc7..712419e 100755..100644
--- a/src/3rdParty/efsw/WatcherWin32.cpp
+++ b/src/3rdParty/efsw/WatcherWin32.cpp
@@ -1,34 +1,114 @@
1#include <efsw/Debug.hpp>
1#include <efsw/String.hpp> 2#include <efsw/String.hpp>
2#include <efsw/WatcherWin32.hpp> 3#include <efsw/WatcherWin32.hpp>
3 4
4#if EFSW_PLATFORM == EFSW_PLATFORM_WIN32 5#if EFSW_PLATFORM == EFSW_PLATFORM_WIN32
5 6
7#include <algorithm>
8
6namespace efsw { 9namespace efsw {
7 10
8/// Unpacks events and passes them to a user defined callback. 11struct EFSW_FILE_NOTIFY_EXTENDED_INFORMATION_EX {
9void CALLBACK WatchCallback( DWORD dwNumberOfBytesTransfered, LPOVERLAPPED lpOverlapped ) { 12 DWORD NextEntryOffset;
10 if ( dwNumberOfBytesTransfered == 0 || NULL == lpOverlapped ) { 13 DWORD Action;
11 return; 14 LARGE_INTEGER CreationTime;
15 LARGE_INTEGER LastModificationTime;
16 LARGE_INTEGER LastChangeTime;
17 LARGE_INTEGER LastAccessTime;
18 LARGE_INTEGER AllocatedLength;
19 LARGE_INTEGER FileSize;
20 DWORD FileAttributes;
21 DWORD ReparsePointTag;
22 LARGE_INTEGER FileId;
23 LARGE_INTEGER ParentFileId;
24 DWORD FileNameLength;
25 WCHAR FileName[1];
26};
27
28typedef EFSW_FILE_NOTIFY_EXTENDED_INFORMATION_EX* EFSW_PFILE_NOTIFY_EXTENDED_INFORMATION_EX;
29
30typedef BOOL( WINAPI* EFSW_LPREADDIRECTORYCHANGESEXW )( HANDLE hDirectory, LPVOID lpBuffer,
31 DWORD nBufferLength, BOOL bWatchSubtree,
32 DWORD dwNotifyFilter, LPDWORD lpBytesReturned,
33 LPOVERLAPPED lpOverlapped, LPOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine,
34 DWORD ReadDirectoryNotifyInformationClass );
35
36static EFSW_LPREADDIRECTORYCHANGESEXW pReadDirectoryChangesExW = NULL;
37
38#define EFSW_ReadDirectoryNotifyExtendedInformation 2
39
40static void initReadDirectoryChangesEx() {
41 static bool hasInit = false;
42 if ( !hasInit ) {
43 hasInit = true;
44
45 HMODULE hModule = GetModuleHandleW( L"Kernel32.dll" );
46 if ( !hModule )
47 return;
48
49 pReadDirectoryChangesExW =
50 (EFSW_LPREADDIRECTORYCHANGESEXW)GetProcAddress( hModule, "ReadDirectoryChangesExW" );
12 } 51 }
52}
13 53
14 char szFile[MAX_PATH]; 54void WatchCallbackOld( WatcherWin32* pWatch ) {
15 PFILE_NOTIFY_INFORMATION pNotify; 55 PFILE_NOTIFY_INFORMATION pNotify;
16 WatcherStructWin32* tWatch = (WatcherStructWin32*)lpOverlapped;
17 WatcherWin32* pWatch = tWatch->Watch;
18 size_t offset = 0; 56 size_t offset = 0;
19
20 do { 57 do {
21 bool skip = false; 58 bool skip = false;
22 59
23 pNotify = (PFILE_NOTIFY_INFORMATION)&pWatch->Buffer[offset]; 60 pNotify = (PFILE_NOTIFY_INFORMATION)&pWatch->Buffer[offset];
24 offset += pNotify->NextEntryOffset; 61 offset += pNotify->NextEntryOffset;
62 int count =
63 WideCharToMultiByte( CP_UTF8, 0, pNotify->FileName,
64 pNotify->FileNameLength / sizeof( WCHAR ), NULL, 0, NULL, NULL );
65 if ( count == 0 )
66 continue;
67
68 std::string nfile( count, '\0' );
69
70 count = WideCharToMultiByte( CP_UTF8, 0, pNotify->FileName,
71 pNotify->FileNameLength / sizeof( WCHAR ), &nfile[0], count,
72 NULL, NULL );
73
74 if ( FILE_ACTION_MODIFIED == pNotify->Action ) {
75 FileInfo fifile( std::string( pWatch->DirName ) + nfile );
76
77 if ( pWatch->LastModifiedEvent.file.ModificationTime == fifile.ModificationTime &&
78 pWatch->LastModifiedEvent.file.Size == fifile.Size &&
79 pWatch->LastModifiedEvent.fileName == nfile ) {
80 skip = true;
81 }
82
83 pWatch->LastModifiedEvent.fileName = nfile;
84 pWatch->LastModifiedEvent.file = fifile;
85 }
86
87 if ( !skip ) {
88 pWatch->Watch->handleAction( pWatch, nfile, pNotify->Action );
89 }
90 } while ( pNotify->NextEntryOffset != 0 );
91}
92
93void WatchCallbackEx( WatcherWin32* pWatch ) {
94 EFSW_PFILE_NOTIFY_EXTENDED_INFORMATION_EX pNotify;
95 size_t offset = 0;
96 do {
97 bool skip = false;
98
99 pNotify = (EFSW_PFILE_NOTIFY_EXTENDED_INFORMATION_EX)&pWatch->Buffer[offset];
100 offset += pNotify->NextEntryOffset;
101 int count =
102 WideCharToMultiByte( CP_UTF8, 0, pNotify->FileName,
103 pNotify->FileNameLength / sizeof( WCHAR ), NULL, 0, NULL, NULL );
104 if ( count == 0 )
105 continue;
25 106
26 int count = WideCharToMultiByte( CP_UTF8, 0, pNotify->FileName, 107 std::string nfile( count, '\0' );
27 pNotify->FileNameLength / sizeof( WCHAR ), szFile,
28 MAX_PATH - 1, NULL, NULL );
29 szFile[count] = TEXT( '\0' );
30 108
31 std::string nfile( szFile ); 109 count = WideCharToMultiByte( CP_UTF8, 0, pNotify->FileName,
110 pNotify->FileNameLength / sizeof( WCHAR ), &nfile[0], count,
111 NULL, NULL );
32 112
33 if ( FILE_ACTION_MODIFIED == pNotify->Action ) { 113 if ( FILE_ACTION_MODIFIED == pNotify->Action ) {
34 FileInfo fifile( std::string( pWatch->DirName ) + nfile ); 114 FileInfo fifile( std::string( pWatch->DirName ) + nfile );
@@ -41,12 +121,59 @@ void CALLBACK WatchCallback( DWORD dwNumberOfBytesTransfered, LPOVERLAPPED lpOve
41 121
42 pWatch->LastModifiedEvent.fileName = nfile; 122 pWatch->LastModifiedEvent.fileName = nfile;
43 pWatch->LastModifiedEvent.file = fifile; 123 pWatch->LastModifiedEvent.file = fifile;
124 } else if ( FILE_ACTION_RENAMED_OLD_NAME == pNotify->Action ) {
125 pWatch->OldFiles.emplace_back( nfile, pNotify->FileId );
126 skip = true;
127 } else if ( FILE_ACTION_RENAMED_NEW_NAME == pNotify->Action ) {
128 std::string oldFile;
129 LARGE_INTEGER oldFileId{};
130
131 for ( auto it = pWatch->OldFiles.begin(); it != pWatch->OldFiles.end(); ++it ) {
132 if ( it->second.QuadPart == pNotify->FileId.QuadPart ) {
133 oldFile = it->first;
134 oldFileId = it->second;
135 it = pWatch->OldFiles.erase( it );
136 break;
137 }
138 }
139
140 if ( oldFile.empty() ) {
141 pWatch->Watch->handleAction( pWatch, nfile, FILE_ACTION_ADDED );
142 skip = true;
143 } else {
144 pWatch->Watch->handleAction( pWatch, oldFile, FILE_ACTION_RENAMED_OLD_NAME );
145 }
44 } 146 }
45 147
46 if ( !skip ) { 148 if ( !skip ) {
47 pWatch->Watch->handleAction( pWatch, nfile, pNotify->Action ); 149 pWatch->Watch->handleAction( pWatch, nfile, pNotify->Action );
48 } 150 }
49 } while ( pNotify->NextEntryOffset != 0 ); 151 } while ( pNotify->NextEntryOffset != 0 );
152}
153
154/// Unpacks events and passes them to a user defined callback.
155void CALLBACK WatchCallback( DWORD dwNumberOfBytesTransfered, LPOVERLAPPED lpOverlapped ) {
156 if ( NULL == lpOverlapped ) {
157 return;
158 }
159
160 WatcherStructWin32* tWatch = (WatcherStructWin32*)lpOverlapped;
161 WatcherWin32* pWatch = tWatch->Watch;
162
163 if ( dwNumberOfBytesTransfered == 0 ) {
164 if ( nullptr != pWatch && !pWatch->StopNow ) {
165 RefreshWatch( tWatch );
166 } else {
167 return;
168 }
169 }
170
171 // Fork watch depending on the Windows API supported
172 if ( pWatch->Extended ) {
173 WatchCallbackEx( pWatch );
174 } else {
175 WatchCallbackOld( pWatch );
176 }
50 177
51 if ( !pWatch->StopNow ) { 178 if ( !pWatch->StopNow ) {
52 RefreshWatch( tWatch ); 179 RefreshWatch( tWatch );
@@ -54,11 +181,40 @@ void CALLBACK WatchCallback( DWORD dwNumberOfBytesTransfered, LPOVERLAPPED lpOve
54} 181}
55 182
56/// Refreshes the directory monitoring. 183/// Refreshes the directory monitoring.
57bool RefreshWatch( WatcherStructWin32* pWatch ) { 184RefreshResult RefreshWatch( WatcherStructWin32* pWatch ) {
58 return ReadDirectoryChangesW( pWatch->Watch->DirHandle, pWatch->Watch->Buffer, 185 initReadDirectoryChangesEx();
59 sizeof( pWatch->Watch->Buffer ), pWatch->Watch->Recursive, 186
60 pWatch->Watch->NotifyFilter, NULL, &pWatch->Overlapped, 187 bool bRet = false;
61 NULL ) != 0; 188 RefreshResult ret = RefreshResult::Failed;
189 pWatch->Watch->Extended = false;
190
191 if ( pReadDirectoryChangesExW ) {
192 bRet = pReadDirectoryChangesExW( pWatch->Watch->DirHandle, pWatch->Watch->Buffer.data(),
193 (DWORD)pWatch->Watch->Buffer.size(), pWatch->Watch->Recursive,
194 pWatch->Watch->NotifyFilter, NULL, &pWatch->Overlapped,
195 NULL, EFSW_ReadDirectoryNotifyExtendedInformation ) != 0;
196 if ( bRet ) {
197 ret = RefreshResult::SucessEx;
198 pWatch->Watch->Extended = true;
199 }
200 }
201
202 if ( !bRet ) {
203 bRet = ReadDirectoryChangesW( pWatch->Watch->DirHandle, pWatch->Watch->Buffer.data(),
204 (DWORD)pWatch->Watch->Buffer.size(), pWatch->Watch->Recursive,
205 pWatch->Watch->NotifyFilter, NULL, &pWatch->Overlapped,
206 NULL ) != 0;
207
208 if ( bRet )
209 ret = RefreshResult::Success;
210 }
211
212 if ( !bRet ) {
213 std::string error = std::to_string( GetLastError() );
214 Errors::Log::createLastError( Errors::WatcherFailed, error );
215 }
216
217 return ret;
62} 218}
63 219
64/// Stops monitoring a directory. 220/// Stops monitoring a directory.
@@ -70,19 +226,17 @@ void DestroyWatch( WatcherStructWin32* pWatch ) {
70 CloseHandle( pWatch->Watch->DirHandle ); 226 CloseHandle( pWatch->Watch->DirHandle );
71 efSAFE_DELETE_ARRAY( pWatch->Watch->DirName ); 227 efSAFE_DELETE_ARRAY( pWatch->Watch->DirName );
72 efSAFE_DELETE( pWatch->Watch ); 228 efSAFE_DELETE( pWatch->Watch );
229 efSAFE_DELETE( pWatch );
73 } 230 }
74} 231}
75 232
76/// Starts monitoring a directory. 233/// Starts monitoring a directory.
77WatcherStructWin32* CreateWatch( LPCWSTR szDirectory, bool recursive, DWORD NotifyFilter, 234WatcherStructWin32* CreateWatch( LPCWSTR szDirectory, bool recursive,
78 HANDLE iocp ) { 235 DWORD bufferSize, DWORD notifyFilter, HANDLE iocp ) {
79 WatcherStructWin32* tWatch; 236 WatcherStructWin32* tWatch = new WatcherStructWin32();
80 size_t ptrsize = sizeof( *tWatch ); 237 WatcherWin32* pWatch = new WatcherWin32(bufferSize);
81 tWatch = static_cast<WatcherStructWin32*>( 238 if (tWatch)
82 HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, ptrsize ) ); 239 tWatch->Watch = pWatch;
83
84 WatcherWin32* pWatch = new WatcherWin32();
85 tWatch->Watch = pWatch;
86 240
87 pWatch->DirHandle = CreateFileW( 241 pWatch->DirHandle = CreateFileW(
88 szDirectory, GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, NULL, 242 szDirectory, GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, NULL,
@@ -90,17 +244,17 @@ WatcherStructWin32* CreateWatch( LPCWSTR szDirectory, bool recursive, DWORD Noti
90 244
91 if ( pWatch->DirHandle != INVALID_HANDLE_VALUE && 245 if ( pWatch->DirHandle != INVALID_HANDLE_VALUE &&
92 CreateIoCompletionPort( pWatch->DirHandle, iocp, 0, 1 ) ) { 246 CreateIoCompletionPort( pWatch->DirHandle, iocp, 0, 1 ) ) {
93 pWatch->NotifyFilter = NotifyFilter; 247 pWatch->NotifyFilter = notifyFilter;
94 pWatch->Recursive = recursive; 248 pWatch->Recursive = recursive;
95 249
96 if ( RefreshWatch( tWatch ) ) { 250 if ( RefreshResult::Failed != RefreshWatch( tWatch ) ) {
97 return tWatch; 251 return tWatch;
98 } 252 }
99 } 253 }
100 254
101 CloseHandle( pWatch->DirHandle ); 255 CloseHandle( pWatch->DirHandle );
102 efSAFE_DELETE( pWatch->Watch ); 256 efSAFE_DELETE( pWatch->Watch );
103 HeapFree( GetProcessHeap(), 0, tWatch ); 257 efSAFE_DELETE( tWatch );
104 return NULL; 258 return NULL;
105} 259}
106 260