From 97ee4422b522c8a21b9f8bd09c6030ea965c875c Mon Sep 17 00:00:00 2001 From: b0bh00d Date: Tue, 2 Mar 2021 20:26:01 -0700 Subject: [PATCH 1/2] Added the AddDeepWatch() and DeepWatch() functions to enable the 'bWatchSubtree' parameter of ReadDirectoryChanges() for getting events anywhere within the watched folder tree. The original functions, AddWatch() and Watch(), continue to behave as they did before (shallow). --- winfsnotify/winfsnotify.go | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/winfsnotify/winfsnotify.go b/winfsnotify/winfsnotify.go index 678129127..49fcd427f 100644 --- a/winfsnotify/winfsnotify.go +++ b/winfsnotify/winfsnotify.go @@ -40,6 +40,7 @@ type input struct { path string flags uint32 reply chan error + recurse bool } type inode struct { @@ -56,6 +57,7 @@ type watch struct { names map[string]uint64 // Map of names being watched and their notify flags rename string // Remembers the old name while renaming a file buf [4096]byte + recurse bool } type indexMap map[uint64]*watch @@ -111,7 +113,7 @@ func (w *Watcher) Close() error { } // AddWatch adds path to the watched file set. -func (w *Watcher) AddWatch(path string, flags uint32) error { +func (w *Watcher) AddWatch(path string, flags uint32, isRecursive bool) error { if w.isClosed { return errors.New("watcher already closed") } @@ -120,6 +122,7 @@ func (w *Watcher) AddWatch(path string, flags uint32) error { path: filepath.Clean(path), flags: flags, reply: make(chan error), + recurse: isRecursive } w.input <- in if err := w.wakeupReader(); err != nil { @@ -218,7 +221,7 @@ func (m watchMap) set(ino *inode, watch *watch) { } // Must run within the I/O thread. -func (w *Watcher) addWatch(pathname string, flags uint64) error { +func (w *Watcher) addWatch(pathname string, flags uint64, isRecursive bool) error { dir, err := getDir(pathname) if err != nil { return err @@ -240,6 +243,7 @@ func (w *Watcher) addWatch(pathname string, flags uint64) error { ino: ino, path: dir, names: make(map[string]uint64), + recurse: isRecursive } w.watches.set(ino, watchEntry) flags |= provisional @@ -321,7 +325,7 @@ func (w *Watcher) startRead(watch *watch) error { return nil } e := syscall.ReadDirectoryChanges(watch.ino.handle, &watch.buf[0], - uint32(unsafe.Sizeof(watch.buf)), false, mask, nil, &watch.ov, 0) + uint32(unsafe.Sizeof(watch.buf)), watch.recurse, mask, nil, &watch.ov, 0) if e != nil { err := os.NewSyscallError("ReadDirectoryChanges", e) if e == syscall.ERROR_ACCESS_DENIED && watch.mask&provisional == 0 { @@ -374,7 +378,7 @@ func (w *Watcher) readEvents() { case in := <-w.input: switch in.op { case opAddWatch: - in.reply <- w.addWatch(in.path, uint64(in.flags)) + in.reply <- w.addWatch(in.path, uint64(in.flags), in.recurse) case opRemoveWatch: in.reply <- w.removeWatch(in.path) } From 1305fe561f77c056d8f2d30112c0913c4f350430 Mon Sep 17 00:00:00 2001 From: b0bh00d Date: Wed, 3 Mar 2021 07:19:49 -0700 Subject: [PATCH 2/2] The new AddDeepWatch() and DeepWatch() functions were missing for some reason. --- winfsnotify/winfsnotify.go | 66 ++++++++++++++++++++++++++------------ 1 file changed, 45 insertions(+), 21 deletions(-) diff --git a/winfsnotify/winfsnotify.go b/winfsnotify/winfsnotify.go index 49fcd427f..ca8414f67 100644 --- a/winfsnotify/winfsnotify.go +++ b/winfsnotify/winfsnotify.go @@ -36,10 +36,10 @@ const ( ) type input struct { - op int - path string - flags uint32 - reply chan error + op int + path string + flags uint32 + reply chan error recurse bool } @@ -50,13 +50,13 @@ type inode struct { } type watch struct { - ov syscall.Overlapped - ino *inode // i-number - path string // Directory path - mask uint64 // Directory itself is being watched with these notify flags - names map[string]uint64 // Map of names being watched and their notify flags - rename string // Remembers the old name while renaming a file - buf [4096]byte + ov syscall.Overlapped + ino *inode // i-number + path string // Directory path + mask uint64 // Directory itself is being watched with these notify flags + names map[string]uint64 // Map of names being watched and their notify flags + rename string // Remembers the old name while renaming a file + buf [4096]byte recurse bool } @@ -113,16 +113,35 @@ func (w *Watcher) Close() error { } // AddWatch adds path to the watched file set. -func (w *Watcher) AddWatch(path string, flags uint32, isRecursive bool) error { +func (w *Watcher) AddWatch(path string, flags uint32) error { if w.isClosed { return errors.New("watcher already closed") } in := &input{ - op: opAddWatch, - path: filepath.Clean(path), - flags: flags, - reply: make(chan error), - recurse: isRecursive + op: opAddWatch, + path: filepath.Clean(path), + flags: flags, + reply: make(chan error), + recurse: false, + } + w.input <- in + if err := w.wakeupReader(); err != nil { + return err + } + return <-in.reply +} + +// AddDeepWatch adds path to the watched file set which will monitor the entire subtree. +func (w *Watcher) AddDeepWatch(path string, flags uint32) error { + if w.isClosed { + return errors.New("watcher already closed") + } + in := &input{ + op: opAddWatch, + path: filepath.Clean(path), + flags: flags, + reply: make(chan error), + recurse: true, } w.input <- in if err := w.wakeupReader(); err != nil { @@ -136,6 +155,11 @@ func (w *Watcher) Watch(path string) error { return w.AddWatch(path, FS_ALL_EVENTS) } +// DeepWatch adds path to the watched file set, watching all events in the entire subtree. +func (w *Watcher) DeepWatch(path string) error { + return w.AddDeepWatch(path, FS_ALL_EVENTS) +} + // RemoveWatch removes path from the watched file set. func (w *Watcher) RemoveWatch(path string) error { in := &input{ @@ -240,10 +264,10 @@ func (w *Watcher) addWatch(pathname string, flags uint64, isRecursive bool) erro return os.NewSyscallError("CreateIoCompletionPort", e) } watchEntry = &watch{ - ino: ino, - path: dir, - names: make(map[string]uint64), - recurse: isRecursive + ino: ino, + path: dir, + names: make(map[string]uint64), + recurse: isRecursive, } w.watches.set(ino, watchEntry) flags |= provisional