1*aceb79b2SNicolas Bonnefon /* 2*aceb79b2SNicolas Bonnefon * Copyright (C) 2015 Nicolas Bonnefon and other contributors 3*aceb79b2SNicolas Bonnefon * 4*aceb79b2SNicolas Bonnefon * This file is part of glogg. 5*aceb79b2SNicolas Bonnefon * 6*aceb79b2SNicolas Bonnefon * glogg is free software: you can redistribute it and/or modify 7*aceb79b2SNicolas Bonnefon * it under the terms of the GNU General Public License as published by 8*aceb79b2SNicolas Bonnefon * the Free Software Foundation, either version 3 of the License, or 9*aceb79b2SNicolas Bonnefon * (at your option) any later version. 10*aceb79b2SNicolas Bonnefon * 11*aceb79b2SNicolas Bonnefon * glogg is distributed in the hope that it will be useful, 12*aceb79b2SNicolas Bonnefon * but WITHOUT ANY WARRANTY; without even the implied warranty of 13*aceb79b2SNicolas Bonnefon * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14*aceb79b2SNicolas Bonnefon * GNU General Public License for more details. 15*aceb79b2SNicolas Bonnefon * 16*aceb79b2SNicolas Bonnefon * You should have received a copy of the GNU General Public License 17*aceb79b2SNicolas Bonnefon * along with glogg. If not, see <http://www.gnu.org/licenses/>. 18*aceb79b2SNicolas Bonnefon */ 19*aceb79b2SNicolas Bonnefon 20f09fa651SNicolas Bonnefon #include "winwatchtowerdriver.h" 21f09fa651SNicolas Bonnefon 22f09fa651SNicolas Bonnefon #define WIN32_LEAN_AND_MEAN 23f09fa651SNicolas Bonnefon #include <windows.h> 24f09fa651SNicolas Bonnefon #include <winbase.h> 25f09fa651SNicolas Bonnefon 26f09fa651SNicolas Bonnefon #include <map> 27f09fa651SNicolas Bonnefon 28f09fa651SNicolas Bonnefon #include "watchtowerlist.h" 29f09fa651SNicolas Bonnefon #include "utils.h" 30f09fa651SNicolas Bonnefon #include "log.h" 31f09fa651SNicolas Bonnefon 32f09fa651SNicolas Bonnefon namespace { 33f09fa651SNicolas Bonnefon std::string shortstringize( const std::wstring& long_string ); 34f09fa651SNicolas Bonnefon std::wstring longstringize( const std::string& short_string ); 35f09fa651SNicolas Bonnefon }; 36f09fa651SNicolas Bonnefon 37f09fa651SNicolas Bonnefon // Utility classes 38f09fa651SNicolas Bonnefon 39f09fa651SNicolas Bonnefon WinNotificationInfoList::WinNotificationInfoList( const char* buffer, size_t buffer_size ) 40f09fa651SNicolas Bonnefon { 41f09fa651SNicolas Bonnefon pointer_ = buffer; 42f09fa651SNicolas Bonnefon next_ = updateCurrentNotification( pointer_ ); 43f09fa651SNicolas Bonnefon } 44f09fa651SNicolas Bonnefon 45f09fa651SNicolas Bonnefon const char* WinNotificationInfoList::updateCurrentNotification( 46f09fa651SNicolas Bonnefon const char* new_position ) 47f09fa651SNicolas Bonnefon { 48f09fa651SNicolas Bonnefon using Action = WinNotificationInfo::Action; 49f09fa651SNicolas Bonnefon 50f09fa651SNicolas Bonnefon static const std::map<uint16_t, Action> int_to_action = { 51f09fa651SNicolas Bonnefon { FILE_ACTION_ADDED, Action::ADDED }, 52f09fa651SNicolas Bonnefon { FILE_ACTION_REMOVED, Action::REMOVED }, 53f09fa651SNicolas Bonnefon { FILE_ACTION_MODIFIED, Action::MODIFIED }, 54f09fa651SNicolas Bonnefon { FILE_ACTION_RENAMED_OLD_NAME, Action::RENAMED_OLD_NAME }, 55f09fa651SNicolas Bonnefon { FILE_ACTION_RENAMED_NEW_NAME, Action::RENAMED_NEW_NAME }, 56f09fa651SNicolas Bonnefon }; 57f09fa651SNicolas Bonnefon 58f09fa651SNicolas Bonnefon uint32_t next_offset = *( reinterpret_cast<const uint32_t*>( new_position ) ); 59f09fa651SNicolas Bonnefon uint32_t action = *( reinterpret_cast<const uint32_t*>( new_position ) + 1 ); 60f09fa651SNicolas Bonnefon uint32_t length = *( reinterpret_cast<const uint32_t*>( new_position ) + 2 ); 61f09fa651SNicolas Bonnefon 62f09fa651SNicolas Bonnefon const std::wstring file_name = { reinterpret_cast<const wchar_t*>( new_position + 12 ), length / 2 }; 63f09fa651SNicolas Bonnefon 64f09fa651SNicolas Bonnefon LOG(logDEBUG) << "Next: " << next_offset; 65f09fa651SNicolas Bonnefon LOG(logDEBUG) << "Action: " << action; 66f09fa651SNicolas Bonnefon LOG(logDEBUG) << "Length: " << length; 67f09fa651SNicolas Bonnefon 68f09fa651SNicolas Bonnefon current_notification_ = WinNotificationInfo( int_to_action.at( action ), file_name ); 69f09fa651SNicolas Bonnefon 70f09fa651SNicolas Bonnefon return ( next_offset == 0 ) ? nullptr : new_position + next_offset; 71f09fa651SNicolas Bonnefon } 72f09fa651SNicolas Bonnefon 73f09fa651SNicolas Bonnefon const char* WinNotificationInfoList::advanceToNext() 74f09fa651SNicolas Bonnefon { 75f09fa651SNicolas Bonnefon pointer_ = next_; 76f09fa651SNicolas Bonnefon if ( pointer_ ) 77f09fa651SNicolas Bonnefon next_ = updateCurrentNotification( pointer_ ); 78f09fa651SNicolas Bonnefon 79f09fa651SNicolas Bonnefon return pointer_; 80f09fa651SNicolas Bonnefon } 81f09fa651SNicolas Bonnefon 82fcaa7557SNicolas Bonnefon // WinWatchTowerDriver::FileChangeToken 83fcaa7557SNicolas Bonnefon 84fcaa7557SNicolas Bonnefon void WinWatchTowerDriver::FileChangeToken::readFromFile( 85fcaa7557SNicolas Bonnefon const std::string& file_name ) 86fcaa7557SNicolas Bonnefon { 87fcaa7557SNicolas Bonnefon // On Windows, we open the file and get its last written date/time 88fcaa7557SNicolas Bonnefon // That seems to work alright in my tests, but who knows for sure? 89fcaa7557SNicolas Bonnefon 90fcaa7557SNicolas Bonnefon HANDLE hFile = CreateFile( 9180bca0a3SNicolas Bonnefon #ifdef UNICODE 9280bca0a3SNicolas Bonnefon longstringize( file_name ).c_str(), 9380bca0a3SNicolas Bonnefon #else 9480bca0a3SNicolas Bonnefon ( file_name ).c_str(), 9580bca0a3SNicolas Bonnefon #endif 96fcaa7557SNicolas Bonnefon 0, 97fcaa7557SNicolas Bonnefon FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, 98fcaa7557SNicolas Bonnefon NULL, 99fcaa7557SNicolas Bonnefon OPEN_EXISTING, 100fcaa7557SNicolas Bonnefon FILE_ATTRIBUTE_NORMAL, 101fcaa7557SNicolas Bonnefon NULL ); 102fcaa7557SNicolas Bonnefon 103fcaa7557SNicolas Bonnefon if ( hFile == (HANDLE)-1 ) { 104fcaa7557SNicolas Bonnefon DWORD err = GetLastError(); 105fcaa7557SNicolas Bonnefon LOG(logERROR) << "FileChangeToken::readFromFile: failed with " << err; 106fcaa7557SNicolas Bonnefon 107fcaa7557SNicolas Bonnefon low_date_time_ = 0; 108fcaa7557SNicolas Bonnefon high_date_time_ = 0; 109fcaa7557SNicolas Bonnefon 110fcaa7557SNicolas Bonnefon return; 111fcaa7557SNicolas Bonnefon } 112fcaa7557SNicolas Bonnefon else { 113fcaa7557SNicolas Bonnefon BY_HANDLE_FILE_INFORMATION file_info; 114fcaa7557SNicolas Bonnefon 115fcaa7557SNicolas Bonnefon if ( GetFileInformationByHandle( 116fcaa7557SNicolas Bonnefon hFile, 117fcaa7557SNicolas Bonnefon &file_info ) ) { 118fcaa7557SNicolas Bonnefon low_date_time_ = file_info.ftLastWriteTime.dwLowDateTime; 119fcaa7557SNicolas Bonnefon high_date_time_ = file_info.ftLastWriteTime.dwHighDateTime; 120fcaa7557SNicolas Bonnefon 121fcaa7557SNicolas Bonnefon LOG(logDEBUG) << "FileChangeToken::readFromFile: low_date_time_ " << low_date_time_; 122fcaa7557SNicolas Bonnefon LOG(logDEBUG) << "FileChangeToken::readFromFile: high_date_time_ " << high_date_time_; 123fcaa7557SNicolas Bonnefon } 124fcaa7557SNicolas Bonnefon else { 125fcaa7557SNicolas Bonnefon DWORD err = GetLastError(); 126fcaa7557SNicolas Bonnefon LOG(logERROR) << "FileChangeToken::readFromFile: failed with " << err; 127fcaa7557SNicolas Bonnefon 128fcaa7557SNicolas Bonnefon low_date_time_ = 0; 129fcaa7557SNicolas Bonnefon high_date_time_ = 0; 130fcaa7557SNicolas Bonnefon } 131fcaa7557SNicolas Bonnefon } 132fcaa7557SNicolas Bonnefon 133fcaa7557SNicolas Bonnefon CloseHandle(hFile); 134fcaa7557SNicolas Bonnefon } 135fcaa7557SNicolas Bonnefon 136f09fa651SNicolas Bonnefon // WinWatchTowerDriver 137f09fa651SNicolas Bonnefon 138f09fa651SNicolas Bonnefon WinWatchTowerDriver::WinWatchTowerDriver() 139f09fa651SNicolas Bonnefon { 140f09fa651SNicolas Bonnefon hCompPort_ = CreateIoCompletionPort( INVALID_HANDLE_VALUE, 141f09fa651SNicolas Bonnefon NULL, 142f09fa651SNicolas Bonnefon 0x0, 143f09fa651SNicolas Bonnefon 0); 144f09fa651SNicolas Bonnefon } 145f09fa651SNicolas Bonnefon 146f09fa651SNicolas Bonnefon WinWatchTowerDriver::~WinWatchTowerDriver() 147f09fa651SNicolas Bonnefon { 148f09fa651SNicolas Bonnefon } 149f09fa651SNicolas Bonnefon 150f09fa651SNicolas Bonnefon WinWatchTowerDriver::FileId WinWatchTowerDriver::addFile( 151f09fa651SNicolas Bonnefon const std::string& file_name ) 152f09fa651SNicolas Bonnefon { 153f09fa651SNicolas Bonnefon // Nothing for Windows 154f09fa651SNicolas Bonnefon return { }; 155f09fa651SNicolas Bonnefon } 156f09fa651SNicolas Bonnefon 157f09fa651SNicolas Bonnefon WinWatchTowerDriver::SymlinkId WinWatchTowerDriver::addSymlink( 158f09fa651SNicolas Bonnefon const std::string& file_name ) 159f09fa651SNicolas Bonnefon { 160f09fa651SNicolas Bonnefon // Nothing for Windows 161f09fa651SNicolas Bonnefon return { }; 162f09fa651SNicolas Bonnefon } 163f09fa651SNicolas Bonnefon 164f09fa651SNicolas Bonnefon // This implementation is blocking, i.e. it will wait until the file 165f09fa651SNicolas Bonnefon // is effectively loaded in the watchtower thread. 166f09fa651SNicolas Bonnefon WinWatchTowerDriver::DirId WinWatchTowerDriver::addDir( 167f09fa651SNicolas Bonnefon const std::string& file_name ) 168f09fa651SNicolas Bonnefon { 169f09fa651SNicolas Bonnefon DirId dir_id { }; 170f09fa651SNicolas Bonnefon 171f09fa651SNicolas Bonnefon // Add will be done in the watchtower thread 172f09fa651SNicolas Bonnefon { 1733104b268SNicolas Bonnefon /* 174f09fa651SNicolas Bonnefon std::lock_guard<std::mutex> lk( action_mutex_ ); 175f09fa651SNicolas Bonnefon scheduled_action_ = std::make_unique<Action>( [this, file_name, &dir_id] { 176f09fa651SNicolas Bonnefon serialisedAddDir( file_name, dir_id ); 177f09fa651SNicolas Bonnefon } ); 1783104b268SNicolas Bonnefon */ 1793104b268SNicolas Bonnefon serialisedAddDir( file_name, dir_id ); 180f09fa651SNicolas Bonnefon } 181f09fa651SNicolas Bonnefon 182f09fa651SNicolas Bonnefon // Poke the thread 183*aceb79b2SNicolas Bonnefon interruptWait(); 184f09fa651SNicolas Bonnefon 185f09fa651SNicolas Bonnefon // Wait for the add task to be completed 186f09fa651SNicolas Bonnefon { 1873104b268SNicolas Bonnefon /* 188f09fa651SNicolas Bonnefon std::unique_lock<std::mutex> lk( action_mutex_ ); 189f09fa651SNicolas Bonnefon action_done_cv_.wait( lk, 190f09fa651SNicolas Bonnefon [this]{ return ( scheduled_action_ == nullptr ); } ); 1913104b268SNicolas Bonnefon */ 192f09fa651SNicolas Bonnefon } 193f09fa651SNicolas Bonnefon 194dc1c9514SNicolas Bonnefon LOG(logDEBUG) << "addDir returned " << dir_id.dir_record_; 195f09fa651SNicolas Bonnefon 196f09fa651SNicolas Bonnefon return dir_id; 197f09fa651SNicolas Bonnefon } 198f09fa651SNicolas Bonnefon 199f09fa651SNicolas Bonnefon 200f09fa651SNicolas Bonnefon void WinWatchTowerDriver::removeFile( 2018b11848fSNicolas Bonnefon const WinWatchTowerDriver::FileId& ) 202f09fa651SNicolas Bonnefon { 203f09fa651SNicolas Bonnefon } 204f09fa651SNicolas Bonnefon 2058b11848fSNicolas Bonnefon void WinWatchTowerDriver::removeSymlink( const SymlinkId& ) 206f09fa651SNicolas Bonnefon { 207f09fa651SNicolas Bonnefon } 208f09fa651SNicolas Bonnefon 2093104b268SNicolas Bonnefon void WinWatchTowerDriver::removeDir( const DirId& dir_id ) 2103104b268SNicolas Bonnefon { 211dc1c9514SNicolas Bonnefon LOG(logDEBUG) << "Entering driver::removeDir"; 2128b11848fSNicolas Bonnefon if ( dir_id.dir_record_ ) { 2133104b268SNicolas Bonnefon void* handle = dir_id.dir_record_->handle_; 2143104b268SNicolas Bonnefon 2153104b268SNicolas Bonnefon LOG(logDEBUG) << "WinWatchTowerDriver::removeDir handle=" << std::hex << handle; 2163104b268SNicolas Bonnefon 2173104b268SNicolas Bonnefon CloseHandle( handle ); 2183104b268SNicolas Bonnefon } 2198b11848fSNicolas Bonnefon else { 2208b11848fSNicolas Bonnefon /* Happens when an error occured when creating the dir_record_ */ 2218b11848fSNicolas Bonnefon } 2228b11848fSNicolas Bonnefon } 2233104b268SNicolas Bonnefon 224f09fa651SNicolas Bonnefon // 225f09fa651SNicolas Bonnefon // Private functions 226f09fa651SNicolas Bonnefon // 227f09fa651SNicolas Bonnefon 228f09fa651SNicolas Bonnefon // Add a file (run in the context of the WatchTower thread) 229f09fa651SNicolas Bonnefon void WinWatchTowerDriver::serialisedAddDir( 230f09fa651SNicolas Bonnefon const std::string& dir_name, 231f09fa651SNicolas Bonnefon DirId& dir_id ) 232f09fa651SNicolas Bonnefon { 233dc1c9514SNicolas Bonnefon bool inserted = false; 234f09fa651SNicolas Bonnefon auto dir_record = std::make_shared<WinWatchedDirRecord>( dir_name ); 235dc1c9514SNicolas Bonnefon // The index we will be inserting this record (if success), plus 1 (to avoid 236dc1c9514SNicolas Bonnefon // 0 which is used as a magic value) 237dc1c9514SNicolas Bonnefon unsigned int index_record = dir_records_.size() + 1; 238f09fa651SNicolas Bonnefon 239f09fa651SNicolas Bonnefon LOG(logDEBUG) << "Adding dir for: " << dir_name; 240f09fa651SNicolas Bonnefon 241f09fa651SNicolas Bonnefon // Open the directory 242f09fa651SNicolas Bonnefon HANDLE hDir = CreateFile( 243f09fa651SNicolas Bonnefon #ifdef UNICODE 244f09fa651SNicolas Bonnefon longstringize( dir_name ).c_str(), 245f09fa651SNicolas Bonnefon #else 246f09fa651SNicolas Bonnefon ( dir_name ).c_str(), 247f09fa651SNicolas Bonnefon #endif 248f09fa651SNicolas Bonnefon FILE_LIST_DIRECTORY, 249f09fa651SNicolas Bonnefon FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, 250f09fa651SNicolas Bonnefon NULL, 251f09fa651SNicolas Bonnefon OPEN_EXISTING, 252f09fa651SNicolas Bonnefon FILE_FLAG_BACKUP_SEMANTICS | FILE_FLAG_OVERLAPPED, 253f09fa651SNicolas Bonnefon NULL ); 254f09fa651SNicolas Bonnefon 2553104b268SNicolas Bonnefon if ( hDir == INVALID_HANDLE_VALUE ) { 2563104b268SNicolas Bonnefon LOG(logERROR) << "CreateFile failed for dir " << dir_name; 2573104b268SNicolas Bonnefon } 258dc1c9514SNicolas Bonnefon else { 259f09fa651SNicolas Bonnefon dir_record->handle_ = hDir; 260f09fa651SNicolas Bonnefon 261f09fa651SNicolas Bonnefon //create a IO completion port/or associate this key with 262f09fa651SNicolas Bonnefon //the existing IO completion port 263f09fa651SNicolas Bonnefon hCompPort_ = CreateIoCompletionPort( hDir, 264f09fa651SNicolas Bonnefon hCompPort_, //if m_hCompPort is NULL, hDir is associated with a NEW completion port, 265f09fa651SNicolas Bonnefon //if m_hCompPort is NON-NULL, hDir is associated with the existing completion port that the handle m_hCompPort references 266f09fa651SNicolas Bonnefon // We use the index (plus 1) of the weak_ptr as a key 267f09fa651SNicolas Bonnefon index_record, 268f09fa651SNicolas Bonnefon 0 ); 269f09fa651SNicolas Bonnefon 270f09fa651SNicolas Bonnefon LOG(logDEBUG) << "Weak ptr address stored: " << index_record; 271f09fa651SNicolas Bonnefon 272f09fa651SNicolas Bonnefon memset( &overlapped_, 0, sizeof overlapped_ ); 273f09fa651SNicolas Bonnefon 274dc1c9514SNicolas Bonnefon inserted = ReadDirectoryChangesW( hDir, 275f09fa651SNicolas Bonnefon dir_record->buffer_, 276f09fa651SNicolas Bonnefon dir_record->buffer_length_, 277f09fa651SNicolas Bonnefon false, 278f09fa651SNicolas Bonnefon FILE_NOTIFY_CHANGE_FILE_NAME | FILE_NOTIFY_CHANGE_LAST_WRITE, 279f09fa651SNicolas Bonnefon &buffer_length_, // not set when using asynchronous mechanisms... 280f09fa651SNicolas Bonnefon &overlapped_, 281f09fa651SNicolas Bonnefon NULL ); // no completion routine 282f09fa651SNicolas Bonnefon 283dc1c9514SNicolas Bonnefon if ( ! inserted ) { 2843104b268SNicolas Bonnefon LOG(logERROR) << "ReadDirectoryChangesW failed (" << GetLastError() << ")"; 285dc1c9514SNicolas Bonnefon CloseHandle( hDir ); 2863104b268SNicolas Bonnefon } 2878b11848fSNicolas Bonnefon else { 288f09fa651SNicolas Bonnefon dir_id.dir_record_ = dir_record; 289f09fa651SNicolas Bonnefon } 2908b11848fSNicolas Bonnefon } 291f09fa651SNicolas Bonnefon 292dc1c9514SNicolas Bonnefon if ( inserted ) { 293dc1c9514SNicolas Bonnefon dir_records_.push_back( std::weak_ptr<WinWatchedDirRecord>( dir_record ) ); 294dc1c9514SNicolas Bonnefon } 295dc1c9514SNicolas Bonnefon } 296dc1c9514SNicolas Bonnefon 297f09fa651SNicolas Bonnefon std::vector<ObservedFile<WinWatchTowerDriver>*> WinWatchTowerDriver::waitAndProcessEvents( 298f09fa651SNicolas Bonnefon ObservedFileList<WinWatchTowerDriver>* list, 29991f7c705SNicolas Bonnefon std::unique_lock<std::mutex>* lock, 300fcaa7557SNicolas Bonnefon std::vector<ObservedFile<WinWatchTowerDriver>*>* /* not needed in WinWatchTowerDriver */, 301fcaa7557SNicolas Bonnefon int timeout_ms ) 302f09fa651SNicolas Bonnefon { 303f09fa651SNicolas Bonnefon std::vector<ObservedFile<WinWatchTowerDriver>*> files_to_notify { }; 304f09fa651SNicolas Bonnefon 3053089b1a1SNicolas Bonnefon ULONG_PTR key = 0; 306f09fa651SNicolas Bonnefon DWORD num_bytes = 0; 307f09fa651SNicolas Bonnefon LPOVERLAPPED lpOverlapped = 0; 308f09fa651SNicolas Bonnefon 309fcaa7557SNicolas Bonnefon if ( timeout_ms == 0 ) 310fcaa7557SNicolas Bonnefon timeout_ms = INFINITE; 311fcaa7557SNicolas Bonnefon 3123104b268SNicolas Bonnefon lock->unlock(); 313dc1c9514SNicolas Bonnefon LOG(logDEBUG) << "waitAndProcessEvents now blocking..."; 314f09fa651SNicolas Bonnefon BOOL status = GetQueuedCompletionStatus( hCompPort_, 315f09fa651SNicolas Bonnefon &num_bytes, 316f09fa651SNicolas Bonnefon &key, 317f09fa651SNicolas Bonnefon &lpOverlapped, 318fcaa7557SNicolas Bonnefon timeout_ms ); 3193104b268SNicolas Bonnefon lock->lock(); 320f09fa651SNicolas Bonnefon 3213104b268SNicolas Bonnefon LOG(logDEBUG) << "Event (" << status << ") key: " << std::hex << key; 322f09fa651SNicolas Bonnefon 323f09fa651SNicolas Bonnefon if ( key ) { 324f09fa651SNicolas Bonnefon // Extract the dir from the completion key 325f09fa651SNicolas Bonnefon auto dir_record_ptr = dir_records_[key - 1]; 326f09fa651SNicolas Bonnefon LOG(logDEBUG) << "use_count = " << dir_record_ptr.use_count(); 327f09fa651SNicolas Bonnefon 328f09fa651SNicolas Bonnefon if ( std::shared_ptr<WinWatchedDirRecord> dir_record = dir_record_ptr.lock() ) 329f09fa651SNicolas Bonnefon { 330f09fa651SNicolas Bonnefon LOG(logDEBUG) << "Got event for dir " << dir_record.get(); 331f09fa651SNicolas Bonnefon 332f09fa651SNicolas Bonnefon WinNotificationInfoList notification_info( 333f09fa651SNicolas Bonnefon dir_record->buffer_, 334f09fa651SNicolas Bonnefon dir_record->buffer_length_ ); 335f09fa651SNicolas Bonnefon 336f09fa651SNicolas Bonnefon for ( auto notification : notification_info ) { 337f09fa651SNicolas Bonnefon std::string file_path = dir_record->path_ + shortstringize( notification.fileName() ); 338f09fa651SNicolas Bonnefon LOG(logDEBUG) << "File is " << file_path; 339f09fa651SNicolas Bonnefon auto file = list->searchByName( file_path ); 340f09fa651SNicolas Bonnefon 341f09fa651SNicolas Bonnefon if ( file ) 342f09fa651SNicolas Bonnefon { 343f09fa651SNicolas Bonnefon files_to_notify.push_back( file ); 344f09fa651SNicolas Bonnefon } 345f09fa651SNicolas Bonnefon } 346f09fa651SNicolas Bonnefon 347f09fa651SNicolas Bonnefon // Re-listen for changes 348f09fa651SNicolas Bonnefon status = ReadDirectoryChangesW( 349f09fa651SNicolas Bonnefon dir_record->handle_, 350f09fa651SNicolas Bonnefon dir_record->buffer_, 351f09fa651SNicolas Bonnefon dir_record->buffer_length_, 352f09fa651SNicolas Bonnefon false, 353f09fa651SNicolas Bonnefon FILE_NOTIFY_CHANGE_FILE_NAME | FILE_NOTIFY_CHANGE_LAST_WRITE, 354f09fa651SNicolas Bonnefon &buffer_length_,// not set when using asynchronous mechanisms... 355f09fa651SNicolas Bonnefon &overlapped_, 356f09fa651SNicolas Bonnefon NULL ); // no completion routine 357f09fa651SNicolas Bonnefon } 358f09fa651SNicolas Bonnefon else { 359f09fa651SNicolas Bonnefon LOG(logWARNING) << "Looks like our dir_record disappeared!"; 360f09fa651SNicolas Bonnefon } 361f09fa651SNicolas Bonnefon } 362f09fa651SNicolas Bonnefon else { 363f09fa651SNicolas Bonnefon LOG(logDEBUG) << "Signaled"; 364f09fa651SNicolas Bonnefon } 365f09fa651SNicolas Bonnefon 366f09fa651SNicolas Bonnefon { 367f09fa651SNicolas Bonnefon std::lock_guard<std::mutex> lk( action_mutex_ ); 368f09fa651SNicolas Bonnefon if ( scheduled_action_ ) { 369f09fa651SNicolas Bonnefon (*scheduled_action_)(); 370f09fa651SNicolas Bonnefon scheduled_action_ = nullptr; 371f09fa651SNicolas Bonnefon action_done_cv_.notify_all(); 372f09fa651SNicolas Bonnefon } 373f09fa651SNicolas Bonnefon } 374f09fa651SNicolas Bonnefon 375f09fa651SNicolas Bonnefon /* 376f09fa651SNicolas Bonnefon // Just in case someone is waiting for an action to complete 377f09fa651SNicolas Bonnefon std::lock_guard<std::mutex> lk( action_mutex_ ); 378f09fa651SNicolas Bonnefon scheduled_action_ = nullptr; 379f09fa651SNicolas Bonnefon action_done_cv_.notify_all(); 380f09fa651SNicolas Bonnefon */ 381f09fa651SNicolas Bonnefon return files_to_notify; 382f09fa651SNicolas Bonnefon } 383f09fa651SNicolas Bonnefon 384f09fa651SNicolas Bonnefon void WinWatchTowerDriver::interruptWait() 385f09fa651SNicolas Bonnefon { 386dc1c9514SNicolas Bonnefon LOG(logDEBUG) << "Driver::interruptWait()"; 387f09fa651SNicolas Bonnefon PostQueuedCompletionStatus( hCompPort_, 0, 0, NULL ); 388f09fa651SNicolas Bonnefon } 389f09fa651SNicolas Bonnefon 390f09fa651SNicolas Bonnefon namespace { 391f09fa651SNicolas Bonnefon std::string shortstringize( const std::wstring& long_string ) 392f09fa651SNicolas Bonnefon { 393f09fa651SNicolas Bonnefon std::string short_result {}; 394f09fa651SNicolas Bonnefon 395f09fa651SNicolas Bonnefon for ( wchar_t c : long_string ) { 396f09fa651SNicolas Bonnefon // FIXME: that does not work for non ASCII char!! 397f09fa651SNicolas Bonnefon char short_c = static_cast<char>( c & 0x00FF ); 398f09fa651SNicolas Bonnefon short_result += short_c; 399f09fa651SNicolas Bonnefon } 400f09fa651SNicolas Bonnefon 401f09fa651SNicolas Bonnefon return short_result; 402f09fa651SNicolas Bonnefon } 403f09fa651SNicolas Bonnefon 404f09fa651SNicolas Bonnefon std::wstring longstringize( const std::string& short_string ) 405f09fa651SNicolas Bonnefon { 406f09fa651SNicolas Bonnefon std::wstring long_result {}; 407f09fa651SNicolas Bonnefon 408f09fa651SNicolas Bonnefon for ( char c : short_string ) { 409f09fa651SNicolas Bonnefon wchar_t long_c = static_cast<wchar_t>( c ); 410f09fa651SNicolas Bonnefon long_result += long_c; 411f09fa651SNicolas Bonnefon } 412f09fa651SNicolas Bonnefon 413f09fa651SNicolas Bonnefon return long_result; 414f09fa651SNicolas Bonnefon } 415f09fa651SNicolas Bonnefon }; 416