From f1ff826d0a5fbcb19c77b1548c32d945dbee554c Mon Sep 17 00:00:00 2001 From: Vlad Losev Date: Sun, 23 Apr 2017 13:06:45 -0700 Subject: [PATCH 1/5] Fixes not notifying on deletion of open files under inotify. --- inotify.go | 7 ++++-- inotify_test.go | 57 +++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 62 insertions(+), 2 deletions(-) diff --git a/inotify.go b/inotify.go index d9fd1b88..5785aeac 100644 --- a/inotify.go +++ b/inotify.go @@ -303,12 +303,15 @@ func (e *Event) ignoreLinux(mask uint32) bool { return true } - // If the event is not a DELETE or RENAME, the file must exist. + // If the event is MODIFY or CREATE, the file must exist. // Otherwise the event is ignored. // *Note*: this was put in place because it was seen that a MODIFY // event was sent after the DELETE. This ignores that MODIFY and // assumes a DELETE will come or has come if the file doesn't exist. - if !(e.Op&Remove == Remove || e.Op&Rename == Rename) { + // A CHMOD event (triggeded by IN_MODIFY) can arrive when an open file is + // deleted. In that case the DELETE event is defered until all open + // handles for the file are closed. + if e.Op&Create == Create || e.Op&Write == Write { _, statErr := os.Lstat(e.Name) return os.IsNotExist(statErr) } diff --git a/inotify_test.go b/inotify_test.go index 54f3f00e..456c26f1 100644 --- a/inotify_test.go +++ b/inotify_test.go @@ -447,3 +447,60 @@ func TestInotifyOverflow(t *testing.T) { numDirs*numFiles, creates) } } + +func TestInotifyDeleteOpenFile(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) + } + + 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 watch for %s: %v", testFile, err) + } + + go func() { + err = os.Remove(testFile) + if err != nil { + t.Fatalf("Failed to remove %s: %v", testFile, err) + } + }() + + var event Event + + select { + case event = <-w.Events: + if event.Op != Chmod { + t.Fatalf("Expected first event type %s, got: %v", Chmod, event.Op) + } + case <-time.After(100 * time.Millisecond): + t.Fatalf("Expected first event not delivered") + } + + handle.Close() + select { + case event = <-w.Events: + if event.Op != Remove { + t.Fatalf("Expected second event type %s, got: %v", Remove, event.Op) + } + case <-time.After(100 * time.Millisecond): + t.Fatalf("Expected first event not delivered") + } + + w.Close() + + // Wait for the close to complete. + time.Sleep(50 * time.Millisecond) + isWatcherReallyClosed(t, w) +} From c25ac3ab69d142624194829620226c0ee6900d6e Mon Sep 17 00:00:00 2001 From: Vlad Losev Date: Sun, 23 Apr 2017 13:14:42 -0700 Subject: [PATCH 2/5] Adds explanatory comments. --- inotify_test.go | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/inotify_test.go b/inotify_test.go index 456c26f1..a4427671 100644 --- a/inotify_test.go +++ b/inotify_test.go @@ -470,15 +470,15 @@ func TestInotifyDeleteOpenFile(t *testing.T) { t.Fatalf("Failed to add watch for %s: %v", testFile, err) } - go func() { - err = os.Remove(testFile) - if err != nil { - t.Fatalf("Failed to remove %s: %v", testFile, err) - } - }() + err = os.Remove(testFile) + if err != nil { + t.Fatalf("Failed to remove %s: %v", testFile, err) + } var event Event + // Verify we receive Chmod event caused by the change in the file link count + // when we delete it. select { case event = <-w.Events: if event.Op != Chmod { @@ -488,7 +488,10 @@ func TestInotifyDeleteOpenFile(t *testing.T) { t.Fatalf("Expected first event not delivered") } + // Now close our open handle... handle.Close() + + // ...and observe the file being deleted from the disk. select { case event = <-w.Events: if event.Op != Remove { From e70ff3d689538e11f1abb20bb7c3ea95176a0baf Mon Sep 17 00:00:00 2001 From: Vlad Losev Date: Sun, 23 Apr 2017 13:17:20 -0700 Subject: [PATCH 3/5] Fixes a typo. --- inotify_test.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/inotify_test.go b/inotify_test.go index a4427671..541ca82a 100644 --- a/inotify_test.go +++ b/inotify_test.go @@ -498,7 +498,7 @@ func TestInotifyDeleteOpenFile(t *testing.T) { t.Fatalf("Expected second event type %s, got: %v", Remove, event.Op) } case <-time.After(100 * time.Millisecond): - t.Fatalf("Expected first event not delivered") + t.Fatalf("Expected second event not delivered") } w.Close() From 93e90c899bb6df3578b5d1b91e44624961db3ef5 Mon Sep 17 00:00:00 2001 From: Vlad Losev Date: Fri, 2 Mar 2018 17:43:09 -0800 Subject: [PATCH 4/5] Adds reference to the related issue. --- inotify.go | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/inotify.go b/inotify.go index 5785aeac..5f13a2b3 100644 --- a/inotify.go +++ b/inotify.go @@ -309,8 +309,9 @@ func (e *Event) ignoreLinux(mask uint32) bool { // event was sent after the DELETE. This ignores that MODIFY and // assumes a DELETE will come or has come if the file doesn't exist. // A CHMOD event (triggeded by IN_MODIFY) can arrive when an open file is - // deleted. In that case the DELETE event is defered until all open - // handles for the file are closed. + // deleted. In that case the DELETE event is deferred until all open + // handles for the file are closed. See + // https://github.com/fsnotify/fsnotify/issues/194 for more information. if e.Op&Create == Create || e.Op&Write == Write { _, statErr := os.Lstat(e.Name) return os.IsNotExist(statErr) From 877935a3e4085210e34cf31d023550f2082ea8d1 Mon Sep 17 00:00:00 2001 From: Vlad Losev Date: Fri, 2 Mar 2018 17:43:26 -0800 Subject: [PATCH 5/5] Fixes a typo. --- inotify.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/inotify.go b/inotify.go index 5f13a2b3..3afea4d9 100644 --- a/inotify.go +++ b/inotify.go @@ -308,7 +308,7 @@ func (e *Event) ignoreLinux(mask uint32) bool { // *Note*: this was put in place because it was seen that a MODIFY // event was sent after the DELETE. This ignores that MODIFY and // assumes a DELETE will come or has come if the file doesn't exist. - // A CHMOD event (triggeded by IN_MODIFY) can arrive when an open file is + // A CHMOD event (triggered by IN_MODIFY) can arrive when an open file is // deleted. In that case the DELETE event is deferred until all open // handles for the file are closed. See // https://github.com/fsnotify/fsnotify/issues/194 for more information.