From c6d8a5dbcac621f3e8f1da9f2aff629ddab42237 Mon Sep 17 00:00:00 2001 From: Martin Tournoij Date: Sun, 16 Oct 2022 21:28:33 +0200 Subject: [PATCH] kqueue: fix removing a directory Fix regression from #526, which would sometimes fail with something along the lines of: --- FAIL: TestWatchRm/remove_watched_directory (1.30s) helpers_test.go:384: fsnotify.sendDirectoryChangeEvents: open /tmp/TestWatchRmremove_watched_directory2055111636/001: no such file or directory fsnotify_test.go:750: have: REMOVE "/a" REMOVE "/b" REMOVE "/c" REMOVE "/d" REMOVE "/e" REMOVE "/f" REMOVE "/g" want: REMOVE "/" REMOVE "/a" REMOVE "/b" REMOVE "/c" REMOVE "/d" REMOVE "/e" REMOVE "/f" REMOVE "/g" REMOVE "/h" REMOVE "/i" REMOVE "/j" We can just always ignore a directory no longer existing; kqueue should still send the correct events. --- backend_kqueue.go | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/backend_kqueue.go b/backend_kqueue.go index f9a0951f..16571363 100644 --- a/backend_kqueue.go +++ b/backend_kqueue.go @@ -194,8 +194,8 @@ func (w *Watcher) sendEvent(e Event) bool { case w.Events <- e: return true case <-w.done: + return false } - return false } // Returns true if the error was sent, or false if watcher is closed. @@ -204,8 +204,8 @@ func (w *Watcher) sendError(err error) bool { case w.Errors <- err: return true case <-w.done: + return false } - return false } // Close removes all watches and closes the events channel. @@ -544,7 +544,7 @@ func (w *Watcher) readEvents() { } if path.isDir && event.Has(Write) && !event.Has(Remove) { - w.sendDirectoryChangeEvents(event.Name, false) + w.sendDirectoryChangeEvents(event.Name) } else { if !w.sendEvent(event) { closed = true @@ -553,15 +553,15 @@ func (w *Watcher) readEvents() { } if event.Has(Remove) { - // Look for a file that may have overwritten this. - // For example, mv f1 f2 will delete f2, then create f2. + // Look for a file that may have overwritten this; for example, + // mv f1 f2 will delete f2, then create f2. if path.isDir { fileDir := filepath.Clean(event.Name) w.mu.Lock() _, found := w.watches[fileDir] w.mu.Unlock() if found { - w.sendDirectoryChangeEvents(fileDir, true) + w.sendDirectoryChangeEvents(fileDir) } } else { filePath := filepath.Clean(event.Name) @@ -634,21 +634,21 @@ func (w *Watcher) watchDirectoryFiles(dirPath string) error { // // This functionality is to have the BSD watcher match the inotify, which sends // a create event for files created in a watched directory. -func (w *Watcher) sendDirectoryChangeEvents(dir string, ignoreNotExists bool) { +func (w *Watcher) sendDirectoryChangeEvents(dir string) { files, err := ioutil.ReadDir(dir) if err != nil { - // Directory could have been deleted already; just ignore that. - if ignoreNotExists && errors.Is(err, os.ErrNotExist) { - return - } - if !w.sendError(fmt.Errorf("fsnotify.sendDirectoryChangeEvents: %w", err)) { - return + // Directory no longer exists: we can ignore this safely. kqueue will + // still give us the correct events. + if !errors.Is(err, os.ErrNotExist) { + w.sendError(fmt.Errorf("fsnotify.sendDirectoryChangeEvents: %w", err)) } + return } for _, fi := range files { err := w.sendFileCreatedEventIfNew(filepath.Join(dir, fi.Name()), fi) if err != nil { + w.sendError(fmt.Errorf("fsnotify.sendDirectoryChangeEvents: %w", err)) return } }