def _loop_asynchronous(self, callback): buf = win32file.AllocateReadBuffer(8192) overlapped = pywintypes.OVERLAPPED() overlapped.hEvent = win32event.CreateEvent(None, 0, 0, None) while not self._stopped: win32file.ReadDirectoryChangesW(self._hdir, buf, self._recurse, self._filter, overlapped) ## ## This will block until notification OR timeout. ## rc = win32event.WaitForSingleObject(overlapped.hEvent, self._timeout) if rc == win32event.WAIT_OBJECT_0: ## got event: determine data length .. n = win32file.GetOverlappedResult(self._hdir, overlapped, True) if n: ## retrieve data results = win32file.FILE_NOTIFY_INFORMATION(buf, n) r = [(DirWatcher._ACTIONS.get(x[0], "UNKNOWN"), x[1]) for x in results] if len(r) > 0: callback(r) else: # directory handled was closed self._stopped = True else: ## timeout pass
def _watcherThreadOverlapped(self, dn, dh, changes): flags = win32con.FILE_NOTIFY_CHANGE_FILE_NAME buf = win32file.AllocateReadBuffer(8192) overlapped = pywintypes.OVERLAPPED() overlapped.hEvent = win32event.CreateEvent(None, 0, 0, None) while 1: win32file.ReadDirectoryChangesW( dh, buf, False, #sub-tree flags, overlapped) # Wait for our event, or for 5 seconds. rc = win32event.WaitForSingleObject(overlapped.hEvent, 5000) if rc == win32event.WAIT_OBJECT_0: # got some data! Must use GetOverlappedResult to find out # how much is valid! 0 generally means the handle has # been closed. Blocking is OK here, as the event has # already been set. nbytes = win32file.GetOverlappedResult(dh, overlapped, True) if nbytes: bits = win32file.FILE_NOTIFY_INFORMATION(buf, nbytes) changes.extend(bits) else: # This is "normal" exit - our 'tearDown' closes the # handle. # print "looks like dir handle was closed!" return else: print("ERROR: Watcher thread timed-out!") return # kill the thread!
def _read_watch(self, watch): if win32event.WaitForSingleObject(watch.event, 0) \ == win32event.WAIT_TIMEOUT: nbytes = 0 else: nbytes = win32file.GetOverlappedResult(watch.handle, watch.overlapped, False) return win32file.FILE_NOTIFY_INFORMATION(watch.buffer, nbytes)
def read(self): if win32event.WaitForSingleObject(self.event, 0) \ == win32event.WAIT_TIMEOUT: result = [] else: nbytes = win32file.GetOverlappedResult(self.handle, self.overlapped, False) result = win32file.FILE_NOTIFY_INFORMATION(self.buffer, nbytes) self._start() return result
def process_events(watch, num): for action, name in win32file.FILE_NOTIFY_INFORMATION(watch._buf.raw, num): action = action_map.get(action) if action is not None and (action & watch.flags): yield FSEvent(watch, action, name) try: read_changes(watch) except pywintypes.error as e: if e.args[0] == 5: close_watch(watch) yield FSEvent(watch, FSEvent.DeleteSelf) else: raise FSMonitorWindowsError(*e.args)
def run(self): hDir = win32file.CreateFileW( self._watch_path, FILE_LIST_DIRECTORY, win32con.FILE_SHARE_READ | win32con.FILE_SHARE_WRITE, None, win32con.OPEN_EXISTING, win32con.FILE_FLAG_BACKUP_SEMANTICS | win32con.FILE_FLAG_OVERLAPPED, None ) while self._windows_sucks_flag: buf = win32file.AllocateReadBuffer(1024) win32file.ReadDirectoryChangesW( hDir, buf, True, win32con.FILE_NOTIFY_CHANGE_FILE_NAME | win32con.FILE_NOTIFY_CHANGE_DIR_NAME | win32con.FILE_NOTIFY_CHANGE_SIZE | win32con.FILE_NOTIFY_CHANGE_LAST_WRITE, self._overlapped ) result_stack = {} rc = win32event.WaitForMultipleObjects((self._wait_stop, self._overlapped.hEvent), 0, win32event.INFINITE) if rc == win32event.WAIT_OBJECT_0: # Stop event break data = win32file.GetOverlappedResult(hDir, self._overlapped, True) # lets read the data and store it in the results results = win32file.FILE_NOTIFY_INFORMATION(buf, data) for action, afile in results: if action in ACTIONS: full_filename = os.path.join(self._watch_path, afile) result_stack.setdefault(full_filename, []).append(ACTIONS.get(action)) keys = list(result_stack.keys()) while len(keys): key = keys.pop(0) event = result_stack.pop(key) if (ADDED in event) and (DELETED in event): event = [e for e in event if e not in (ADDED, DELETED)] noticed = [] for each_event in event: if each_event not in noticed: self._callback(each_event, full_filename) noticed.append(each_event)
def process_events(watch, num): for action, name in win32file.FILE_NOTIFY_INFORMATION( watch._buf.raw, num): if action is not None and ( action & win32con.FILE_NOTIFY_CHANGE_FILE_NAME | win32con.FILE_NOTIFY_CHANGE_LAST_WRITE): yield FSEvent(watch, action, name) try: read_changes(watch) except pywintypes.error, e: if e.args[0] == 5: close_watch(watch) yield FSEvent(watch, FSEvent.DeleteSelf) else: raise FSMonitorWindowsError(*e.args)
def monitor_dir_async(file_path, handle_function, run, key): dir_handle = get_dir_handle(file_path, True) buffer = win32file.AllocateReadBuffer(BUF_SIZE) overlapped = pywintypes.OVERLAPPED() overlapped.hEvent = win32event.CreateEvent(None, False, 0, None) while run.value: read_dir_changes(dir_handle, buffer, overlapped) rc = win32event.WaitForSingleObject(overlapped.hEvent, ASYNC_TIMEOUT) if rc == win32event.WAIT_OBJECT_0: bufer_size = win32file.GetOverlappedResult(dir_handle, overlapped, True) results = win32file.FILE_NOTIFY_INFORMATION(buffer, bufer_size) handle_function(results, file_path, key) elif rc == win32event.WAIT_TIMEOUT: pass win32api.CloseHandle(overlapped.hEvent) dir_handle.close()
def _read_events(self): """Reads the events from the system and formats as ``DirWatcherEvent``. :returns: List of ``(DirWatcherEvent, <path>)`` """ result = [] while self._changed: info = self._changed.popleft() try: size = win32file.GetOverlappedResult(info.file, info.overlapped, False) except win32file.error as exc: win32event.ResetEvent(info.overlapped.hEvent) _LOGGER.warning( 'Failed to get directory changes for \'%s\': %s', info.path, exc) if exc.winerror == winerror.ERROR_ACCESS_DENIED: self._preempt_watch(info, result) continue notifications = win32file.FILE_NOTIFY_INFORMATION(info.buffer, size) for action, path in notifications: action_name = _ACTION_NAMES.get(action) path = os.path.join(info.path, path) if action_name is None: _LOGGER.error('Received unknown action (%s, \'%s\')', action, path) continue _LOGGER.debug('Received event (%s, \'%s\')', action_name, path) event = _EVENTS.get(action_name) if event is not None: result.append((event, path)) win32event.ResetEvent(info.overlapped.hEvent) if not self._read_dir(info): self._preempt_watch(info, result) return result
def main(): flags = win32con.FILE_NOTIFY_CHANGE_FILE_NAME dh = win32file.CreateFile( "C:\\", 0x0001, win32con.FILE_SHARE_READ | win32con.FILE_SHARE_WRITE | win32con.FILE_SHARE_DELETE, None, win32con.OPEN_EXISTING, win32con.FILE_FLAG_BACKUP_SEMANTICS | win32con.FILE_FLAG_OVERLAPPED, None) overlapped = pywintypes.OVERLAPPED() overlapped.hEvent = win32event.CreateEvent(None, 0, 0, None) buf = win32file.AllocateReadBuffer(8192) changes = [] iterations = 0 timedout = False while True: iterations += 1 print(iterations) if timedout == False: # This is to ensure the directory handle only has one instance of ReadDirectoryChangesW at a time. # If this isn't here and ReadDirectoryChangesW stacks up without being used, it will break after 60-64 iterations if # using a mapped network folder and the directory handle will need to be closed (dh.close()) and reopened. win32file.ReadDirectoryChangesW(dh, buf, True, flags, overlapped) rc = win32event.MsgWaitForMultipleObjects([overlapped.hEvent], False, 5000, win32event.QS_ALLEVENTS) # rc = win32event.WaitForSingleObject(overlapped.hEvent, 5000) # Also acceptable # rc = win32event.WaitForMultipleObjects([overlapped.hEvent], False, 5000) # Also acceptable if rc == win32event.WAIT_TIMEOUT: timedout = True print('timed out') if rc == win32event.WAIT_OBJECT_0: # can replace win32event.WAIT_OBJECT_0 with the integer 0 (and win32event.WAIT_OBJECT_0+1 with 1) timedout = False # since we got a result, reset the timedout variable so ReadDirectoryChangesW can be run again result = win32file.GetOverlappedResult(dh, overlapped, True) if result: bufferData = win32file.FILE_NOTIFY_INFORMATION(buf, result) changes.extend(bufferData) print(bufferData) for x in bufferData: if x[1] == 'break': # for testing, create a file named "break" in the watched folder and the script will stop and print the list of files print("\nFinal result!") return changes else: print('dir handle closed')
def run_win32(self): """Generate notifications using pywin32""" hdir = win32file.CreateFile( self._path, 0x0001, win32con.FILE_SHARE_READ | win32con.FILE_SHARE_WRITE, None, win32con.OPEN_EXISTING, win32con.FILE_FLAG_BACKUP_SEMANTICS | win32con.FILE_FLAG_OVERLAPPED, None) flags = (win32con.FILE_NOTIFY_CHANGE_FILE_NAME | win32con.FILE_NOTIFY_CHANGE_DIR_NAME | win32con.FILE_NOTIFY_CHANGE_ATTRIBUTES | win32con.FILE_NOTIFY_CHANGE_SIZE | win32con.FILE_NOTIFY_CHANGE_LAST_WRITE | win32con.FILE_NOTIFY_CHANGE_SECURITY) buf = win32file.AllocateReadBuffer(8192) overlapped = pywintypes.OVERLAPPED() overlapped.hEvent = win32event.CreateEvent(None, 0, 0, None) handler = Handler() while self._running: win32file.ReadDirectoryChangesW(hdir, buf, True, flags, overlapped) rc = win32event.WaitForSingleObject(overlapped.hEvent, self._timeout) if rc != win32event.WAIT_OBJECT_0: continue nbytes = win32file.GetOverlappedResult(hdir, overlapped, True) if not nbytes: continue results = win32file.FILE_NOTIFY_INFORMATION(buf, nbytes) for action, path in results: if not self._running: break path = path.replace('\\', '/') if (not path.startswith('.git/') and '/.git/' not in path and os.path.isfile(path)): handler.handle(path)
async def polling_task(self): while True: for item in self._watch_list: try: length = win32file.GetOverlappedResult(item[2], item[3], 0) except pywintypes.error as e: if e.args[0] == 996: # Overlapped I/O event is not in a signaled state continue else: raise e else: for action, name in win32file.FILE_NOTIFY_INFORMATION( item[-1], length): target = os.path.join(item[1], name) if action == FILE_ACTION_MODIFIED and not os.path.isfile( target): # Ignore directory modify event continue elif action == FILE_ACTION_MODIFIED and os.path.isfile( target): dir_node = self._get_dir_node(item[1]) if name not in dir_node: # Auto insert file create event self._event_queue.put_nowait( (target, item[0], FILE_ACTION_ADDED)) dir_node[name] = None elif action == FILE_ACTION_REMOVED: path = target remove_root = target while not os.path.exists(path): # Get remove root remove_root = path path = os.path.dirname(path) if self._get_dir_node(remove_root): # Insert remove sub dirs/files event def _handle_sub_dir(path): dir_node = self._get_dir_node(path) for it in dir_node: if isinstance(dir_node[it], dict): if dir_node[it]: _handle_sub_dir( os.path.join(path, it)) self._event_queue.put_nowait(( os.path.join(path, it), EnumWatchType.WATCH_DIRECTORY, action, )) else: self._event_queue.put_nowait(( os.path.join(path, it), EnumWatchType.WATCH_FILE, action, )) _handle_sub_dir(remove_root) self._event_queue.put_nowait(( remove_root, EnumWatchType.WATCH_DIRECTORY, action, )) parent_dir_node = self._get_dir_node( os.path.dirname(remove_root)) parent_dir_node.pop( os.path.split(remove_root)[-1]) continue self._event_queue.put_nowait((target, item[0], action)) if action == FILE_ACTION_ADDED and os.path.isdir( target): # Handle mkdir -p def _handle_sub_dir(path): dir_node = self._get_dir_node(path, True) for it in os.listdir(path): if it in dir_node: continue subpath = os.path.join(path, it) if os.path.isdir(subpath): watch_type = EnumWatchType.WATCH_DIRECTORY dir_node[it] = {} else: watch_type = EnumWatchType.WATCH_FILE dir_node[it] = None self._event_queue.put_nowait( (subpath, watch_type, action)) if os.path.isdir(subpath): _handle_sub_dir(subpath) dir_node = self._get_dir_node(item[1]) dir_node[name] = {} _handle_sub_dir(target) elif action == FILE_ACTION_ADDED and os.path.isfile( target): # Auto fire modify event self._event_queue.put_nowait( (target, item[0], FILE_ACTION_MODIFIED)) dir_node = self._get_dir_node( os.path.dirname(target)) dir_node[os.path.split(target)[-1]] = None # Continue to listen self._add_dir_watch(item[2], item[4], item[3]) self._add_file_watch(item[2], item[4], item[3]) await asyncio.sleep(0.005)
import os, sys import pywintypes import win32file import win32event import win32con import ntsecuritycon overlapped = pywintypes.OVERLAPPED() overlapped.hEvent = win32event.CreateEvent(None, 0, 0, None) hDir = win32file.CreateFile( "c:/temp", ntsecuritycon.FILE_LIST_DIRECTORY, win32file.FILE_SHARE_READ | win32file.FILE_SHARE_WRITE | win32file.FILE_SHARE_DELETE, None, win32con.OPEN_EXISTING, win32con.FILE_FLAG_BACKUP_SEMANTICS | win32con.FILE_FLAG_OVERLAPPED, None) buffer = win32file.AllocateReadBuffer(8192) while True: print "#0", win32file.ReadDirectoryChangesW( hDir, buffer, True, win32con.FILE_NOTIFY_CHANGE_FILE_NAME, overlapped) print "#1" rc = win32event.WaitForSingleObject(overlapped.hEvent, 1000) print "#2", rc if rc == win32event.WAIT_OBJECT_0: n_bytes = win32file.GetOverlappedResult(hDir, overlapped, True) if n_bytes: print win32file.FILE_NOTIFY_INFORMATION(buffer, n_bytes) else: break