Skip to content

Commit

Permalink
Add recursive watcher support under Windows
Browse files Browse the repository at this point in the history
This adds a new method, SetRecursive, to the Watcher structure returned
by NewWatcher. It enables the Watcher to monitor subdirectories of the
watched directories.

Currently this functionality is only supported under Windows. Calling
the SetRecursive method in all other OS-es will return an error.
  • Loading branch information
adriansr committed Apr 17, 2018
1 parent c282820 commit c9bbe1f
Show file tree
Hide file tree
Showing 4 changed files with 37 additions and 9 deletions.
6 changes: 6 additions & 0 deletions fen.go
Original file line number Diff line number Diff line change
Expand Up @@ -35,3 +35,9 @@ func (w *Watcher) Add(name string) error {
func (w *Watcher) Remove(name string) error {
return nil
}

// SetRecursive enables watches to also monitor subdirectories. Currently
// only supported under Windows.
func (w *Watcher) SetRecursive() error {
return nil

This comment has been minimized.

Copy link
@andrewkroh

andrewkroh Apr 19, 2018

Shouldn't this return an error?

This comment has been minimized.

Copy link
@adriansr

adriansr Apr 19, 2018

Author Owner

As this platform (solaris) is not supported at all by fsnotify, what it does is return an error in NewWatcher, and all the Watcher methods return nil. I just copied what all the other methods are doing in this case, but I agree it looks a bit inconsistent with the other platforms.

}
6 changes: 6 additions & 0 deletions inotify.go
Original file line number Diff line number Diff line change
Expand Up @@ -162,6 +162,12 @@ func (w *Watcher) Remove(name string) error {
return nil
}

// SetRecursive enables watches to also monitor subdirectories. Currently
// only supported under Windows.
func (w *Watcher) SetRecursive() error {
return errors.New("recursion not supported")
}

type watch struct {
wd uint32 // Watch descriptor (as returned by the inotify_add_watch() syscall)
flags uint32 // inotify flags of this watch (see inotify(7) for the list of valid flags)
Expand Down
6 changes: 6 additions & 0 deletions kqueue.go
Original file line number Diff line number Diff line change
Expand Up @@ -147,6 +147,12 @@ func (w *Watcher) Remove(name string) error {
return nil
}

// SetRecursive enables watches to also monitor subdirectories. Currently
// only supported under Windows.
func (w *Watcher) SetRecursive() error {
return errors.New("recursion not supported")
}

// Watch all events (except NOTE_EXTEND, NOTE_LINK, NOTE_REVOKE)
const noteAllEvents = unix.NOTE_DELETE | unix.NOTE_WRITE | unix.NOTE_ATTRIB | unix.NOTE_RENAME

Expand Down
28 changes: 19 additions & 9 deletions windows.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,20 +13,22 @@ import (
"path/filepath"
"runtime"
"sync"
"sync/atomic"
"syscall"
"unsafe"
)

// Watcher watches a set of files, delivering events to a channel.
type Watcher struct {
Events chan Event
Errors chan error
isClosed bool // Set to true when Close() is first called
mu sync.Mutex // Map access
port syscall.Handle // Handle to completion port
watches watchMap // Map of watches (key: i-number)
input chan *input // Inputs to the reader are sent on this channel
quit chan chan<- error
Events chan Event
Errors chan error
isClosed bool // Set to true when Close() is first called
mu sync.Mutex // Map access
port syscall.Handle // Handle to completion port
watches watchMap // Map of watches (key: i-number)
input chan *input // Inputs to the reader are sent on this channel
quit chan chan<- error
watchSubTree uint32
}

// NewWatcher establishes a new watcher with the underlying OS and begins waiting for events.
Expand Down Expand Up @@ -95,6 +97,13 @@ func (w *Watcher) Remove(name string) error {
return <-in.reply
}

// SetRecursive enables watches to also monitor subdirectories. Currently
// only supported under Windows.
func (w *Watcher) SetRecursive() error {
atomic.StoreUint32(&w.watchSubTree, 1)
return nil
}

const (
// Options for AddWatch
sysFSONESHOT = 0x80000000
Expand Down Expand Up @@ -348,7 +357,8 @@ 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)), atomic.LoadUint32(&w.watchSubTree) != 0,
mask, nil, &watch.ov, 0)
if e != nil {
err := os.NewSyscallError("ReadDirectoryChanges", e)
if e == syscall.ERROR_ACCESS_DENIED && watch.mask&provisional == 0 {
Expand Down

0 comments on commit c9bbe1f

Please sign in to comment.