Skip to content

Commit

Permalink
Do not suppress Chmod on non-existent file
Browse files Browse the repository at this point in the history
Currently fsnorify suppresses a Chmod event if the file does not exist
when event is received.

This prevents a possibility of fsnotify user to detect a situation
when an opened file is removed. In such case the Linux kernel sends
IN_ATTRIB event, as described in inotify(7) man page:

> IN_ATTRIB (*)
>        Metadata  changed—for example, permissions (e.g., chmod(2)),
>        timestamps (e.g., utimensat(2)), extended attributes  (setx‐
>        attr(2)), link count (since Linux 2.6.25; e.g., for the tar‐
>        get of link(2) and for unlink(2)), and user/group ID  (e.g.,
>        chown(2)).

To fix:
 * Modify the code to only suppress MODIFY and CREATE events.
 * Add a test case to verify Chmod event is delivered.

While at it, fix the comment in ignoreLinux() to use the up-to-date
terminology (event ops).

Signed-off-by: Kir Kolyshkin <kolyshkin@gmail.com>
  • Loading branch information
kolyshkin committed Aug 16, 2018
1 parent c282820 commit 486df7f
Show file tree
Hide file tree
Showing 2 changed files with 55 additions and 6 deletions.
12 changes: 6 additions & 6 deletions inotify.go
Expand Up @@ -303,12 +303,12 @@ func (e *Event) ignoreLinux(mask uint32) bool {
return true
}

// If the event is not a DELETE or RENAME, 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) {
// If the event is Create or Write, the file must exist, or the
// event will be suppressed.
// *Note*: this was put in place because it was seen that a Write
// event was sent after the Remove. This ignores the Write and
// assumes a Remove will come or has come if the file doesn't exist.
if e.Op&Create == Create || e.Op&Write == Write {
_, statErr := os.Lstat(e.Name)
return os.IsNotExist(statErr)
}
Expand Down
49 changes: 49 additions & 0 deletions inotify_test.go
Expand Up @@ -447,3 +447,52 @@ func TestInotifyOverflow(t *testing.T) {
numDirs*numFiles, creates)
}
}

func TestInotifyDeleteOpenedFile(t *testing.T) {
testDir := tempMkdir(t)
defer os.RemoveAll(testDir)

testFile := filepath.Join(testDir, "testfile")

// create and open a file
fd, err := os.Create(testFile)
if err != nil {
t.Fatalf("Create failed: %v", err)
}
defer fd.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 watch for %s: %v", testFile, err)
}

checkEvent := func(exp Op) {
select {
case event := <-w.Events:
t.Logf("Event received: %s", event.Op)
if event.Op != exp {
t.Fatalf("Event expected: %s, got: %s", exp, event.Op)
}
case <-time.After(100 * time.Millisecond):
t.Fatalf("Expected %s event not received", exp)
}
}

// Remove the (opened) file, check Chmod event (notifying
// about file link count change) is received
err = os.Remove(testFile)
if err != nil {
t.Fatalf("Failed to remove file: %s", err)
}
checkEvent(Chmod)

// Close the file, check Remove event is received
fd.Close()
checkEvent(Remove)
}

0 comments on commit 486df7f

Please sign in to comment.