From: Chris Howey Date: Mon, 2 Jul 2012 23:30:37 +0000 (-0500) Subject: BSD - FSNotify flags X-Git-Tag: v1.7.2~419 X-Git-Url: https://go.fuhry.dev/?a=commitdiff_plain;h=97df35bc44a2a28a50185f39241415025c8f07db;p=fsnotify.git BSD - FSNotify flags --- diff --git a/fsnotify.go b/fsnotify.go index 023665e..33c74b5 100644 --- a/fsnotify.go +++ b/fsnotify.go @@ -2,6 +2,60 @@ package fsnotify import "fmt" +const ( + FSN_CREATE = 1 + FSN_MODIFY = 2 + FSN_DELETE = 4 + FSN_RENAME = 8 + + FSN_ALL = FSN_MODIFY | FSN_DELETE | FSN_RENAME | FSN_CREATE +) + +// Purge events from interal chan to external chan if passes filter +func (w *Watcher) purgeEvents() { + for ev := range w.internalEvent { + sendEvent := false + fsnFlags := w.fsnFlags[ev.Name] + + if (fsnFlags&FSN_CREATE == FSN_CREATE) && ev.IsCreate() { + sendEvent = true + } + + if (fsnFlags&FSN_MODIFY == FSN_MODIFY) && ev.IsModify() { + sendEvent = true + } + + if (fsnFlags&FSN_DELETE == FSN_DELETE) && ev.IsDelete() { + sendEvent = true + } + + if (fsnFlags&FSN_RENAME == FSN_RENAME) && ev.IsRename() { + sendEvent = true + } + + if sendEvent { + w.Event <- ev + } + } + + close(w.Event) +} + +func (w *Watcher) Watch(path string) error { + w.fsnFlags[path] = FSN_ALL + return w.watch(path) +} + +func (w *Watcher) WatchFlags(path string, flags uint32) error { + w.fsnFlags[path] = flags + return w.watch(path) +} + +func (w *Watcher) RemoveWatch(path string) error { + delete(w.fsnFlags, path) + return w.removeWatch(path) +} + // String formats the event e in the form // "filename: DELETE|MODIFY|..." func (e *FileEvent) String() string { diff --git a/fsnotify_bsd.go b/fsnotify_bsd.go index 7799a39..8348208 100644 --- a/fsnotify_bsd.go +++ b/fsnotify_bsd.go @@ -37,15 +37,17 @@ func (e *FileEvent) IsModify() bool { func (e *FileEvent) IsRename() bool { return (e.mask & NOTE_RENAME) == NOTE_RENAME } type Watcher struct { - kq int // File descriptor (as returned by the kqueue() syscall) - watches map[string]int // Map of watched file diescriptors (key: path) - paths map[int]string // Map of watched paths (key: watch descriptor) - finfo map[int]os.FileInfo // Map of file information (isDir, isReg; key: watch descriptor) - Error chan error // Errors are sent on this channel - Event chan *FileEvent // Events are returned on this channel - done chan bool // Channel for sending a "quit message" to the reader goroutine - isClosed bool // Set to true when Close() is first called - kbuf [1]syscall.Kevent_t // An event buffer for Add/Remove watch + kq int // File descriptor (as returned by the kqueue() syscall) + watches map[string]int // Map of watched file diescriptors (key: path) + fsnFlags map[string]uint32 // Map of watched files to flags used for filter + paths map[int]string // Map of watched paths (key: watch descriptor) + finfo map[int]os.FileInfo // Map of file information (isDir, isReg; key: watch descriptor) + Error chan error // Errors are sent on this channel + internalEvent chan *FileEvent // Events are queued on this channel + Event chan *FileEvent // Events are returned on this channel + done chan bool // Channel for sending a "quit message" to the reader goroutine + isClosed bool // Set to true when Close() is first called + kbuf [1]syscall.Kevent_t // An event buffer for Add/Remove watch } // NewWatcher creates and returns a new kevent instance using kqueue(2) @@ -55,16 +57,19 @@ func NewWatcher() (*Watcher, error) { return nil, os.NewSyscallError("kqueue", errno) } w := &Watcher{ - kq: fd, - watches: make(map[string]int), - paths: make(map[int]string), - finfo: make(map[int]os.FileInfo), - Event: make(chan *FileEvent), - Error: make(chan error), - done: make(chan bool, 1), + kq: fd, + watches: make(map[string]int), + fsnFlags: make(map[string]uint32), + paths: make(map[int]string), + finfo: make(map[int]os.FileInfo), + internalEvent: make(chan *FileEvent), + Event: make(chan *FileEvent), + Error: make(chan error), + done: make(chan bool, 1), } go w.readEvents() + go w.purgeEvents() return w, nil } @@ -80,7 +85,7 @@ func (w *Watcher) Close() error { // Send "quit" message to the reader goroutine w.done <- true for path := range w.watches { - w.RemoveWatch(path) + w.removeWatch(path) } return nil @@ -151,12 +156,12 @@ func (w *Watcher) addWatch(path string, flags uint32) error { } // Watch adds path to the watched file set, watching all events. -func (w *Watcher) Watch(path string) error { +func (w *Watcher) watch(path string) error { return w.addWatch(path, NOTE_ALLEVENTS) } // RemoveWatch removes path from the watched file set. -func (w *Watcher) RemoveWatch(path string) error { +func (w *Watcher) removeWatch(path string) error { watchfd, ok := w.watches[path] if !ok { return errors.New(fmt.Sprintf("can't remove non-existent kevent watch for: %s", path)) @@ -202,7 +207,7 @@ func (w *Watcher) readEvents() { if errno != nil { w.Error <- os.NewSyscallError("close", errno) } - close(w.Event) + close(w.internalEvent) close(w.Error) return } @@ -236,7 +241,7 @@ func (w *Watcher) readEvents() { w.sendDirectoryChangeEvents(fileEvent.Name) } else { // Send the event on the events channel - w.Event <- fileEvent + w.internalEvent <- fileEvent } // Move to next event @@ -258,6 +263,7 @@ func (w *Watcher) watchDirectoryFiles(dirPath string) error { filePath := filepath.Join(dirPath, fileInfo.Name()) // Watch file to mimic linux fsnotify e := w.addWatch(filePath, NOTE_DELETE|NOTE_WRITE|NOTE_RENAME) + w.fsnFlags[filePath] = FSN_ALL if e != nil { return e } @@ -283,11 +289,12 @@ func (w *Watcher) sendDirectoryChangeEvents(dirPath string) { if fileInfo.IsDir() == false { filePath := filepath.Join(dirPath, fileInfo.Name()) if w.watches[filePath] == 0 { + w.fsnFlags[filePath] = FSN_ALL // Send create event fileEvent := new(FileEvent) fileEvent.Name = filePath fileEvent.create = true - w.Event <- fileEvent + w.internalEvent <- fileEvent } } }