diff options
| author | Li Jin <dragon-fly@qq.com> | 2025-04-09 17:40:13 +0800 |
|---|---|---|
| committer | Li Jin <dragon-fly@qq.com> | 2025-04-09 17:40:13 +0800 |
| commit | 9750786a5c03b5ce3ea22b240d1b3cd34990856b (patch) | |
| tree | e495e43245e1bacc86d33142af202613a82a40c1 /src/3rdParty/efsw/WatcherWin32.cpp | |
| parent | 571fb952b99e580a0381f539885f8f175e2ec3b0 (diff) | |
| download | yuescript-9750786a5c03b5ce3ea22b240d1b3cd34990856b.tar.gz yuescript-9750786a5c03b5ce3ea22b240d1b3cd34990856b.tar.bz2 yuescript-9750786a5c03b5ce3ea22b240d1b3cd34990856b.zip | |
Updated efsw. Fixed issue #204.
Diffstat (limited to 'src/3rdParty/efsw/WatcherWin32.cpp')
| -rw-r--r--[-rwxr-xr-x] | src/3rdParty/efsw/WatcherWin32.cpp | 214 |
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 | |||
| 6 | namespace efsw { | 9 | namespace efsw { |
| 7 | 10 | ||
| 8 | /// Unpacks events and passes them to a user defined callback. | 11 | struct EFSW_FILE_NOTIFY_EXTENDED_INFORMATION_EX { |
| 9 | void 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 | |||
| 28 | typedef EFSW_FILE_NOTIFY_EXTENDED_INFORMATION_EX* EFSW_PFILE_NOTIFY_EXTENDED_INFORMATION_EX; | ||
| 29 | |||
| 30 | typedef 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 | |||
| 36 | static EFSW_LPREADDIRECTORYCHANGESEXW pReadDirectoryChangesExW = NULL; | ||
| 37 | |||
| 38 | #define EFSW_ReadDirectoryNotifyExtendedInformation 2 | ||
| 39 | |||
| 40 | static 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]; | 54 | void 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 | |||
| 93 | void 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. | ||
| 155 | void 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. |
| 57 | bool RefreshWatch( WatcherStructWin32* pWatch ) { | 184 | RefreshResult 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. |
| 77 | WatcherStructWin32* CreateWatch( LPCWSTR szDirectory, bool recursive, DWORD NotifyFilter, | 234 | WatcherStructWin32* 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 | ||
