Update fsnotify to v1.4.7 (#5792)

fsnotify v1.3.1 uses unix.InotifyInit() which is not available on
mips64/mips64le. Updating to a newer version allows builds to succeed on
these platforms.

Signed-off-by: Jeffery To <jeffery.to@gmail.com>
This commit is contained in:
Jeffery To 2019-07-23 22:53:50 +08:00 committed by Brian Brazil
parent fb2b3c2b0b
commit d91f724637
13 changed files with 184 additions and 87 deletions

View file

@ -43,10 +43,8 @@ crossbuild:
- linux/arm64 - linux/arm64
- freebsd/arm - freebsd/arm
- openbsd/arm - openbsd/arm
# Temporarily deactivated as golang.org/x/sys does not have syscalls - linux/mips64
# implemented for that os/platform combination. - linux/mips64le
#- linux/mips64
#- linux/mips64le
- netbsd/arm - netbsd/arm
- linux/ppc64 - linux/ppc64
- linux/ppc64le - linux/ppc64le

2
go.mod
View file

@ -57,7 +57,7 @@ require (
google.golang.org/genproto v0.0.0-20190307195333-5fe7a883aa19 google.golang.org/genproto v0.0.0-20190307195333-5fe7a883aa19
google.golang.org/grpc v1.19.1 google.golang.org/grpc v1.19.1
gopkg.in/alecthomas/kingpin.v2 v2.2.6 gopkg.in/alecthomas/kingpin.v2 v2.2.6
gopkg.in/fsnotify/fsnotify.v1 v1.3.1 gopkg.in/fsnotify/fsnotify.v1 v1.4.7
gopkg.in/inf.v0 v0.9.1 // indirect gopkg.in/inf.v0 v0.9.1 // indirect
gopkg.in/yaml.v2 v2.2.2 gopkg.in/yaml.v2 v2.2.2
k8s.io/api v0.0.0-20190718183219-b59d8169aab5 k8s.io/api v0.0.0-20190718183219-b59d8169aab5

4
go.sum
View file

@ -409,8 +409,8 @@ gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 h1:qIbj1fsPNlZgppZ+VLlY7N33
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/fsnotify.v1 v1.4.7 h1:xOHLXZwVvI9hhs+cLKq5+I5onOuwQLhQwiu63xxlHs4= gopkg.in/fsnotify.v1 v1.4.7 h1:xOHLXZwVvI9hhs+cLKq5+I5onOuwQLhQwiu63xxlHs4=
gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys= gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys=
gopkg.in/fsnotify/fsnotify.v1 v1.3.1 h1:2fkCHbPQZNYRAyRyIV9VX0bpRkxIorlQDiYRmufHnhA= gopkg.in/fsnotify/fsnotify.v1 v1.4.7 h1:XNNYLJHt73EyYiCZi6+xjupS9CpvmiDgjPTAjrBlQbo=
gopkg.in/fsnotify/fsnotify.v1 v1.3.1/go.mod h1:Fyux9zXlo4rWoMSIzpn9fDAYjalPqJ/K1qJ27s+7ltE= gopkg.in/fsnotify/fsnotify.v1 v1.4.7/go.mod h1:Fyux9zXlo4rWoMSIzpn9fDAYjalPqJ/K1qJ27s+7ltE=
gopkg.in/inf.v0 v0.9.0/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw= gopkg.in/inf.v0 v0.9.0/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw=
gopkg.in/inf.v0 v0.9.1 h1:73M5CoZyi3ZLMOyDlQh031Cx6N9NDJ2Vvfl76EDAgDc= gopkg.in/inf.v0 v0.9.1 h1:73M5CoZyi3ZLMOyDlQh031Cx6N9NDJ2Vvfl76EDAgDc=
gopkg.in/inf.v0 v0.9.1/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw= gopkg.in/inf.v0 v0.9.1/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw=

5
vendor/gopkg.in/fsnotify/fsnotify.v1/.editorconfig generated vendored Normal file
View file

@ -0,0 +1,5 @@
root = true
[*]
indent_style = tab
indent_size = 4

View file

@ -2,13 +2,14 @@ sudo: false
language: go language: go
go: go:
- 1.5.4 - 1.8.x
- 1.6.1 - 1.9.x
- tip - tip
matrix: matrix:
allow_failures: allow_failures:
- go: tip - go: tip
fast_finish: true
before_script: before_script:
- go get -u github.com/golang/lint/golint - go get -u github.com/golang/lint/golint

View file

@ -8,8 +8,10 @@
# Please keep the list sorted. # Please keep the list sorted.
Aaron L <aaron@bettercoder.net>
Adrien Bustany <adrien@bustany.org> Adrien Bustany <adrien@bustany.org>
Amit Krishnan <amit.krishnan@oracle.com> Amit Krishnan <amit.krishnan@oracle.com>
Anmol Sethi <me@anmol.io>
Bjørn Erik Pedersen <bjorn.erik.pedersen@gmail.com> Bjørn Erik Pedersen <bjorn.erik.pedersen@gmail.com>
Bruno Bigras <bigras.bruno@gmail.com> Bruno Bigras <bigras.bruno@gmail.com>
Caleb Spare <cespare@gmail.com> Caleb Spare <cespare@gmail.com>
@ -26,17 +28,23 @@ Kelvin Fo <vmirage@gmail.com>
Ken-ichirou MATSUZAWA <chamas@h4.dion.ne.jp> Ken-ichirou MATSUZAWA <chamas@h4.dion.ne.jp>
Matt Layher <mdlayher@gmail.com> Matt Layher <mdlayher@gmail.com>
Nathan Youngman <git@nathany.com> Nathan Youngman <git@nathany.com>
Nickolai Zeldovich <nickolai@csail.mit.edu>
Patrick <patrick@dropbox.com>
Paul Hammond <paul@paulhammond.org> Paul Hammond <paul@paulhammond.org>
Pawel Knap <pawelknap88@gmail.com> Pawel Knap <pawelknap88@gmail.com>
Pieter Droogendijk <pieter@binky.org.uk> Pieter Droogendijk <pieter@binky.org.uk>
Pursuit92 <JoshChase@techpursuit.net> Pursuit92 <JoshChase@techpursuit.net>
Riku Voipio <riku.voipio@linaro.org> Riku Voipio <riku.voipio@linaro.org>
Rob Figueiredo <robfig@gmail.com> Rob Figueiredo <robfig@gmail.com>
Rodrigo Chiossi <rodrigochiossi@gmail.com>
Slawek Ligus <root@ooz.ie>
Soge Zhang <zhssoge@gmail.com> Soge Zhang <zhssoge@gmail.com>
Tiffany Jernigan <tiffany.jernigan@intel.com> Tiffany Jernigan <tiffany.jernigan@intel.com>
Tilak Sharma <tilaks@google.com> Tilak Sharma <tilaks@google.com>
Tom Payne <twpayne@gmail.com>
Travis Cline <travis.cline@gmail.com> Travis Cline <travis.cline@gmail.com>
Tudor Golubenco <tudor.g@gmail.com> Tudor Golubenco <tudor.g@gmail.com>
Vahe Khachikyan <vahe@live.ca>
Yukang <moorekang@gmail.com> Yukang <moorekang@gmail.com>
bronze1man <bronze1man@gmail.com> bronze1man <bronze1man@gmail.com>
debrando <denis.brandolini@gmail.com> debrando <denis.brandolini@gmail.com>

View file

@ -1,8 +1,30 @@
# Changelog # Changelog
## v1.4.7 / 2018-01-09
* BSD/macOS: Fix possible deadlock on closing the watcher on kqueue (thanks @nhooyr and @glycerine)
* Tests: Fix missing verb on format string (thanks @rchiossi)
* Linux: Fix deadlock in Remove (thanks @aarondl)
* Linux: Watch.Add improvements (avoid race, fix consistency, reduce garbage) (thanks @twpayne)
* Docs: Moved FAQ into the README (thanks @vahe)
* Linux: Properly handle inotify's IN_Q_OVERFLOW event (thanks @zeldovich)
* Docs: replace references to OS X with macOS
## v1.4.2 / 2016-10-10
* Linux: use InotifyInit1 with IN_CLOEXEC to stop leaking a file descriptor to a child process when using fork/exec [#178](https://github.com/fsnotify/fsnotify/pull/178) (thanks @pattyshack)
## v1.4.1 / 2016-10-04
* Fix flaky inotify stress test on Linux [#177](https://github.com/fsnotify/fsnotify/pull/177) (thanks @pattyshack)
## v1.4.0 / 2016-10-01
* add a String() method to Event.Op [#165](https://github.com/fsnotify/fsnotify/pull/165) (thanks @oozie)
## v1.3.1 / 2016-06-28 ## v1.3.1 / 2016-06-28
* windows: fix for double backslash when watching the root of a drive [#151](https://github.com/fsnotify/fsnotify/issues/151) (thanks @brunoqc) * Windows: fix for double backslash when watching the root of a drive [#151](https://github.com/fsnotify/fsnotify/issues/151) (thanks @brunoqc)
## v1.3.0 / 2016-04-19 ## v1.3.0 / 2016-04-19
@ -67,7 +89,7 @@ kqueue: Fix logic for CREATE after REMOVE [#111](https://github.com/fsnotify/fsn
## v1.0.2 / 2014-08-17 ## v1.0.2 / 2014-08-17
* [Fix] Missing create events on OS X. [#14](https://github.com/fsnotify/fsnotify/issues/14) (thanks @zhsso) * [Fix] Missing create events on macOS. [#14](https://github.com/fsnotify/fsnotify/issues/14) (thanks @zhsso)
* [Fix] Make ./path and path equivalent. (thanks @zhsso) * [Fix] Make ./path and path equivalent. (thanks @zhsso)
## v1.0.0 / 2014-08-15 ## v1.0.0 / 2014-08-15
@ -130,7 +152,7 @@ kqueue: Fix logic for CREATE after REMOVE [#111](https://github.com/fsnotify/fsn
## v0.9.2 / 2014-08-17 ## v0.9.2 / 2014-08-17
* [Backport] Fix missing create events on OS X. [#14](https://github.com/fsnotify/fsnotify/issues/14) (thanks @zhsso) * [Backport] Fix missing create events on macOS. [#14](https://github.com/fsnotify/fsnotify/issues/14) (thanks @zhsso)
## v0.9.1 / 2014-06-12 ## v0.9.1 / 2014-06-12
@ -149,7 +171,7 @@ kqueue: Fix logic for CREATE after REMOVE [#111](https://github.com/fsnotify/fsn
## v0.8.11 / 2013-11-02 ## v0.8.11 / 2013-11-02
* [Doc] Add Changelog [#72][] (thanks @nathany) * [Doc] Add Changelog [#72][] (thanks @nathany)
* [Doc] Spotlight and double modify events on OS X [#62][] (reported by @paulhammond) * [Doc] Spotlight and double modify events on macOS [#62][] (reported by @paulhammond)
## v0.8.10 / 2013-10-19 ## v0.8.10 / 2013-10-19

View file

@ -17,7 +17,7 @@ Please indicate that you have signed the CLA in your pull request.
### How fsnotify is Developed ### How fsnotify is Developed
* Development is done on feature branches. * Development is done on feature branches.
* Tests are run on BSD, Linux, OS X and Windows. * Tests are run on BSD, Linux, macOS and Windows.
* Pull requests are reviewed and [applied to master][am] using [hub][]. * Pull requests are reviewed and [applied to master][am] using [hub][].
* Maintainers may modify or squash commits rather than asking contributors to. * Maintainers may modify or squash commits rather than asking contributors to.
* To issue a new release, the maintainers will: * To issue a new release, the maintainers will:
@ -40,11 +40,11 @@ Contribute upstream:
3. Push to the branch (`git push fork my-new-feature`) 3. Push to the branch (`git push fork my-new-feature`)
4. Create a new Pull Request on GitHub 4. Create a new Pull Request on GitHub
This workflow is [thoroughly explained by Katrina Owen](https://blog.splice.com/contributing-open-source-git-repositories-go/). This workflow is [thoroughly explained by Katrina Owen](https://splice.com/blog/contributing-open-source-git-repositories-go/).
### Testing ### Testing
fsnotify uses build tags to compile different code on Linux, BSD, OS X, and Windows. fsnotify uses build tags to compile different code on Linux, BSD, macOS, and Windows.
Before doing a pull request, please do your best to test your changes on multiple platforms, and list which platforms you were able/unable to test on. Before doing a pull request, please do your best to test your changes on multiple platforms, and list which platforms you were able/unable to test on.
@ -58,7 +58,7 @@ To aid in cross-platform testing there is a Vagrantfile for Linux and BSD.
Notice: fsnotify file system events won't trigger in shared folders. The tests get around this limitation by using the /tmp directory. Notice: fsnotify file system events won't trigger in shared folders. The tests get around this limitation by using the /tmp directory.
Right now there is no equivalent solution for Windows and OS X, but there are Windows VMs [freely available from Microsoft](http://www.modern.ie/en-us/virtualization-tools#downloads). Right now there is no equivalent solution for Windows and macOS, but there are Windows VMs [freely available from Microsoft](http://www.modern.ie/en-us/virtualization-tools#downloads).
### Maintainers ### Maintainers

View file

@ -1,6 +1,6 @@
# File system notifications for Go # File system notifications for Go
[![GoDoc](https://godoc.org/github.com/fsnotify/fsnotify?status.svg)](https://godoc.org/github.com/fsnotify/fsnotify) [![Go Report Card](https://goreportcard.com/badge/github.com/fsnotify/fsnotify)](https://goreportcard.com/report/github.com/fsnotify/fsnotify) [![Coverage](http://gocover.io/_badge/github.com/fsnotify/fsnotify)](http://gocover.io/github.com/fsnotify/fsnotify) [![GoDoc](https://godoc.org/github.com/fsnotify/fsnotify?status.svg)](https://godoc.org/github.com/fsnotify/fsnotify) [![Go Report Card](https://goreportcard.com/badge/github.com/fsnotify/fsnotify)](https://goreportcard.com/report/github.com/fsnotify/fsnotify)
fsnotify utilizes [golang.org/x/sys](https://godoc.org/golang.org/x/sys) rather than `syscall` from the standard library. Ensure you have the latest version installed by running: fsnotify utilizes [golang.org/x/sys](https://godoc.org/golang.org/x/sys) rather than `syscall` from the standard library. Ensure you have the latest version installed by running:
@ -8,14 +8,14 @@ fsnotify utilizes [golang.org/x/sys](https://godoc.org/golang.org/x/sys) rather
go get -u golang.org/x/sys/... go get -u golang.org/x/sys/...
``` ```
Cross platform: Windows, Linux, BSD and OS X. Cross platform: Windows, Linux, BSD and macOS.
|Adapter |OS |Status | |Adapter |OS |Status |
|----------|----------|----------| |----------|----------|----------|
|inotify |Linux 2.6.27 or later, Android\*|Supported [![Build Status](https://travis-ci.org/fsnotify/fsnotify.svg?branch=master)](https://travis-ci.org/fsnotify/fsnotify)| |inotify |Linux 2.6.27 or later, Android\*|Supported [![Build Status](https://travis-ci.org/fsnotify/fsnotify.svg?branch=master)](https://travis-ci.org/fsnotify/fsnotify)|
|kqueue |BSD, OS X, iOS\*|Supported [![Build Status](https://travis-ci.org/fsnotify/fsnotify.svg?branch=master)](https://travis-ci.org/fsnotify/fsnotify)| |kqueue |BSD, macOS, iOS\*|Supported [![Build Status](https://travis-ci.org/fsnotify/fsnotify.svg?branch=master)](https://travis-ci.org/fsnotify/fsnotify)|
|ReadDirectoryChangesW|Windows|Supported [![Build status](https://ci.appveyor.com/api/projects/status/ivwjubaih4r0udeh/branch/master?svg=true)](https://ci.appveyor.com/project/NathanYoungman/fsnotify/branch/master)| |ReadDirectoryChangesW|Windows|Supported [![Build status](https://ci.appveyor.com/api/projects/status/ivwjubaih4r0udeh/branch/master?svg=true)](https://ci.appveyor.com/project/NathanYoungman/fsnotify/branch/master)|
|FSEvents |OS X |[Planned](https://github.com/fsnotify/fsnotify/issues/11)| |FSEvents |macOS |[Planned](https://github.com/fsnotify/fsnotify/issues/11)|
|FEN |Solaris 11 |[In Progress](https://github.com/fsnotify/fsnotify/issues/12)| |FEN |Solaris 11 |[In Progress](https://github.com/fsnotify/fsnotify/issues/12)|
|fanotify |Linux 2.6.37+ | | |fanotify |Linux 2.6.37+ | |
|USN Journals |Windows |[Maybe](https://github.com/fsnotify/fsnotify/issues/53)| |USN Journals |Windows |[Maybe](https://github.com/fsnotify/fsnotify/issues/53)|
@ -23,7 +23,7 @@ Cross platform: Windows, Linux, BSD and OS X.
\* Android and iOS are untested. \* Android and iOS are untested.
Please see [the documentation](https://godoc.org/github.com/fsnotify/fsnotify) for usage. Consult the [Wiki](https://github.com/fsnotify/fsnotify/wiki) for the FAQ and further information. Please see [the documentation](https://godoc.org/github.com/fsnotify/fsnotify) and consult the [FAQ](#faq) for usage information.
## API stability ## API stability
@ -41,6 +41,35 @@ Please refer to [CONTRIBUTING][] before opening an issue or pull request.
See [example_test.go](https://github.com/fsnotify/fsnotify/blob/master/example_test.go). See [example_test.go](https://github.com/fsnotify/fsnotify/blob/master/example_test.go).
## FAQ
**When a file is moved to another directory is it still being watched?**
No (it shouldn't be, unless you are watching where it was moved to).
**When I watch a directory, are all subdirectories watched as well?**
No, you must add watches for any directory you want to watch (a recursive watcher is on the roadmap [#18][]).
**Do I have to watch the Error and Event channels in a separate goroutine?**
As of now, yes. Looking into making this single-thread friendly (see [howeyc #7][#7])
**Why am I receiving multiple events for the same file on OS X?**
Spotlight indexing on OS X can result in multiple events (see [howeyc #62][#62]). A temporary workaround is to add your folder(s) to the *Spotlight Privacy settings* until we have a native FSEvents implementation (see [#11][]).
**How many files can be watched at once?**
There are OS-specific limits as to how many watches can be created:
* Linux: /proc/sys/fs/inotify/max_user_watches contains the limit, reaching this limit results in a "no space left on device" error.
* BSD / OSX: sysctl variables "kern.maxfiles" and "kern.maxfilesperproc", reaching these limits results in a "too many open files" error.
[#62]: https://github.com/howeyc/fsnotify/issues/62
[#18]: https://github.com/fsnotify/fsnotify/issues/18
[#11]: https://github.com/fsnotify/fsnotify/issues/11
[#7]: https://github.com/howeyc/fsnotify/issues/7
[contributing]: https://github.com/fsnotify/fsnotify/blob/master/CONTRIBUTING.md [contributing]: https://github.com/fsnotify/fsnotify/blob/master/CONTRIBUTING.md
## Related Projects ## Related Projects

View file

@ -9,6 +9,7 @@ package fsnotify
import ( import (
"bytes" "bytes"
"errors"
"fmt" "fmt"
) )
@ -30,33 +31,36 @@ const (
Chmod Chmod
) )
// String returns a string representation of the event in the form func (op Op) String() string {
// "file: REMOVE|WRITE|..."
func (e Event) String() string {
// Use a buffer for efficient string concatenation // Use a buffer for efficient string concatenation
var buffer bytes.Buffer var buffer bytes.Buffer
if e.Op&Create == Create { if op&Create == Create {
buffer.WriteString("|CREATE") buffer.WriteString("|CREATE")
} }
if e.Op&Remove == Remove { if op&Remove == Remove {
buffer.WriteString("|REMOVE") buffer.WriteString("|REMOVE")
} }
if e.Op&Write == Write { if op&Write == Write {
buffer.WriteString("|WRITE") buffer.WriteString("|WRITE")
} }
if e.Op&Rename == Rename { if op&Rename == Rename {
buffer.WriteString("|RENAME") buffer.WriteString("|RENAME")
} }
if e.Op&Chmod == Chmod { if op&Chmod == Chmod {
buffer.WriteString("|CHMOD") buffer.WriteString("|CHMOD")
} }
// If buffer remains empty, return no event names
if buffer.Len() == 0 { if buffer.Len() == 0 {
return fmt.Sprintf("%q: ", e.Name) return ""
} }
return buffer.String()[1:] // Strip leading pipe
// Return a list of event names, with leading pipe character stripped
return fmt.Sprintf("%q: %s", e.Name, buffer.String()[1:])
} }
// String returns a string representation of the event in the form
// "file: REMOVE|WRITE|..."
func (e Event) String() string {
return fmt.Sprintf("%q: %s", e.Name, e.Op.String())
}
// Common errors that can be reported by a watcher
var ErrEventOverflow = errors.New("fsnotify queue overflow")

View file

@ -24,7 +24,6 @@ type Watcher struct {
Events chan Event Events chan Event
Errors chan error Errors chan error
mu sync.Mutex // Map access mu sync.Mutex // Map access
cv *sync.Cond // sync removing on rm_watch with IN_IGNORE
fd int fd int
poller *fdPoller poller *fdPoller
watches map[string]*watch // Map of inotify watches (key: path) watches map[string]*watch // Map of inotify watches (key: path)
@ -36,7 +35,7 @@ type Watcher struct {
// NewWatcher establishes a new watcher with the underlying OS and begins waiting for events. // NewWatcher establishes a new watcher with the underlying OS and begins waiting for events.
func NewWatcher() (*Watcher, error) { func NewWatcher() (*Watcher, error) {
// Create inotify fd // Create inotify fd
fd, errno := unix.InotifyInit() fd, errno := unix.InotifyInit1(unix.IN_CLOEXEC)
if fd == -1 { if fd == -1 {
return nil, errno return nil, errno
} }
@ -56,7 +55,6 @@ func NewWatcher() (*Watcher, error) {
done: make(chan struct{}), done: make(chan struct{}),
doneResp: make(chan struct{}), doneResp: make(chan struct{}),
} }
w.cv = sync.NewCond(&w.mu)
go w.readEvents() go w.readEvents()
return w, nil return w, nil
@ -103,21 +101,23 @@ func (w *Watcher) Add(name string) error {
var flags uint32 = agnosticEvents var flags uint32 = agnosticEvents
w.mu.Lock() w.mu.Lock()
watchEntry, found := w.watches[name] defer w.mu.Unlock()
w.mu.Unlock() watchEntry := w.watches[name]
if found { if watchEntry != nil {
watchEntry.flags |= flags flags |= watchEntry.flags | unix.IN_MASK_ADD
flags |= unix.IN_MASK_ADD
} }
wd, errno := unix.InotifyAddWatch(w.fd, name, flags) wd, errno := unix.InotifyAddWatch(w.fd, name, flags)
if wd == -1 { if wd == -1 {
return errno return errno
} }
w.mu.Lock() if watchEntry == nil {
w.watches[name] = &watch{wd: uint32(wd), flags: flags} w.watches[name] = &watch{wd: uint32(wd), flags: flags}
w.paths[wd] = name w.paths[wd] = name
w.mu.Unlock() } else {
watchEntry.wd = uint32(wd)
watchEntry.flags = flags
}
return nil return nil
} }
@ -135,6 +135,13 @@ func (w *Watcher) Remove(name string) error {
if !ok { if !ok {
return fmt.Errorf("can't remove non-existent inotify watch for: %s", name) return fmt.Errorf("can't remove non-existent inotify watch for: %s", name)
} }
// We successfully removed the watch if InotifyRmWatch doesn't return an
// error, we need to clean up our internal state to ensure it matches
// inotify's kernel state.
delete(w.paths, int(watch.wd))
delete(w.watches, name)
// inotify_rm_watch will return EINVAL if the file has been deleted; // inotify_rm_watch will return EINVAL if the file has been deleted;
// the inotify will already have been removed. // the inotify will already have been removed.
// watches and pathes are deleted in ignoreLinux() implicitly and asynchronously // watches and pathes are deleted in ignoreLinux() implicitly and asynchronously
@ -152,13 +159,6 @@ func (w *Watcher) Remove(name string) error {
return errno return errno
} }
// wait until ignoreLinux() deleting maps
exists := true
for exists {
w.cv.Wait()
_, exists = w.watches[name]
}
return nil return nil
} }
@ -245,13 +245,31 @@ func (w *Watcher) readEvents() {
mask := uint32(raw.Mask) mask := uint32(raw.Mask)
nameLen := uint32(raw.Len) nameLen := uint32(raw.Len)
if mask&unix.IN_Q_OVERFLOW != 0 {
select {
case w.Errors <- ErrEventOverflow:
case <-w.done:
return
}
}
// If the event happened to the watched directory or the watched file, the kernel // If the event happened to the watched directory or the watched file, the kernel
// doesn't append the filename to the event, but we would like to always fill the // doesn't append the filename to the event, but we would like to always fill the
// the "Name" field with a valid filename. We retrieve the path of the watch from // the "Name" field with a valid filename. We retrieve the path of the watch from
// the "paths" map. // the "paths" map.
w.mu.Lock() w.mu.Lock()
name := w.paths[int(raw.Wd)] name, ok := w.paths[int(raw.Wd)]
// IN_DELETE_SELF occurs when the file/directory being watched is removed.
// This is a sign to clean up the maps, otherwise we are no longer in sync
// with the inotify kernel state which has already deleted the watch
// automatically.
if ok && mask&unix.IN_DELETE_SELF == unix.IN_DELETE_SELF {
delete(w.paths, int(raw.Wd))
delete(w.watches, name)
}
w.mu.Unlock() w.mu.Unlock()
if nameLen > 0 { if nameLen > 0 {
// Point "bytes" at the first byte of the filename // Point "bytes" at the first byte of the filename
bytes := (*[unix.PathMax]byte)(unsafe.Pointer(&buf[offset+unix.SizeofInotifyEvent])) bytes := (*[unix.PathMax]byte)(unsafe.Pointer(&buf[offset+unix.SizeofInotifyEvent]))
@ -262,7 +280,7 @@ func (w *Watcher) readEvents() {
event := newEvent(name, mask) event := newEvent(name, mask)
// Send the events that are not ignored on the events channel // Send the events that are not ignored on the events channel
if !event.ignoreLinux(w, raw.Wd, mask) { if !event.ignoreLinux(mask) {
select { select {
case w.Events <- event: case w.Events <- event:
case <-w.done: case <-w.done:
@ -279,15 +297,9 @@ func (w *Watcher) readEvents() {
// Certain types of events can be "ignored" and not sent over the Events // Certain types of events can be "ignored" and not sent over the Events
// channel. Such as events marked ignore by the kernel, or MODIFY events // channel. Such as events marked ignore by the kernel, or MODIFY events
// against files that do not exist. // against files that do not exist.
func (e *Event) ignoreLinux(w *Watcher, wd int32, mask uint32) bool { func (e *Event) ignoreLinux(mask uint32) bool {
// Ignore anything the inotify API says to ignore // Ignore anything the inotify API says to ignore
if mask&unix.IN_IGNORED == unix.IN_IGNORED { if mask&unix.IN_IGNORED == unix.IN_IGNORED {
w.mu.Lock()
defer w.mu.Unlock()
name := w.paths[int(wd)]
delete(w.paths, int(wd))
delete(w.watches, name)
w.cv.Broadcast()
return true return true
} }

View file

@ -22,7 +22,7 @@ import (
type Watcher struct { type Watcher struct {
Events chan Event Events chan Event
Errors chan error Errors chan error
done chan bool // Channel for sending a "quit message" to the reader goroutine done chan struct{} // Channel for sending a "quit message" to the reader goroutine
kq int // File descriptor (as returned by the kqueue() syscall). kq int // File descriptor (as returned by the kqueue() syscall).
@ -56,7 +56,7 @@ func NewWatcher() (*Watcher, error) {
externalWatches: make(map[string]bool), externalWatches: make(map[string]bool),
Events: make(chan Event), Events: make(chan Event),
Errors: make(chan error), Errors: make(chan error),
done: make(chan bool), done: make(chan struct{}),
} }
go w.readEvents() go w.readEvents()
@ -71,10 +71,8 @@ func (w *Watcher) Close() error {
return nil return nil
} }
w.isClosed = true w.isClosed = true
w.mu.Unlock()
// copy paths to remove while locked // copy paths to remove while locked
w.mu.Lock()
var pathsToRemove = make([]string, 0, len(w.watches)) var pathsToRemove = make([]string, 0, len(w.watches))
for name := range w.watches { for name := range w.watches {
pathsToRemove = append(pathsToRemove, name) pathsToRemove = append(pathsToRemove, name)
@ -82,15 +80,12 @@ func (w *Watcher) Close() error {
w.mu.Unlock() w.mu.Unlock()
// unlock before calling Remove, which also locks // unlock before calling Remove, which also locks
var err error
for _, name := range pathsToRemove { for _, name := range pathsToRemove {
if e := w.Remove(name); e != nil && err == nil { w.Remove(name)
err = e
}
} }
// Send "quit" message to the reader goroutine: // send a "quit" message to the reader goroutine
w.done <- true close(w.done)
return nil return nil
} }
@ -266,17 +261,12 @@ func (w *Watcher) addWatch(name string, flags uint32) (string, error) {
func (w *Watcher) readEvents() { func (w *Watcher) readEvents() {
eventBuffer := make([]unix.Kevent_t, 10) eventBuffer := make([]unix.Kevent_t, 10)
loop:
for { for {
// See if there is a message on the "done" channel // See if there is a message on the "done" channel
select { select {
case <-w.done: case <-w.done:
err := unix.Close(w.kq) break loop
if err != nil {
w.Errors <- err
}
close(w.Events)
close(w.Errors)
return
default: default:
} }
@ -284,7 +274,11 @@ func (w *Watcher) readEvents() {
kevents, err := read(w.kq, eventBuffer, &keventWaitTime) kevents, err := read(w.kq, eventBuffer, &keventWaitTime)
// EINTR is okay, the syscall was interrupted before timeout expired. // EINTR is okay, the syscall was interrupted before timeout expired.
if err != nil && err != unix.EINTR { if err != nil && err != unix.EINTR {
w.Errors <- err select {
case w.Errors <- err:
case <-w.done:
break loop
}
continue continue
} }
@ -319,8 +313,12 @@ func (w *Watcher) readEvents() {
if path.isDir && event.Op&Write == Write && !(event.Op&Remove == Remove) { if path.isDir && event.Op&Write == Write && !(event.Op&Remove == Remove) {
w.sendDirectoryChangeEvents(event.Name) w.sendDirectoryChangeEvents(event.Name)
} else { } else {
// Send the event on the Events channel // Send the event on the Events channel.
w.Events <- event select {
case w.Events <- event:
case <-w.done:
break loop
}
} }
if event.Op&Remove == Remove { if event.Op&Remove == Remove {
@ -352,6 +350,18 @@ func (w *Watcher) readEvents() {
kevents = kevents[1:] kevents = kevents[1:]
} }
} }
// cleanup
err := unix.Close(w.kq)
if err != nil {
// only way the previous loop breaks is if w.done was closed so we need to async send to w.Errors.
select {
case w.Errors <- err:
default:
}
}
close(w.Events)
close(w.Errors)
} }
// newEvent returns an platform-independent Event based on kqueue Fflags. // newEvent returns an platform-independent Event based on kqueue Fflags.
@ -407,7 +417,11 @@ func (w *Watcher) sendDirectoryChangeEvents(dirPath string) {
// Get all files // Get all files
files, err := ioutil.ReadDir(dirPath) files, err := ioutil.ReadDir(dirPath)
if err != nil { if err != nil {
w.Errors <- err select {
case w.Errors <- err:
case <-w.done:
return
}
} }
// Search for new files // Search for new files
@ -428,7 +442,11 @@ func (w *Watcher) sendFileCreatedEventIfNew(filePath string, fileInfo os.FileInf
w.mu.Unlock() w.mu.Unlock()
if !doesExist { if !doesExist {
// Send create event // Send create event
w.Events <- newCreateEvent(filePath) select {
case w.Events <- newCreateEvent(filePath):
case <-w.done:
return
}
} }
// like watchDirectoryFiles (but without doing another ReadDir) // like watchDirectoryFiles (but without doing another ReadDir)

2
vendor/modules.txt vendored
View file

@ -433,7 +433,7 @@ google.golang.org/grpc/binarylog/grpc_binarylog_v1
google.golang.org/grpc/internal/syscall google.golang.org/grpc/internal/syscall
# gopkg.in/alecthomas/kingpin.v2 v2.2.6 # gopkg.in/alecthomas/kingpin.v2 v2.2.6
gopkg.in/alecthomas/kingpin.v2 gopkg.in/alecthomas/kingpin.v2
# gopkg.in/fsnotify/fsnotify.v1 v1.3.1 # gopkg.in/fsnotify/fsnotify.v1 v1.4.7
gopkg.in/fsnotify/fsnotify.v1 gopkg.in/fsnotify/fsnotify.v1
# gopkg.in/inf.v0 v0.9.1 # gopkg.in/inf.v0 v0.9.1
gopkg.in/inf.v0 gopkg.in/inf.v0