On Windows a FILE_ACTION_MODIFIED event (i.e. a Write event) is
triggered on file attribute changes, rather than some dedicates
ATTRIBUTE_CHANGED event. Looking at the docs, I don't really see a way
to distinguish between "real" write events and attribute changes. This is
very odd, but seems to be how the ReadDirectoryChangesW() API works.
The only way I can see to distinguish between the two events is to set
up two filters: one with a FILE_NOTIFY_CHANGE_ATTRIBUTES, and one
without. But that seems overly complex, and no one asked to get Chmod
events for Windows; it's not really all that interesting on Windows
anyway.
The problem is that some software (anti-virus, backup software, etc.)
can issue lots of attribute changes, causing a lot of "fake" Write
events.
So remove the FILE_NOTIFY_CHANGE_ATTRIBUTES and sysFSATTRIB flags.
This was adapted from the tilt-dev/fsnotify fork:
https://github.com/tilt-dev/fsnotify/pull/8
Fixes #487
// This should all be removed at some point, and just use windows.FILE_NOTIFY_*
const (
sysFSALLEVENTS = 0xfff
- sysFSATTRIB = 0x4
sysFSCREATE = 0x100
sysFSDELETE = 0x200
sysFSDELETESELF = 0x400
if mask&sysFSMOVE == sysFSMOVE || mask&sysFSMOVESELF == sysFSMOVESELF || mask&sysFSMOVEDFROM == sysFSMOVEDFROM {
e.Op |= Rename
}
- if mask&sysFSATTRIB == sysFSATTRIB {
- e.Op |= Chmod
- }
return e
}
if mask&sysFSMODIFY != 0 {
m |= windows.FILE_NOTIFY_CHANGE_LAST_WRITE
}
- if mask&sysFSATTRIB != 0 {
- m |= windows.FILE_NOTIFY_CHANGE_ATTRIBUTES
- }
if mask&(sysFSMOVE|sysFSCREATE|sysFSDELETE) != 0 {
m |= windows.FILE_NOTIFY_CHANGE_FILE_NAME | windows.FILE_NOTIFY_CHANGE_DIR_NAME
}
}
check(0)
}
+
+func TestWindowsNoAttributeChanges(t *testing.T) {
+ tmp := t.TempDir()
+ file := filepath.Join(tmp, "TestFsnotifyEventsExisting.testfile")
+
+ touch(t, file) // Create a file before watching directory
+ w := newCollector(t, tmp)
+ w.collect(t)
+ chmod(t, 0o400, file) // Make the file read-only, which is an attribute change
+
+ have := w.stop(t)
+ if len(have) != 0 {
+ t.Fatalf("should not have received any events, received:\n%s", have)
+ }
+}
symlink(t, filepath.Join(tmp, "file"), tmp, "link")
}, `
create /link
-
- windows:
- create /link
- write /link
`},
{"create new symlink to directory", func(t *testing.T, w *Watcher, tmp string) {
addWatch(t, w, tmp)
symlink(t, tmp, tmp, "link")
}, `
create /link
-
- windows:
- create /link
- write /link
`},
// FIFO
}, `
create /link
- windows:
- create /link
- write /link
-
# No events at all on Dragonfly
# TODO: should fix this.
dragonfly: