xref: /glogg/src/winwatchtowerdriver.cpp (revision aceb79b236bb246eb5ddb6ccade905333d8e24f7)
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