Skip to content
This repository has been archived by the owner on Jun 8, 2022. It is now read-only.

Commit

Permalink
Linux - Fixes issue #36
Browse files Browse the repository at this point in the history
  • Loading branch information
howeyc committed Mar 14, 2013
1 parent 1800992 commit cc2c34e
Show file tree
Hide file tree
Showing 2 changed files with 44 additions and 11 deletions.
10 changes: 9 additions & 1 deletion fsnotify.go
Original file line number Diff line number Diff line change
Expand Up @@ -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

This comment has been minimized.

Copy link
@nathany

nathany Jan 31, 2014

Contributor

@howeyc I'm trying to understand this block of code. So removing fsnFlags here would effectively prevent any additional events from occurring on that file because it is 0? But there are places where if fsnFlags is not found it takes on FSN_ALL?

The reason I'm trying to understand this is because purgeEvents is just one kind of filter on events coming off the channel. If os/fsnotify isn't going to implement any sort of filters, I'd propose to exclude this code and process all events in user-code or a third-party library. But in doing that, what do we lose?

This comment has been minimized.

Copy link
@howeyc

howeyc Jan 31, 2014

Author Owner

@nathany You've basically got it right. The flag is removed so no further events would be passed on to the user.

As for places where no fsnFlags is not found it defaults to FSN_ALL, there isn't really a reason I chose that over nothing (0). Other than that if I screwed up somewhere passing flags from the parent folder down, I defaulted to passing an event on to the user rather than not.

As to removing the filters, I don't think you'll lose anything. That's how a lot of users had been using it for a while, and I believe some still do.

// 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)
Expand Down
45 changes: 35 additions & 10 deletions fsnotify_linux.go
Original file line number Diff line number Diff line change
Expand Up @@ -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
}

Expand All @@ -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

This comment has been minimized.

Copy link
@nhooyr

nhooyr May 12, 2018

How could a MODIFY event be sent after the DELETE? @howeyc

// 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
Expand Down

0 comments on commit cc2c34e

Please sign in to comment.