From: Pieter Droogendijk Date: Sun, 8 Feb 2015 02:50:54 +0000 (+0100) Subject: When removing, delete from watches before removing from inotify (fixes go-fsnotify... X-Git-Tag: v1.7.2~222 X-Git-Url: https://go.fuhry.dev/?a=commitdiff_plain;h=ae966a22c363db3ce4b6cf5e2994250e4b51b93a;p=fsnotify.git When removing, delete from watches before removing from inotify (fixes go-fsnotify/fsnotify#40) --- diff --git a/inotify.go b/inotify.go index 3978fb5..d7759ec 100644 --- a/inotify.go +++ b/inotify.go @@ -132,11 +132,20 @@ func (w *Watcher) Remove(name string) error { if !ok { return fmt.Errorf("can't remove non-existent inotify watch for: %s", name) } + // inotify_rm_watch will return EINVAL if the file has been deleted; + // the inotify will already have been removed. + // That means we can safely delete it from our watches, whatever inotify_rm_watch does. + delete(w.watches, name) success, errno := syscall.InotifyRmWatch(w.fd, watch.wd) if success == -1 { + // TODO: Perhaps it's not helpful to return an error here in every case. + // the only two possible errors are: + // EBADF, which happens when w.fd is not a valid file descriptor of any kind. + // EINVAL, which is when fd is not an inotify descriptor or wd is not a valid watch descriptor. + // Watch descriptors are invalidated when they are removed explicitly or implicitly; + // explicitly by inotify_rm_watch, implicitly when the file they are watching is deleted. return errno } - delete(w.watches, name) return nil } diff --git a/inotify_test.go b/inotify_test.go index 32432c6..035ee8f 100644 --- a/inotify_test.go +++ b/inotify_test.go @@ -252,3 +252,41 @@ func TestInotifyStress(t *testing.T) { } } } + +func TestInotifyRemoveTwice(t *testing.T) { + testDir := tempMkdir(t) + defer os.RemoveAll(testDir) + testFile := filepath.Join(testDir, "testfile") + + handle, err := os.Create(testFile) + if err != nil { + t.Fatalf("Create failed: %v", err) + } + handle.Close() + + w, err := NewWatcher() + if err != nil { + t.Fatalf("Failed to create watcher: %v", err) + } + defer w.Close() + + err = w.Add(testFile) + if err != nil { + t.Fatalf("Failed to add testFile: %v", err) + } + + err = os.Remove(testFile) + if err != nil { + t.Fatalf("Failed to remove testFile: %v", err) + } + + err = w.Remove(testFile) + if err != syscall.EINVAL { + t.Fatalf("Expected EINVAL from Remove, got: %v", err) + } + + err = w.Remove(testFile) + if err == syscall.EINVAL { + t.Fatalf("Got EINVAL again, watch was not removed") + } +}