From cc2c34eeb074ea38c16dbea8600ba03ea36bc9b0 Mon Sep 17 00:00:00 2001 From: Chris Howey Date: Wed, 13 Mar 2013 18:47:20 -0500 Subject: [PATCH] Linux - Fixes issue #36 --- fsnotify.go | 10 +++++++++- fsnotify_linux.go | 45 +++++++++++++++++++++++++++++++++++---------- 2 files changed, 44 insertions(+), 11 deletions(-) diff --git a/fsnotify.go b/fsnotify.go index ed731a5..f371960 100644 --- a/fsnotify.go +++ b/fsnotify.go @@ -37,13 +37,21 @@ func (w *Watcher) purgeEvents() { } if (fsnFlags&FSN_RENAME == FSN_RENAME) && ev.IsRename() { - //w.RemoveWatch(ev.Name) sendEvent = true } if sendEvent { w.Event <- ev } + + // If there's no file, then no more events for user + // BSD must keep watch for internal use (watches DELETEs to keep track + // what files exist for create events) + if ev.IsDelete() { + w.fsnmut.Lock() + delete(w.fsnFlags, ev.Name) + w.fsnmut.Unlock() + } } close(w.Event) diff --git a/fsnotify_linux.go b/fsnotify_linux.go index 3f0241b..074ff60 100644 --- a/fsnotify_linux.go +++ b/fsnotify_linux.go @@ -211,17 +211,17 @@ func (w *Watcher) readEvents() { event.Name += "/" + strings.TrimRight(string(bytes[0:nameLen]), "\000") } - // Setup FSNotify flags (inherit from directory watch) - w.fsnmut.Lock() - fsnFlags := w.fsnFlags[watchedName] - _, fsnFound := w.fsnFlags[event.Name] - if !fsnFound { - w.fsnFlags[event.Name] = fsnFlags - } - w.fsnmut.Unlock() - // Send the events that are not ignored on the events channel - if (event.mask & IN_IGNORED) == 0 { + if !event.ignoreLinux() { + // Setup FSNotify flags (inherit from directory watch) + w.fsnmut.Lock() + fsnFlags := w.fsnFlags[watchedName] + _, fsnFound := w.fsnFlags[event.Name] + if !fsnFound { + w.fsnFlags[event.Name] = fsnFlags + } + w.fsnmut.Unlock() + w.internalEvent <- event } @@ -231,6 +231,31 @@ func (w *Watcher) readEvents() { } } +// Certain types of events can be "ignored" and not sent over the Event +// channel. Such as events marked ignore by the kernel, or MODIFY events +// against files that do not exist. +func (e *FileEvent) ignoreLinux() bool { + // Ignore anything the inotify API says to ignore + if e.mask&IN_IGNORED == IN_IGNORED { + 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.mask&IN_DELETE == IN_DELETE || + e.mask&IN_DELETE_SELF == IN_DELETE_SELF || + e.mask&IN_MOVED_FROM == IN_MOVED_FROM || + e.mask&IN_MOVE_SELF == IN_MOVE_SELF) { + if _, statErr := os.Stat(e.Name); os.IsNotExist(statErr) { + return true + } + } + return false +} + const ( // Options for inotify_init() are not exported // IN_CLOEXEC uint32 = syscall.IN_CLOEXEC