Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fixes inotify not notifying on deletion of open files. #205

Closed
wants to merge 5 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
8 changes: 6 additions & 2 deletions inotify.go
Expand Up @@ -303,12 +303,16 @@ 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 (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.
if e.Op&Create == Create || e.Op&Write == Write {
_, statErr := os.Lstat(e.Name)
return os.IsNotExist(statErr)
}
Expand Down
60 changes: 60 additions & 0 deletions inotify_test.go
Expand Up @@ -447,3 +447,63 @@ func TestInotifyOverflow(t *testing.T) {
numDirs*numFiles, creates)
}
}

func TestInotifyDeleteOpenFile(t *testing.T) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

should have t.Parallel()

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)
}

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 {
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")
}

// 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 {
t.Fatalf("Expected second event type %s, got: %v", Remove, event.Op)
}
case <-time.After(100 * time.Millisecond):
t.Fatalf("Expected second event not delivered")
}

w.Close()

// Wait for the close to complete.
time.Sleep(50 * time.Millisecond)
isWatcherReallyClosed(t, w)
}