1aceb79b2SNicolas Bonnefon /*
2aceb79b2SNicolas Bonnefon * Copyright (C) 2015 Nicolas Bonnefon and other contributors
3aceb79b2SNicolas Bonnefon *
4aceb79b2SNicolas Bonnefon * This file is part of glogg.
5aceb79b2SNicolas Bonnefon *
6aceb79b2SNicolas Bonnefon * glogg is free software: you can redistribute it and/or modify
7aceb79b2SNicolas Bonnefon * it under the terms of the GNU General Public License as published by
8aceb79b2SNicolas Bonnefon * the Free Software Foundation, either version 3 of the License, or
9aceb79b2SNicolas Bonnefon * (at your option) any later version.
10aceb79b2SNicolas Bonnefon *
11aceb79b2SNicolas Bonnefon * glogg is distributed in the hope that it will be useful,
12aceb79b2SNicolas Bonnefon * but WITHOUT ANY WARRANTY; without even the implied warranty of
13aceb79b2SNicolas Bonnefon * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14aceb79b2SNicolas Bonnefon * GNU General Public License for more details.
15aceb79b2SNicolas Bonnefon *
16aceb79b2SNicolas Bonnefon * You should have received a copy of the GNU General Public License
17aceb79b2SNicolas Bonnefon * along with glogg. If not, see <http://www.gnu.org/licenses/>.
18aceb79b2SNicolas Bonnefon */
19aceb79b2SNicolas 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
WinNotificationInfoList(const char * buffer,size_t buffer_size)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
updateCurrentNotification(const char * new_position)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
advanceToNext()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
readFromFile(const std::string & file_name)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
90*f7ea9867SNicolas Bonnefon // On further investigation, in some situations (e.g. putty logging that
91*f7ea9867SNicolas Bonnefon // has been stop/re-started), the size of the file is being updated but not
92*f7ea9867SNicolas Bonnefon // the date (confirmed by "Properties" in the file explorer), so we add the
93*f7ea9867SNicolas Bonnefon // file size to the token. Ha the joy of Windows programming...
94*f7ea9867SNicolas Bonnefon
95fcaa7557SNicolas Bonnefon HANDLE hFile = CreateFile(
9680bca0a3SNicolas Bonnefon #ifdef UNICODE
9780bca0a3SNicolas Bonnefon longstringize( file_name ).c_str(),
9880bca0a3SNicolas Bonnefon #else
9980bca0a3SNicolas Bonnefon ( file_name ).c_str(),
10080bca0a3SNicolas Bonnefon #endif
101fcaa7557SNicolas Bonnefon 0,
102fcaa7557SNicolas Bonnefon FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
103fcaa7557SNicolas Bonnefon NULL,
104fcaa7557SNicolas Bonnefon OPEN_EXISTING,
105fcaa7557SNicolas Bonnefon FILE_ATTRIBUTE_NORMAL,
106fcaa7557SNicolas Bonnefon NULL );
107fcaa7557SNicolas Bonnefon
108fcaa7557SNicolas Bonnefon if ( hFile == (HANDLE)-1 ) {
109fcaa7557SNicolas Bonnefon DWORD err = GetLastError();
110fcaa7557SNicolas Bonnefon LOG(logERROR) << "FileChangeToken::readFromFile: failed with " << err;
111fcaa7557SNicolas Bonnefon
112fcaa7557SNicolas Bonnefon low_date_time_ = 0;
113fcaa7557SNicolas Bonnefon high_date_time_ = 0;
114*f7ea9867SNicolas Bonnefon low_file_size_ = 0;
115*f7ea9867SNicolas Bonnefon high_file_size_ = 0;
116fcaa7557SNicolas Bonnefon
117fcaa7557SNicolas Bonnefon return;
118fcaa7557SNicolas Bonnefon }
119fcaa7557SNicolas Bonnefon else {
120fcaa7557SNicolas Bonnefon BY_HANDLE_FILE_INFORMATION file_info;
121fcaa7557SNicolas Bonnefon
122fcaa7557SNicolas Bonnefon if ( GetFileInformationByHandle(
123fcaa7557SNicolas Bonnefon hFile,
124fcaa7557SNicolas Bonnefon &file_info ) ) {
125fcaa7557SNicolas Bonnefon low_date_time_ = file_info.ftLastWriteTime.dwLowDateTime;
126fcaa7557SNicolas Bonnefon high_date_time_ = file_info.ftLastWriteTime.dwHighDateTime;
127*f7ea9867SNicolas Bonnefon low_file_size_ = file_info.nFileSizeLow;
128*f7ea9867SNicolas Bonnefon high_file_size_ = file_info.nFileSizeHigh;
129fcaa7557SNicolas Bonnefon
130fcaa7557SNicolas Bonnefon LOG(logDEBUG) << "FileChangeToken::readFromFile: low_date_time_ " << low_date_time_;
131fcaa7557SNicolas Bonnefon LOG(logDEBUG) << "FileChangeToken::readFromFile: high_date_time_ " << high_date_time_;
132fcaa7557SNicolas Bonnefon }
133fcaa7557SNicolas Bonnefon else {
134fcaa7557SNicolas Bonnefon DWORD err = GetLastError();
135fcaa7557SNicolas Bonnefon LOG(logERROR) << "FileChangeToken::readFromFile: failed with " << err;
136fcaa7557SNicolas Bonnefon
137fcaa7557SNicolas Bonnefon low_date_time_ = 0;
138fcaa7557SNicolas Bonnefon high_date_time_ = 0;
139fcaa7557SNicolas Bonnefon }
140fcaa7557SNicolas Bonnefon }
141fcaa7557SNicolas Bonnefon
142fcaa7557SNicolas Bonnefon CloseHandle(hFile);
143fcaa7557SNicolas Bonnefon }
144fcaa7557SNicolas Bonnefon
145f09fa651SNicolas Bonnefon // WinWatchTowerDriver
146f09fa651SNicolas Bonnefon
WinWatchTowerDriver()147f09fa651SNicolas Bonnefon WinWatchTowerDriver::WinWatchTowerDriver()
148f09fa651SNicolas Bonnefon {
149f09fa651SNicolas Bonnefon hCompPort_ = CreateIoCompletionPort( INVALID_HANDLE_VALUE,
150f09fa651SNicolas Bonnefon NULL,
151f09fa651SNicolas Bonnefon 0x0,
152f09fa651SNicolas Bonnefon 0);
153f09fa651SNicolas Bonnefon }
154f09fa651SNicolas Bonnefon
~WinWatchTowerDriver()155f09fa651SNicolas Bonnefon WinWatchTowerDriver::~WinWatchTowerDriver()
156f09fa651SNicolas Bonnefon {
157f09fa651SNicolas Bonnefon }
158f09fa651SNicolas Bonnefon
addFile(const std::string & file_name)159f09fa651SNicolas Bonnefon WinWatchTowerDriver::FileId WinWatchTowerDriver::addFile(
160f09fa651SNicolas Bonnefon const std::string& file_name )
161f09fa651SNicolas Bonnefon {
162f09fa651SNicolas Bonnefon // Nothing for Windows
163f09fa651SNicolas Bonnefon return { };
164f09fa651SNicolas Bonnefon }
165f09fa651SNicolas Bonnefon
addSymlink(const std::string & file_name)166f09fa651SNicolas Bonnefon WinWatchTowerDriver::SymlinkId WinWatchTowerDriver::addSymlink(
167f09fa651SNicolas Bonnefon const std::string& file_name )
168f09fa651SNicolas Bonnefon {
169f09fa651SNicolas Bonnefon // Nothing for Windows
170f09fa651SNicolas Bonnefon return { };
171f09fa651SNicolas Bonnefon }
172f09fa651SNicolas Bonnefon
173f09fa651SNicolas Bonnefon // This implementation is blocking, i.e. it will wait until the file
174f09fa651SNicolas Bonnefon // is effectively loaded in the watchtower thread.
addDir(const std::string & file_name)175f09fa651SNicolas Bonnefon WinWatchTowerDriver::DirId WinWatchTowerDriver::addDir(
176f09fa651SNicolas Bonnefon const std::string& file_name )
177f09fa651SNicolas Bonnefon {
178f09fa651SNicolas Bonnefon DirId dir_id { };
179f09fa651SNicolas Bonnefon
180f09fa651SNicolas Bonnefon // Add will be done in the watchtower thread
181f09fa651SNicolas Bonnefon {
1823104b268SNicolas Bonnefon /*
183f09fa651SNicolas Bonnefon std::lock_guard<std::mutex> lk( action_mutex_ );
184f09fa651SNicolas Bonnefon scheduled_action_ = std::make_unique<Action>( [this, file_name, &dir_id] {
185f09fa651SNicolas Bonnefon serialisedAddDir( file_name, dir_id );
186f09fa651SNicolas Bonnefon } );
1873104b268SNicolas Bonnefon */
1883104b268SNicolas Bonnefon serialisedAddDir( file_name, dir_id );
189f09fa651SNicolas Bonnefon }
190f09fa651SNicolas Bonnefon
191f09fa651SNicolas Bonnefon // Poke the thread
192aceb79b2SNicolas Bonnefon interruptWait();
193f09fa651SNicolas Bonnefon
194f09fa651SNicolas Bonnefon // Wait for the add task to be completed
195f09fa651SNicolas Bonnefon {
1963104b268SNicolas Bonnefon /*
197f09fa651SNicolas Bonnefon std::unique_lock<std::mutex> lk( action_mutex_ );
198f09fa651SNicolas Bonnefon action_done_cv_.wait( lk,
199f09fa651SNicolas Bonnefon [this]{ return ( scheduled_action_ == nullptr ); } );
2003104b268SNicolas Bonnefon */
201f09fa651SNicolas Bonnefon }
202f09fa651SNicolas Bonnefon
203dc1c9514SNicolas Bonnefon LOG(logDEBUG) << "addDir returned " << dir_id.dir_record_;
204f09fa651SNicolas Bonnefon
205f09fa651SNicolas Bonnefon return dir_id;
206f09fa651SNicolas Bonnefon }
207f09fa651SNicolas Bonnefon
208f09fa651SNicolas Bonnefon
removeFile(const WinWatchTowerDriver::FileId &)209f09fa651SNicolas Bonnefon void WinWatchTowerDriver::removeFile(
2108b11848fSNicolas Bonnefon const WinWatchTowerDriver::FileId& )
211f09fa651SNicolas Bonnefon {
212f09fa651SNicolas Bonnefon }
213f09fa651SNicolas Bonnefon
removeSymlink(const SymlinkId &)2148b11848fSNicolas Bonnefon void WinWatchTowerDriver::removeSymlink( const SymlinkId& )
215f09fa651SNicolas Bonnefon {
216f09fa651SNicolas Bonnefon }
217f09fa651SNicolas Bonnefon
removeDir(const DirId & dir_id)2183104b268SNicolas Bonnefon void WinWatchTowerDriver::removeDir( const DirId& dir_id )
2193104b268SNicolas Bonnefon {
220dc1c9514SNicolas Bonnefon LOG(logDEBUG) << "Entering driver::removeDir";
2218b11848fSNicolas Bonnefon if ( dir_id.dir_record_ ) {
2223104b268SNicolas Bonnefon void* handle = dir_id.dir_record_->handle_;
2233104b268SNicolas Bonnefon
2243104b268SNicolas Bonnefon LOG(logDEBUG) << "WinWatchTowerDriver::removeDir handle=" << std::hex << handle;
2253104b268SNicolas Bonnefon
2263104b268SNicolas Bonnefon CloseHandle( handle );
2273104b268SNicolas Bonnefon }
2288b11848fSNicolas Bonnefon else {
2298b11848fSNicolas Bonnefon /* Happens when an error occured when creating the dir_record_ */
2308b11848fSNicolas Bonnefon }
2318b11848fSNicolas Bonnefon }
2323104b268SNicolas Bonnefon
233f09fa651SNicolas Bonnefon //
234f09fa651SNicolas Bonnefon // Private functions
235f09fa651SNicolas Bonnefon //
236f09fa651SNicolas Bonnefon
237f09fa651SNicolas Bonnefon // Add a file (run in the context of the WatchTower thread)
serialisedAddDir(const std::string & dir_name,DirId & dir_id)238f09fa651SNicolas Bonnefon void WinWatchTowerDriver::serialisedAddDir(
239f09fa651SNicolas Bonnefon const std::string& dir_name,
240f09fa651SNicolas Bonnefon DirId& dir_id )
241f09fa651SNicolas Bonnefon {
242dc1c9514SNicolas Bonnefon bool inserted = false;
243f09fa651SNicolas Bonnefon auto dir_record = std::make_shared<WinWatchedDirRecord>( dir_name );
244dc1c9514SNicolas Bonnefon // The index we will be inserting this record (if success), plus 1 (to avoid
245dc1c9514SNicolas Bonnefon // 0 which is used as a magic value)
246dc1c9514SNicolas Bonnefon unsigned int index_record = dir_records_.size() + 1;
247f09fa651SNicolas Bonnefon
248f09fa651SNicolas Bonnefon LOG(logDEBUG) << "Adding dir for: " << dir_name;
249f09fa651SNicolas Bonnefon
250f09fa651SNicolas Bonnefon // Open the directory
251f09fa651SNicolas Bonnefon HANDLE hDir = CreateFile(
252f09fa651SNicolas Bonnefon #ifdef UNICODE
253f09fa651SNicolas Bonnefon longstringize( dir_name ).c_str(),
254f09fa651SNicolas Bonnefon #else
255f09fa651SNicolas Bonnefon ( dir_name ).c_str(),
256f09fa651SNicolas Bonnefon #endif
257f09fa651SNicolas Bonnefon FILE_LIST_DIRECTORY,
258f09fa651SNicolas Bonnefon FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
259f09fa651SNicolas Bonnefon NULL,
260f09fa651SNicolas Bonnefon OPEN_EXISTING,
261f09fa651SNicolas Bonnefon FILE_FLAG_BACKUP_SEMANTICS | FILE_FLAG_OVERLAPPED,
262f09fa651SNicolas Bonnefon NULL );
263f09fa651SNicolas Bonnefon
2643104b268SNicolas Bonnefon if ( hDir == INVALID_HANDLE_VALUE ) {
2653104b268SNicolas Bonnefon LOG(logERROR) << "CreateFile failed for dir " << dir_name;
2663104b268SNicolas Bonnefon }
267dc1c9514SNicolas Bonnefon else {
268f09fa651SNicolas Bonnefon dir_record->handle_ = hDir;
269f09fa651SNicolas Bonnefon
270f09fa651SNicolas Bonnefon //create a IO completion port/or associate this key with
271f09fa651SNicolas Bonnefon //the existing IO completion port
272f09fa651SNicolas Bonnefon hCompPort_ = CreateIoCompletionPort( hDir,
273f09fa651SNicolas Bonnefon hCompPort_, //if m_hCompPort is NULL, hDir is associated with a NEW completion port,
274f09fa651SNicolas Bonnefon //if m_hCompPort is NON-NULL, hDir is associated with the existing completion port that the handle m_hCompPort references
275f09fa651SNicolas Bonnefon // We use the index (plus 1) of the weak_ptr as a key
276f09fa651SNicolas Bonnefon index_record,
277f09fa651SNicolas Bonnefon 0 );
278f09fa651SNicolas Bonnefon
279f09fa651SNicolas Bonnefon LOG(logDEBUG) << "Weak ptr address stored: " << index_record;
280f09fa651SNicolas Bonnefon
281f09fa651SNicolas Bonnefon memset( &overlapped_, 0, sizeof overlapped_ );
282f09fa651SNicolas Bonnefon
283dc1c9514SNicolas Bonnefon inserted = ReadDirectoryChangesW( hDir,
284f09fa651SNicolas Bonnefon dir_record->buffer_,
285f09fa651SNicolas Bonnefon dir_record->buffer_length_,
286f09fa651SNicolas Bonnefon false,
287f09fa651SNicolas Bonnefon FILE_NOTIFY_CHANGE_FILE_NAME | FILE_NOTIFY_CHANGE_LAST_WRITE,
288f09fa651SNicolas Bonnefon &buffer_length_, // not set when using asynchronous mechanisms...
289f09fa651SNicolas Bonnefon &overlapped_,
290f09fa651SNicolas Bonnefon NULL ); // no completion routine
291f09fa651SNicolas Bonnefon
292dc1c9514SNicolas Bonnefon if ( ! inserted ) {
2933104b268SNicolas Bonnefon LOG(logERROR) << "ReadDirectoryChangesW failed (" << GetLastError() << ")";
294dc1c9514SNicolas Bonnefon CloseHandle( hDir );
2953104b268SNicolas Bonnefon }
2968b11848fSNicolas Bonnefon else {
297f09fa651SNicolas Bonnefon dir_id.dir_record_ = dir_record;
298f09fa651SNicolas Bonnefon }
2998b11848fSNicolas Bonnefon }
300f09fa651SNicolas Bonnefon
301dc1c9514SNicolas Bonnefon if ( inserted ) {
302dc1c9514SNicolas Bonnefon dir_records_.push_back( std::weak_ptr<WinWatchedDirRecord>( dir_record ) );
303dc1c9514SNicolas Bonnefon }
304dc1c9514SNicolas Bonnefon }
305dc1c9514SNicolas Bonnefon
waitAndProcessEvents(ObservedFileList<WinWatchTowerDriver> * list,std::unique_lock<std::mutex> * lock,std::vector<ObservedFile<WinWatchTowerDriver> * > *,int timeout_ms)306f09fa651SNicolas Bonnefon std::vector<ObservedFile<WinWatchTowerDriver>*> WinWatchTowerDriver::waitAndProcessEvents(
307f09fa651SNicolas Bonnefon ObservedFileList<WinWatchTowerDriver>* list,
30891f7c705SNicolas Bonnefon std::unique_lock<std::mutex>* lock,
309fcaa7557SNicolas Bonnefon std::vector<ObservedFile<WinWatchTowerDriver>*>* /* not needed in WinWatchTowerDriver */,
310fcaa7557SNicolas Bonnefon int timeout_ms )
311f09fa651SNicolas Bonnefon {
312f09fa651SNicolas Bonnefon std::vector<ObservedFile<WinWatchTowerDriver>*> files_to_notify { };
313f09fa651SNicolas Bonnefon
3143089b1a1SNicolas Bonnefon ULONG_PTR key = 0;
315f09fa651SNicolas Bonnefon DWORD num_bytes = 0;
316f09fa651SNicolas Bonnefon LPOVERLAPPED lpOverlapped = 0;
317f09fa651SNicolas Bonnefon
318fcaa7557SNicolas Bonnefon if ( timeout_ms == 0 )
319fcaa7557SNicolas Bonnefon timeout_ms = INFINITE;
320fcaa7557SNicolas Bonnefon
3213104b268SNicolas Bonnefon lock->unlock();
322dc1c9514SNicolas Bonnefon LOG(logDEBUG) << "waitAndProcessEvents now blocking...";
323f09fa651SNicolas Bonnefon BOOL status = GetQueuedCompletionStatus( hCompPort_,
324f09fa651SNicolas Bonnefon &num_bytes,
325f09fa651SNicolas Bonnefon &key,
326f09fa651SNicolas Bonnefon &lpOverlapped,
327fcaa7557SNicolas Bonnefon timeout_ms );
3283104b268SNicolas Bonnefon lock->lock();
329f09fa651SNicolas Bonnefon
3303104b268SNicolas Bonnefon LOG(logDEBUG) << "Event (" << status << ") key: " << std::hex << key;
331f09fa651SNicolas Bonnefon
332f09fa651SNicolas Bonnefon if ( key ) {
333f09fa651SNicolas Bonnefon // Extract the dir from the completion key
334f09fa651SNicolas Bonnefon auto dir_record_ptr = dir_records_[key - 1];
335f09fa651SNicolas Bonnefon LOG(logDEBUG) << "use_count = " << dir_record_ptr.use_count();
336f09fa651SNicolas Bonnefon
337f09fa651SNicolas Bonnefon if ( std::shared_ptr<WinWatchedDirRecord> dir_record = dir_record_ptr.lock() )
338f09fa651SNicolas Bonnefon {
339f09fa651SNicolas Bonnefon LOG(logDEBUG) << "Got event for dir " << dir_record.get();
340f09fa651SNicolas Bonnefon
341f09fa651SNicolas Bonnefon WinNotificationInfoList notification_info(
342f09fa651SNicolas Bonnefon dir_record->buffer_,
343f09fa651SNicolas Bonnefon dir_record->buffer_length_ );
344f09fa651SNicolas Bonnefon
345f09fa651SNicolas Bonnefon for ( auto notification : notification_info ) {
346f09fa651SNicolas Bonnefon std::string file_path = dir_record->path_ + shortstringize( notification.fileName() );
347f09fa651SNicolas Bonnefon LOG(logDEBUG) << "File is " << file_path;
348f09fa651SNicolas Bonnefon auto file = list->searchByName( file_path );
349f09fa651SNicolas Bonnefon
350f09fa651SNicolas Bonnefon if ( file )
351f09fa651SNicolas Bonnefon {
352f09fa651SNicolas Bonnefon files_to_notify.push_back( file );
353f09fa651SNicolas Bonnefon }
354f09fa651SNicolas Bonnefon }
355f09fa651SNicolas Bonnefon
356f09fa651SNicolas Bonnefon // Re-listen for changes
357f09fa651SNicolas Bonnefon status = ReadDirectoryChangesW(
358f09fa651SNicolas Bonnefon dir_record->handle_,
359f09fa651SNicolas Bonnefon dir_record->buffer_,
360f09fa651SNicolas Bonnefon dir_record->buffer_length_,
361f09fa651SNicolas Bonnefon false,
362f09fa651SNicolas Bonnefon FILE_NOTIFY_CHANGE_FILE_NAME | FILE_NOTIFY_CHANGE_LAST_WRITE,
363f09fa651SNicolas Bonnefon &buffer_length_,// not set when using asynchronous mechanisms...
364f09fa651SNicolas Bonnefon &overlapped_,
365f09fa651SNicolas Bonnefon NULL ); // no completion routine
366f09fa651SNicolas Bonnefon }
367f09fa651SNicolas Bonnefon else {
368f09fa651SNicolas Bonnefon LOG(logWARNING) << "Looks like our dir_record disappeared!";
369f09fa651SNicolas Bonnefon }
370f09fa651SNicolas Bonnefon }
371f09fa651SNicolas Bonnefon else {
372f09fa651SNicolas Bonnefon LOG(logDEBUG) << "Signaled";
373f09fa651SNicolas Bonnefon }
374f09fa651SNicolas Bonnefon
375f09fa651SNicolas Bonnefon {
376f09fa651SNicolas Bonnefon std::lock_guard<std::mutex> lk( action_mutex_ );
377f09fa651SNicolas Bonnefon if ( scheduled_action_ ) {
378f09fa651SNicolas Bonnefon (*scheduled_action_)();
379f09fa651SNicolas Bonnefon scheduled_action_ = nullptr;
380f09fa651SNicolas Bonnefon action_done_cv_.notify_all();
381f09fa651SNicolas Bonnefon }
382f09fa651SNicolas Bonnefon }
383f09fa651SNicolas Bonnefon
384f09fa651SNicolas Bonnefon /*
385f09fa651SNicolas Bonnefon // Just in case someone is waiting for an action to complete
386f09fa651SNicolas Bonnefon std::lock_guard<std::mutex> lk( action_mutex_ );
387f09fa651SNicolas Bonnefon scheduled_action_ = nullptr;
388f09fa651SNicolas Bonnefon action_done_cv_.notify_all();
389f09fa651SNicolas Bonnefon */
390f09fa651SNicolas Bonnefon return files_to_notify;
391f09fa651SNicolas Bonnefon }
392f09fa651SNicolas Bonnefon
interruptWait()393f09fa651SNicolas Bonnefon void WinWatchTowerDriver::interruptWait()
394f09fa651SNicolas Bonnefon {
395dc1c9514SNicolas Bonnefon LOG(logDEBUG) << "Driver::interruptWait()";
396f09fa651SNicolas Bonnefon PostQueuedCompletionStatus( hCompPort_, 0, 0, NULL );
397f09fa651SNicolas Bonnefon }
398f09fa651SNicolas Bonnefon
399f09fa651SNicolas Bonnefon namespace {
shortstringize(const std::wstring & long_string)400f09fa651SNicolas Bonnefon std::string shortstringize( const std::wstring& long_string )
401f09fa651SNicolas Bonnefon {
402f09fa651SNicolas Bonnefon std::string short_result {};
403f09fa651SNicolas Bonnefon
404f09fa651SNicolas Bonnefon for ( wchar_t c : long_string ) {
405f09fa651SNicolas Bonnefon // FIXME: that does not work for non ASCII char!!
406f09fa651SNicolas Bonnefon char short_c = static_cast<char>( c & 0x00FF );
407f09fa651SNicolas Bonnefon short_result += short_c;
408f09fa651SNicolas Bonnefon }
409f09fa651SNicolas Bonnefon
410f09fa651SNicolas Bonnefon return short_result;
411f09fa651SNicolas Bonnefon }
412f09fa651SNicolas Bonnefon
longstringize(const std::string & short_string)413f09fa651SNicolas Bonnefon std::wstring longstringize( const std::string& short_string )
414f09fa651SNicolas Bonnefon {
415f09fa651SNicolas Bonnefon std::wstring long_result {};
416f09fa651SNicolas Bonnefon
417f09fa651SNicolas Bonnefon for ( char c : short_string ) {
418f09fa651SNicolas Bonnefon wchar_t long_c = static_cast<wchar_t>( c );
419f09fa651SNicolas Bonnefon long_result += long_c;
420f09fa651SNicolas Bonnefon }
421f09fa651SNicolas Bonnefon
422f09fa651SNicolas Bonnefon return long_result;
423f09fa651SNicolas Bonnefon }
424f09fa651SNicolas Bonnefon };
425