From 301fa9eb2d6e835fdadbbf5ec2a4234ddc5211cd Mon Sep 17 00:00:00 2001 From: ucwong Date: Wed, 20 Sep 2023 20:18:37 +0800 Subject: [PATCH] suppress fsnotify error if keydir not exists --- accounts/keystore/watch.go | 45 +- go.mod | 2 +- go.sum | 3 +- .../fsnotify/fsnotify/.editorconfig | 12 + .../fsnotify/fsnotify/.gitattributes | 1 + .../github.com/fsnotify/fsnotify/.gitignore | 6 + vendor/github.com/fsnotify/fsnotify/.mailmap | 2 + .../github.com/fsnotify/fsnotify/CHANGELOG.md | 470 +++++++++++ .../fsnotify/fsnotify/CONTRIBUTING.md | 26 + vendor/github.com/fsnotify/fsnotify/LICENSE | 25 + vendor/github.com/fsnotify/fsnotify/README.md | 161 ++++ .../fsnotify/fsnotify/backend_fen.go | 162 ++++ .../fsnotify/fsnotify/backend_inotify.go | 459 +++++++++++ .../fsnotify/fsnotify/backend_kqueue.go | 707 +++++++++++++++++ .../fsnotify/fsnotify/backend_other.go | 66 ++ .../fsnotify/fsnotify/backend_windows.go | 746 ++++++++++++++++++ .../github.com/fsnotify/fsnotify/fsnotify.go | 81 ++ vendor/github.com/fsnotify/fsnotify/mkdoc.zsh | 208 +++++ .../fsnotify/fsnotify/system_bsd.go | 8 + .../fsnotify/fsnotify/system_darwin.go | 9 + vendor/github.com/rjeczalik/notify/.gitignore | 92 --- .../github.com/rjeczalik/notify/.travis.yml | 32 - vendor/github.com/rjeczalik/notify/AUTHORS | 10 - vendor/github.com/rjeczalik/notify/LICENSE | 21 - vendor/github.com/rjeczalik/notify/README.md | 23 - .../github.com/rjeczalik/notify/appveyor.yml | 27 - vendor/github.com/rjeczalik/notify/debug.go | 53 -- .../rjeczalik/notify/debug_debug.go | 10 - .../rjeczalik/notify/debug_nodebug.go | 10 - vendor/github.com/rjeczalik/notify/doc.go | 43 - vendor/github.com/rjeczalik/notify/event.go | 143 ---- .../github.com/rjeczalik/notify/event_fen.go | 58 -- .../rjeczalik/notify/event_fsevents.go | 72 -- .../rjeczalik/notify/event_inotify.go | 76 -- .../rjeczalik/notify/event_kqueue.go | 60 -- .../rjeczalik/notify/event_readdcw.go | 119 --- .../github.com/rjeczalik/notify/event_stub.go | 31 - .../rjeczalik/notify/event_trigger.go | 23 - vendor/github.com/rjeczalik/notify/node.go | 275 ------- vendor/github.com/rjeczalik/notify/notify.go | 74 -- vendor/github.com/rjeczalik/notify/tree.go | 22 - .../rjeczalik/notify/tree_nonrecursive.go | 309 -------- .../rjeczalik/notify/tree_recursive.go | 354 --------- vendor/github.com/rjeczalik/notify/util.go | 152 ---- vendor/github.com/rjeczalik/notify/watcher.go | 85 -- .../rjeczalik/notify/watcher_fen.go | 162 ---- .../rjeczalik/notify/watcher_fen_cgo.go | 142 ---- .../rjeczalik/notify/watcher_fsevents.go | 311 -------- .../rjeczalik/notify/watcher_fsevents_cgo.go | 163 ---- .../rjeczalik/notify/watcher_inotify.go | 400 ---------- .../rjeczalik/notify/watcher_kqueue.go | 202 ----- .../notify/watcher_notimplemented.go | 15 - .../rjeczalik/notify/watcher_readdcw.go | 612 -------------- .../rjeczalik/notify/watcher_stub.go | 13 - .../rjeczalik/notify/watcher_trigger.go | 454 ----------- .../github.com/rjeczalik/notify/watchpoint.go | 103 --- .../rjeczalik/notify/watchpoint_other.go | 24 - .../rjeczalik/notify/watchpoint_readdcw.go | 39 - vendor/modules.txt | 6 +- 59 files changed, 3189 insertions(+), 4830 deletions(-) create mode 100644 vendor/github.com/fsnotify/fsnotify/.editorconfig create mode 100644 vendor/github.com/fsnotify/fsnotify/.gitattributes create mode 100644 vendor/github.com/fsnotify/fsnotify/.gitignore create mode 100644 vendor/github.com/fsnotify/fsnotify/.mailmap create mode 100644 vendor/github.com/fsnotify/fsnotify/CHANGELOG.md create mode 100644 vendor/github.com/fsnotify/fsnotify/CONTRIBUTING.md create mode 100644 vendor/github.com/fsnotify/fsnotify/LICENSE create mode 100644 vendor/github.com/fsnotify/fsnotify/README.md create mode 100644 vendor/github.com/fsnotify/fsnotify/backend_fen.go create mode 100644 vendor/github.com/fsnotify/fsnotify/backend_inotify.go create mode 100644 vendor/github.com/fsnotify/fsnotify/backend_kqueue.go create mode 100644 vendor/github.com/fsnotify/fsnotify/backend_other.go create mode 100644 vendor/github.com/fsnotify/fsnotify/backend_windows.go create mode 100644 vendor/github.com/fsnotify/fsnotify/fsnotify.go create mode 100644 vendor/github.com/fsnotify/fsnotify/mkdoc.zsh create mode 100644 vendor/github.com/fsnotify/fsnotify/system_bsd.go create mode 100644 vendor/github.com/fsnotify/fsnotify/system_darwin.go delete mode 100644 vendor/github.com/rjeczalik/notify/.gitignore delete mode 100644 vendor/github.com/rjeczalik/notify/.travis.yml delete mode 100644 vendor/github.com/rjeczalik/notify/AUTHORS delete mode 100644 vendor/github.com/rjeczalik/notify/LICENSE delete mode 100644 vendor/github.com/rjeczalik/notify/README.md delete mode 100644 vendor/github.com/rjeczalik/notify/appveyor.yml delete mode 100644 vendor/github.com/rjeczalik/notify/debug.go delete mode 100644 vendor/github.com/rjeczalik/notify/debug_debug.go delete mode 100644 vendor/github.com/rjeczalik/notify/debug_nodebug.go delete mode 100644 vendor/github.com/rjeczalik/notify/doc.go delete mode 100644 vendor/github.com/rjeczalik/notify/event.go delete mode 100644 vendor/github.com/rjeczalik/notify/event_fen.go delete mode 100644 vendor/github.com/rjeczalik/notify/event_fsevents.go delete mode 100644 vendor/github.com/rjeczalik/notify/event_inotify.go delete mode 100644 vendor/github.com/rjeczalik/notify/event_kqueue.go delete mode 100644 vendor/github.com/rjeczalik/notify/event_readdcw.go delete mode 100644 vendor/github.com/rjeczalik/notify/event_stub.go delete mode 100644 vendor/github.com/rjeczalik/notify/event_trigger.go delete mode 100644 vendor/github.com/rjeczalik/notify/node.go delete mode 100644 vendor/github.com/rjeczalik/notify/notify.go delete mode 100644 vendor/github.com/rjeczalik/notify/tree.go delete mode 100644 vendor/github.com/rjeczalik/notify/tree_nonrecursive.go delete mode 100644 vendor/github.com/rjeczalik/notify/tree_recursive.go delete mode 100644 vendor/github.com/rjeczalik/notify/util.go delete mode 100644 vendor/github.com/rjeczalik/notify/watcher.go delete mode 100644 vendor/github.com/rjeczalik/notify/watcher_fen.go delete mode 100644 vendor/github.com/rjeczalik/notify/watcher_fen_cgo.go delete mode 100644 vendor/github.com/rjeczalik/notify/watcher_fsevents.go delete mode 100644 vendor/github.com/rjeczalik/notify/watcher_fsevents_cgo.go delete mode 100644 vendor/github.com/rjeczalik/notify/watcher_inotify.go delete mode 100644 vendor/github.com/rjeczalik/notify/watcher_kqueue.go delete mode 100644 vendor/github.com/rjeczalik/notify/watcher_notimplemented.go delete mode 100644 vendor/github.com/rjeczalik/notify/watcher_readdcw.go delete mode 100644 vendor/github.com/rjeczalik/notify/watcher_stub.go delete mode 100644 vendor/github.com/rjeczalik/notify/watcher_trigger.go delete mode 100644 vendor/github.com/rjeczalik/notify/watchpoint.go delete mode 100644 vendor/github.com/rjeczalik/notify/watchpoint_other.go delete mode 100644 vendor/github.com/rjeczalik/notify/watchpoint_readdcw.go diff --git a/accounts/keystore/watch.go b/accounts/keystore/watch.go index 0c3127d494..372bd6d6c3 100644 --- a/accounts/keystore/watch.go +++ b/accounts/keystore/watch.go @@ -20,28 +20,31 @@ package keystore import ( + "os" "time" "github.com/CortexFoundation/CortexTheseus/log" - "github.com/rjeczalik/notify" + "github.com/fsnotify/fsnotify" ) type watcher struct { ac *accountCache - starting bool - running bool - ev chan notify.EventInfo + running bool // set to true when runloop begins + runEnded bool // set to true when runloop ends + starting bool // set to true prior to runloop starting quit chan struct{} } func newWatcher(ac *accountCache) *watcher { return &watcher{ ac: ac, - ev: make(chan notify.EventInfo, 10), quit: make(chan struct{}), } } +// enabled returns false on systems not supported. +func (*watcher) enabled() bool { return true } + // starts the watcher loop in the background. // Start a watcher in the background if that's not already in progress. // The caller must hold w.ac.mu. @@ -62,16 +65,26 @@ func (w *watcher) loop() { w.ac.mu.Lock() w.running = false w.starting = false + w.runEnded = true w.ac.mu.Unlock() }() logger := log.New("path", w.ac.keydir) - if err := notify.Watch(w.ac.keydir, w.ev, notify.All); err != nil { - logger.Trace("Failed to watch keystore folder", "err", err) + // Create new watcher. + watcher, err := fsnotify.NewWatcher() + if err != nil { + log.Error("Failed to start filesystem watcher", "err", err) + return + } + defer watcher.Close() + if err := watcher.Add(w.ac.keydir); err != nil { + if !os.IsNotExist(err) { + logger.Warn("Failed to watch keystore folder", "err", err) + } return } - defer notify.Stop(w.ev) - logger.Trace("Started watching keystore folder") + + logger.Trace("Started watching keystore folder", "folder", w.ac.keydir) defer logger.Trace("Stopped watching keystore folder") w.ac.mu.Lock() @@ -95,12 +108,24 @@ func (w *watcher) loop() { select { case <-w.quit: return - case <-w.ev: + case _, ok := <-watcher.Events: + if !ok { + return + } // Trigger the scan (with delay), if not already triggered if !rescanTriggered { debounce.Reset(debounceDuration) rescanTriggered = true } + // The fsnotify library does provide more granular event-info, it + // would be possible to refresh individual affected files instead + // of scheduling a full rescan. For most cases though, the + // full rescan is quick and obviously simplest. + case err, ok := <-watcher.Errors: + if !ok { + return + } + log.Info("Filsystem watcher error", "err", err) case <-debounce.C: w.ac.scanAccounts() rescanTriggered = false diff --git a/go.mod b/go.mod index 3a9bd5a5c9..0a547b112f 100644 --- a/go.mod +++ b/go.mod @@ -28,6 +28,7 @@ require ( github.com/fjl/gencodec v0.0.0-20230517082657-f9840df7b83e github.com/fjl/memsize v0.0.1 github.com/fogleman/ease v0.0.0-20170301025033-8da417bf1776 + github.com/fsnotify/fsnotify v1.6.0 github.com/gballet/go-libpcsclite v0.0.0-20191108122812-4678299bea08 github.com/gballet/go-verkle v0.0.0-20230620072649-dd771ce9a3b3 github.com/go-stack/stack v1.8.1 @@ -53,7 +54,6 @@ require ( github.com/naoina/toml v0.1.2-0.20170918210437-9fafd6967416 github.com/olekukonko/tablewriter v0.0.5 github.com/peterh/liner v1.2.2 - github.com/rjeczalik/notify v0.9.3 github.com/rs/cors v1.10.0 github.com/shirou/gopsutil v3.21.11+incompatible github.com/status-im/keycard-go v0.3.0 diff --git a/go.sum b/go.sum index 9b15102189..2503e95e16 100644 --- a/go.sum +++ b/go.sum @@ -1101,8 +1101,6 @@ github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJ github.com/rivo/uniseg v0.4.4 h1:8TfxU8dW6PdqD27gjM8MVNuicgxIjxpm4K7x4jp8sis= github.com/rivo/uniseg v0.4.4/go.mod h1:FN3SvrM+Zdj16jyLfmOkMNblXMcoc8DfTHruCPUcx88= github.com/rjeczalik/notify v0.9.2/go.mod h1:aErll2f0sUX9PXZnVNyeiObbmTlk5jnMoCa4QEjJeqM= -github.com/rjeczalik/notify v0.9.3 h1:6rJAzHTGKXGj76sbRgDiDcYj/HniypXmSJo1SWakZeY= -github.com/rjeczalik/notify v0.9.3/go.mod h1:gF3zSOrafR9DQEWSE8TjfI9NkooDxbyT4UgRGKZA0lc= github.com/robertkrimen/godocdown v0.0.0-20130622164427-0bfa04905481/go.mod h1:C9WhFzY47SzYBIvzFqSvHIR6ROgDo4TtdTuRaOMjF/s= github.com/robertkrimen/otto v0.0.0-20191219234010-c382bd3c16ff/go.mod h1:xvqspoSXJTIpemEonrMDFq6XzwHYYgToXWj5eRX1OtY= github.com/rogpeppe/fastuuid v0.0.0-20150106093220-6724a57986af/go.mod h1:XWv6SoW27p1b0cqNHllgS5HIMJraePCO15w5zCzIWYg= @@ -1567,6 +1565,7 @@ golang.org/x/sys v0.0.0-20220412211240-33da011f77ad/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220908164124-27713097b956/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20221010170243-090e33056c14/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.2.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= diff --git a/vendor/github.com/fsnotify/fsnotify/.editorconfig b/vendor/github.com/fsnotify/fsnotify/.editorconfig new file mode 100644 index 0000000000..fad895851e --- /dev/null +++ b/vendor/github.com/fsnotify/fsnotify/.editorconfig @@ -0,0 +1,12 @@ +root = true + +[*.go] +indent_style = tab +indent_size = 4 +insert_final_newline = true + +[*.{yml,yaml}] +indent_style = space +indent_size = 2 +insert_final_newline = true +trim_trailing_whitespace = true diff --git a/vendor/github.com/fsnotify/fsnotify/.gitattributes b/vendor/github.com/fsnotify/fsnotify/.gitattributes new file mode 100644 index 0000000000..32f1001be0 --- /dev/null +++ b/vendor/github.com/fsnotify/fsnotify/.gitattributes @@ -0,0 +1 @@ +go.sum linguist-generated diff --git a/vendor/github.com/fsnotify/fsnotify/.gitignore b/vendor/github.com/fsnotify/fsnotify/.gitignore new file mode 100644 index 0000000000..1d89d85ce4 --- /dev/null +++ b/vendor/github.com/fsnotify/fsnotify/.gitignore @@ -0,0 +1,6 @@ +# go test -c output +*.test +*.test.exe + +# Output of go build ./cmd/fsnotify +/fsnotify diff --git a/vendor/github.com/fsnotify/fsnotify/.mailmap b/vendor/github.com/fsnotify/fsnotify/.mailmap new file mode 100644 index 0000000000..a04f2907fe --- /dev/null +++ b/vendor/github.com/fsnotify/fsnotify/.mailmap @@ -0,0 +1,2 @@ +Chris Howey +Nathan Youngman <4566+nathany@users.noreply.github.com> diff --git a/vendor/github.com/fsnotify/fsnotify/CHANGELOG.md b/vendor/github.com/fsnotify/fsnotify/CHANGELOG.md new file mode 100644 index 0000000000..77f9593bd5 --- /dev/null +++ b/vendor/github.com/fsnotify/fsnotify/CHANGELOG.md @@ -0,0 +1,470 @@ +# Changelog + +All notable changes to this project will be documented in this file. + +The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), +and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). + +## [Unreleased] + +Nothing yet. + +## [1.6.0] - 2022-10-13 + +This version of fsnotify needs Go 1.16 (this was already the case since 1.5.1, +but not documented). It also increases the minimum Linux version to 2.6.32. + +### Additions + +- all: add `Event.Has()` and `Op.Has()` ([#477]) + + This makes checking events a lot easier; for example: + + if event.Op&Write == Write && !(event.Op&Remove == Remove) { + } + + Becomes: + + if event.Has(Write) && !event.Has(Remove) { + } + +- all: add cmd/fsnotify ([#463]) + + A command-line utility for testing and some examples. + +### Changes and fixes + +- inotify: don't ignore events for files that don't exist ([#260], [#470]) + + Previously the inotify watcher would call `os.Lstat()` to check if a file + still exists before emitting events. + + This was inconsistent with other platforms and resulted in inconsistent event + reporting (e.g. when a file is quickly removed and re-created), and generally + a source of confusion. It was added in 2013 to fix a memory leak that no + longer exists. + +- all: return `ErrNonExistentWatch` when `Remove()` is called on a path that's + not watched ([#460]) + +- inotify: replace epoll() with non-blocking inotify ([#434]) + + Non-blocking inotify was not generally available at the time this library was + written in 2014, but now it is. As a result, the minimum Linux version is + bumped from 2.6.27 to 2.6.32. This hugely simplifies the code and is faster. + +- kqueue: don't check for events every 100ms ([#480]) + + The watcher would wake up every 100ms, even when there was nothing to do. Now + it waits until there is something to do. + +- macos: retry opening files on EINTR ([#475]) + +- kqueue: skip unreadable files ([#479]) + + kqueue requires a file descriptor for every file in a directory; this would + fail if a file was unreadable by the current user. Now these files are simply + skipped. + +- windows: fix renaming a watched directory if the parent is also watched ([#370]) + +- windows: increase buffer size from 4K to 64K ([#485]) + +- windows: close file handle on Remove() ([#288]) + +- kqueue: put pathname in the error if watching a file fails ([#471]) + +- inotify, windows: calling Close() more than once could race ([#465]) + +- kqueue: improve Close() performance ([#233]) + +- all: various documentation additions and clarifications. + +[#233]: https://github.com/fsnotify/fsnotify/pull/233 +[#260]: https://github.com/fsnotify/fsnotify/pull/260 +[#288]: https://github.com/fsnotify/fsnotify/pull/288 +[#370]: https://github.com/fsnotify/fsnotify/pull/370 +[#434]: https://github.com/fsnotify/fsnotify/pull/434 +[#460]: https://github.com/fsnotify/fsnotify/pull/460 +[#463]: https://github.com/fsnotify/fsnotify/pull/463 +[#465]: https://github.com/fsnotify/fsnotify/pull/465 +[#470]: https://github.com/fsnotify/fsnotify/pull/470 +[#471]: https://github.com/fsnotify/fsnotify/pull/471 +[#475]: https://github.com/fsnotify/fsnotify/pull/475 +[#477]: https://github.com/fsnotify/fsnotify/pull/477 +[#479]: https://github.com/fsnotify/fsnotify/pull/479 +[#480]: https://github.com/fsnotify/fsnotify/pull/480 +[#485]: https://github.com/fsnotify/fsnotify/pull/485 + +## [1.5.4] - 2022-04-25 + +* Windows: add missing defer to `Watcher.WatchList` [#447](https://github.com/fsnotify/fsnotify/pull/447) +* go.mod: use latest x/sys [#444](https://github.com/fsnotify/fsnotify/pull/444) +* Fix compilation for OpenBSD [#443](https://github.com/fsnotify/fsnotify/pull/443) + +## [1.5.3] - 2022-04-22 + +* This version is retracted. An incorrect branch is published accidentally [#445](https://github.com/fsnotify/fsnotify/issues/445) + +## [1.5.2] - 2022-04-21 + +* Add a feature to return the directories and files that are being monitored [#374](https://github.com/fsnotify/fsnotify/pull/374) +* Fix potential crash on windows if `raw.FileNameLength` exceeds `syscall.MAX_PATH` [#361](https://github.com/fsnotify/fsnotify/pull/361) +* Allow build on unsupported GOOS [#424](https://github.com/fsnotify/fsnotify/pull/424) +* Don't set `poller.fd` twice in `newFdPoller` [#406](https://github.com/fsnotify/fsnotify/pull/406) +* fix go vet warnings: call to `(*T).Fatalf` from a non-test goroutine [#416](https://github.com/fsnotify/fsnotify/pull/416) + +## [1.5.1] - 2021-08-24 + +* Revert Add AddRaw to not follow symlinks [#394](https://github.com/fsnotify/fsnotify/pull/394) + +## [1.5.0] - 2021-08-20 + +* Go: Increase minimum required version to Go 1.12 [#381](https://github.com/fsnotify/fsnotify/pull/381) +* Feature: Add AddRaw method which does not follow symlinks when adding a watch [#289](https://github.com/fsnotify/fsnotify/pull/298) +* Windows: Follow symlinks by default like on all other systems [#289](https://github.com/fsnotify/fsnotify/pull/289) +* CI: Use GitHub Actions for CI and cover go 1.12-1.17 + [#378](https://github.com/fsnotify/fsnotify/pull/378) + [#381](https://github.com/fsnotify/fsnotify/pull/381) + [#385](https://github.com/fsnotify/fsnotify/pull/385) +* Go 1.14+: Fix unsafe pointer conversion [#325](https://github.com/fsnotify/fsnotify/pull/325) + +## [1.4.9] - 2020-03-11 + +* Move example usage to the readme #329. This may resolve #328. + +## [1.4.8] - 2020-03-10 + +* CI: test more go versions (@nathany 1d13583d846ea9d66dcabbfefbfb9d8e6fb05216) +* Tests: Queued inotify events could have been read by the test before max_queued_events was hit (@matthias-stone #265) +* Tests: t.Fatalf -> t.Errorf in go routines (@gdey #266) +* CI: Less verbosity (@nathany #267) +* Tests: Darwin: Exchangedata is deprecated on 10.13 (@nathany #267) +* Tests: Check if channels are closed in the example (@alexeykazakov #244) +* CI: Only run golint on latest version of go and fix issues (@cpuguy83 #284) +* CI: Add windows to travis matrix (@cpuguy83 #284) +* Docs: Remover appveyor badge (@nathany 11844c0959f6fff69ba325d097fce35bd85a8e93) +* Linux: create epoll and pipe fds with close-on-exec (@JohannesEbke #219) +* Linux: open files with close-on-exec (@linxiulei #273) +* Docs: Plan to support fanotify (@nathany ab058b44498e8b7566a799372a39d150d9ea0119 ) +* Project: Add go.mod (@nathany #309) +* Project: Revise editor config (@nathany #309) +* Project: Update copyright for 2019 (@nathany #309) +* CI: Drop go1.8 from CI matrix (@nathany #309) +* Docs: Updating the FAQ section for supportability with NFS & FUSE filesystems (@Pratik32 4bf2d1fec78374803a39307bfb8d340688f4f28e ) + +## [1.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 + +## [1.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) + +## [1.4.1] - 2016-10-04 + +* Fix flaky inotify stress test on Linux [#177](https://github.com/fsnotify/fsnotify/pull/177) (thanks @pattyshack) + +## [1.4.0] - 2016-10-01 + +* add a String() method to Event.Op [#165](https://github.com/fsnotify/fsnotify/pull/165) (thanks @oozie) + +## [1.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) + +## [1.3.0] - 2016-04-19 + +* Support linux/arm64 by [patching](https://go-review.googlesource.com/#/c/21971/) x/sys/unix and switching to to it from syscall (thanks @suihkulokki) [#135](https://github.com/fsnotify/fsnotify/pull/135) + +## [1.2.10] - 2016-03-02 + +* Fix golint errors in windows.go [#121](https://github.com/fsnotify/fsnotify/pull/121) (thanks @tiffanyfj) + +## [1.2.9] - 2016-01-13 + +kqueue: Fix logic for CREATE after REMOVE [#111](https://github.com/fsnotify/fsnotify/pull/111) (thanks @bep) + +## [1.2.8] - 2015-12-17 + +* kqueue: fix race condition in Close [#105](https://github.com/fsnotify/fsnotify/pull/105) (thanks @djui for reporting the issue and @ppknap for writing a failing test) +* inotify: fix race in test +* enable race detection for continuous integration (Linux, Mac, Windows) + +## [1.2.5] - 2015-10-17 + +* inotify: use epoll_create1 for arm64 support (requires Linux 2.6.27 or later) [#100](https://github.com/fsnotify/fsnotify/pull/100) (thanks @suihkulokki) +* inotify: fix path leaks [#73](https://github.com/fsnotify/fsnotify/pull/73) (thanks @chamaken) +* kqueue: watch for rename events on subdirectories [#83](https://github.com/fsnotify/fsnotify/pull/83) (thanks @guotie) +* kqueue: avoid infinite loops from symlinks cycles [#101](https://github.com/fsnotify/fsnotify/pull/101) (thanks @illicitonion) + +## [1.2.1] - 2015-10-14 + +* kqueue: don't watch named pipes [#98](https://github.com/fsnotify/fsnotify/pull/98) (thanks @evanphx) + +## [1.2.0] - 2015-02-08 + +* inotify: use epoll to wake up readEvents [#66](https://github.com/fsnotify/fsnotify/pull/66) (thanks @PieterD) +* inotify: closing watcher should now always shut down goroutine [#63](https://github.com/fsnotify/fsnotify/pull/63) (thanks @PieterD) +* kqueue: close kqueue after removing watches, fixes [#59](https://github.com/fsnotify/fsnotify/issues/59) + +## [1.1.1] - 2015-02-05 + +* inotify: Retry read on EINTR [#61](https://github.com/fsnotify/fsnotify/issues/61) (thanks @PieterD) + +## [1.1.0] - 2014-12-12 + +* kqueue: rework internals [#43](https://github.com/fsnotify/fsnotify/pull/43) + * add low-level functions + * only need to store flags on directories + * less mutexes [#13](https://github.com/fsnotify/fsnotify/issues/13) + * done can be an unbuffered channel + * remove calls to os.NewSyscallError +* More efficient string concatenation for Event.String() [#52](https://github.com/fsnotify/fsnotify/pull/52) (thanks @mdlayher) +* kqueue: fix regression in rework causing subdirectories to be watched [#48](https://github.com/fsnotify/fsnotify/issues/48) +* kqueue: cleanup internal watch before sending remove event [#51](https://github.com/fsnotify/fsnotify/issues/51) + +## [1.0.4] - 2014-09-07 + +* kqueue: add dragonfly to the build tags. +* Rename source code files, rearrange code so exported APIs are at the top. +* Add done channel to example code. [#37](https://github.com/fsnotify/fsnotify/pull/37) (thanks @chenyukang) + +## [1.0.3] - 2014-08-19 + +* [Fix] Windows MOVED_TO now translates to Create like on BSD and Linux. [#36](https://github.com/fsnotify/fsnotify/issues/36) + +## [1.0.2] - 2014-08-17 + +* [Fix] Missing create events on macOS. [#14](https://github.com/fsnotify/fsnotify/issues/14) (thanks @zhsso) +* [Fix] Make ./path and path equivalent. (thanks @zhsso) + +## [1.0.0] - 2014-08-15 + +* [API] Remove AddWatch on Windows, use Add. +* Improve documentation for exported identifiers. [#30](https://github.com/fsnotify/fsnotify/issues/30) +* Minor updates based on feedback from golint. + +## dev / 2014-07-09 + +* Moved to [github.com/fsnotify/fsnotify](https://github.com/fsnotify/fsnotify). +* Use os.NewSyscallError instead of returning errno (thanks @hariharan-uno) + +## dev / 2014-07-04 + +* kqueue: fix incorrect mutex used in Close() +* Update example to demonstrate usage of Op. + +## dev / 2014-06-28 + +* [API] Don't set the Write Op for attribute notifications [#4](https://github.com/fsnotify/fsnotify/issues/4) +* Fix for String() method on Event (thanks Alex Brainman) +* Don't build on Plan 9 or Solaris (thanks @4ad) + +## dev / 2014-06-21 + +* Events channel of type Event rather than *Event. +* [internal] use syscall constants directly for inotify and kqueue. +* [internal] kqueue: rename events to kevents and fileEvent to event. + +## dev / 2014-06-19 + +* Go 1.3+ required on Windows (uses syscall.ERROR_MORE_DATA internally). +* [internal] remove cookie from Event struct (unused). +* [internal] Event struct has the same definition across every OS. +* [internal] remove internal watch and removeWatch methods. + +## dev / 2014-06-12 + +* [API] Renamed Watch() to Add() and RemoveWatch() to Remove(). +* [API] Pluralized channel names: Events and Errors. +* [API] Renamed FileEvent struct to Event. +* [API] Op constants replace methods like IsCreate(). + +## dev / 2014-06-12 + +* Fix data race on kevent buffer (thanks @tilaks) [#98](https://github.com/howeyc/fsnotify/pull/98) + +## dev / 2014-05-23 + +* [API] Remove current implementation of WatchFlags. + * current implementation doesn't take advantage of OS for efficiency + * provides little benefit over filtering events as they are received, but has extra bookkeeping and mutexes + * no tests for the current implementation + * not fully implemented on Windows [#93](https://github.com/howeyc/fsnotify/issues/93#issuecomment-39285195) + +## [0.9.3] - 2014-12-31 + +* kqueue: cleanup internal watch before sending remove event [#51](https://github.com/fsnotify/fsnotify/issues/51) + +## [0.9.2] - 2014-08-17 + +* [Backport] Fix missing create events on macOS. [#14](https://github.com/fsnotify/fsnotify/issues/14) (thanks @zhsso) + +## [0.9.1] - 2014-06-12 + +* Fix data race on kevent buffer (thanks @tilaks) [#98](https://github.com/howeyc/fsnotify/pull/98) + +## [0.9.0] - 2014-01-17 + +* IsAttrib() for events that only concern a file's metadata [#79][] (thanks @abustany) +* [Fix] kqueue: fix deadlock [#77][] (thanks @cespare) +* [NOTICE] Development has moved to `code.google.com/p/go.exp/fsnotify` in preparation for inclusion in the Go standard library. + +## [0.8.12] - 2013-11-13 + +* [API] Remove FD_SET and friends from Linux adapter + +## [0.8.11] - 2013-11-02 + +* [Doc] Add Changelog [#72][] (thanks @nathany) +* [Doc] Spotlight and double modify events on macOS [#62][] (reported by @paulhammond) + +## [0.8.10] - 2013-10-19 + +* [Fix] kqueue: remove file watches when parent directory is removed [#71][] (reported by @mdwhatcott) +* [Fix] kqueue: race between Close and readEvents [#70][] (reported by @bernerdschaefer) +* [Doc] specify OS-specific limits in README (thanks @debrando) + +## [0.8.9] - 2013-09-08 + +* [Doc] Contributing (thanks @nathany) +* [Doc] update package path in example code [#63][] (thanks @paulhammond) +* [Doc] GoCI badge in README (Linux only) [#60][] +* [Doc] Cross-platform testing with Vagrant [#59][] (thanks @nathany) + +## [0.8.8] - 2013-06-17 + +* [Fix] Windows: handle `ERROR_MORE_DATA` on Windows [#49][] (thanks @jbowtie) + +## [0.8.7] - 2013-06-03 + +* [API] Make syscall flags internal +* [Fix] inotify: ignore event changes +* [Fix] race in symlink test [#45][] (reported by @srid) +* [Fix] tests on Windows +* lower case error messages + +## [0.8.6] - 2013-05-23 + +* kqueue: Use EVT_ONLY flag on Darwin +* [Doc] Update README with full example + +## [0.8.5] - 2013-05-09 + +* [Fix] inotify: allow monitoring of "broken" symlinks (thanks @tsg) + +## [0.8.4] - 2013-04-07 + +* [Fix] kqueue: watch all file events [#40][] (thanks @ChrisBuchholz) + +## [0.8.3] - 2013-03-13 + +* [Fix] inoitfy/kqueue memory leak [#36][] (reported by @nbkolchin) +* [Fix] kqueue: use fsnFlags for watching a directory [#33][] (reported by @nbkolchin) + +## [0.8.2] - 2013-02-07 + +* [Doc] add Authors +* [Fix] fix data races for map access [#29][] (thanks @fsouza) + +## [0.8.1] - 2013-01-09 + +* [Fix] Windows path separators +* [Doc] BSD License + +## [0.8.0] - 2012-11-09 + +* kqueue: directory watching improvements (thanks @vmirage) +* inotify: add `IN_MOVED_TO` [#25][] (requested by @cpisto) +* [Fix] kqueue: deleting watched directory [#24][] (reported by @jakerr) + +## [0.7.4] - 2012-10-09 + +* [Fix] inotify: fixes from https://codereview.appspot.com/5418045/ (ugorji) +* [Fix] kqueue: preserve watch flags when watching for delete [#21][] (reported by @robfig) +* [Fix] kqueue: watch the directory even if it isn't a new watch (thanks @robfig) +* [Fix] kqueue: modify after recreation of file + +## [0.7.3] - 2012-09-27 + +* [Fix] kqueue: watch with an existing folder inside the watched folder (thanks @vmirage) +* [Fix] kqueue: no longer get duplicate CREATE events + +## [0.7.2] - 2012-09-01 + +* kqueue: events for created directories + +## [0.7.1] - 2012-07-14 + +* [Fix] for renaming files + +## [0.7.0] - 2012-07-02 + +* [Feature] FSNotify flags +* [Fix] inotify: Added file name back to event path + +## [0.6.0] - 2012-06-06 + +* kqueue: watch files after directory created (thanks @tmc) + +## [0.5.1] - 2012-05-22 + +* [Fix] inotify: remove all watches before Close() + +## [0.5.0] - 2012-05-03 + +* [API] kqueue: return errors during watch instead of sending over channel +* kqueue: match symlink behavior on Linux +* inotify: add `DELETE_SELF` (requested by @taralx) +* [Fix] kqueue: handle EINTR (reported by @robfig) +* [Doc] Godoc example [#1][] (thanks @davecheney) + +## [0.4.0] - 2012-03-30 + +* Go 1 released: build with go tool +* [Feature] Windows support using winfsnotify +* Windows does not have attribute change notifications +* Roll attribute notifications into IsModify + +## [0.3.0] - 2012-02-19 + +* kqueue: add files when watch directory + +## [0.2.0] - 2011-12-30 + +* update to latest Go weekly code + +## [0.1.0] - 2011-10-19 + +* kqueue: add watch on file creation to match inotify +* kqueue: create file event +* inotify: ignore `IN_IGNORED` events +* event String() +* linux: common FileEvent functions +* initial commit + +[#79]: https://github.com/howeyc/fsnotify/pull/79 +[#77]: https://github.com/howeyc/fsnotify/pull/77 +[#72]: https://github.com/howeyc/fsnotify/issues/72 +[#71]: https://github.com/howeyc/fsnotify/issues/71 +[#70]: https://github.com/howeyc/fsnotify/issues/70 +[#63]: https://github.com/howeyc/fsnotify/issues/63 +[#62]: https://github.com/howeyc/fsnotify/issues/62 +[#60]: https://github.com/howeyc/fsnotify/issues/60 +[#59]: https://github.com/howeyc/fsnotify/issues/59 +[#49]: https://github.com/howeyc/fsnotify/issues/49 +[#45]: https://github.com/howeyc/fsnotify/issues/45 +[#40]: https://github.com/howeyc/fsnotify/issues/40 +[#36]: https://github.com/howeyc/fsnotify/issues/36 +[#33]: https://github.com/howeyc/fsnotify/issues/33 +[#29]: https://github.com/howeyc/fsnotify/issues/29 +[#25]: https://github.com/howeyc/fsnotify/issues/25 +[#24]: https://github.com/howeyc/fsnotify/issues/24 +[#21]: https://github.com/howeyc/fsnotify/issues/21 diff --git a/vendor/github.com/fsnotify/fsnotify/CONTRIBUTING.md b/vendor/github.com/fsnotify/fsnotify/CONTRIBUTING.md new file mode 100644 index 0000000000..ea379759d5 --- /dev/null +++ b/vendor/github.com/fsnotify/fsnotify/CONTRIBUTING.md @@ -0,0 +1,26 @@ +Thank you for your interest in contributing to fsnotify! We try to review and +merge PRs in a reasonable timeframe, but please be aware that: + +- To avoid "wasted" work, please discus changes on the issue tracker first. You + can just send PRs, but they may end up being rejected for one reason or the + other. + +- fsnotify is a cross-platform library, and changes must work reasonably well on + all supported platforms. + +- Changes will need to be compatible; old code should still compile, and the + runtime behaviour can't change in ways that are likely to lead to problems for + users. + +Testing +------- +Just `go test ./...` runs all the tests; the CI runs this on all supported +platforms. Testing different platforms locally can be done with something like +[goon] or [Vagrant], but this isn't super-easy to set up at the moment. + +Use the `-short` flag to make the "stress test" run faster. + + +[goon]: https://github.com/arp242/goon +[Vagrant]: https://www.vagrantup.com/ +[integration_test.go]: /integration_test.go diff --git a/vendor/github.com/fsnotify/fsnotify/LICENSE b/vendor/github.com/fsnotify/fsnotify/LICENSE new file mode 100644 index 0000000000..fb03ade750 --- /dev/null +++ b/vendor/github.com/fsnotify/fsnotify/LICENSE @@ -0,0 +1,25 @@ +Copyright © 2012 The Go Authors. All rights reserved. +Copyright © fsnotify Authors. All rights reserved. + +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + +* Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. +* Redistributions in binary form must reproduce the above copyright notice, this + list of conditions and the following disclaimer in the documentation and/or + other materials provided with the distribution. +* Neither the name of Google Inc. nor the names of its contributors may be used + to endorse or promote products derived from this software without specific + prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR +ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/vendor/github.com/fsnotify/fsnotify/README.md b/vendor/github.com/fsnotify/fsnotify/README.md new file mode 100644 index 0000000000..d4e6080feb --- /dev/null +++ b/vendor/github.com/fsnotify/fsnotify/README.md @@ -0,0 +1,161 @@ +fsnotify is a Go library to provide cross-platform filesystem notifications on +Windows, Linux, macOS, and BSD systems. + +Go 1.16 or newer is required; the full documentation is at +https://pkg.go.dev/github.com/fsnotify/fsnotify + +**It's best to read the documentation at pkg.go.dev, as it's pinned to the last +released version, whereas this README is for the last development version which +may include additions/changes.** + +--- + +Platform support: + +| Adapter | OS | Status | +| --------------------- | ---------------| -------------------------------------------------------------| +| inotify | Linux 2.6.32+ | Supported | +| kqueue | BSD, macOS | Supported | +| ReadDirectoryChangesW | Windows | Supported | +| FSEvents | macOS | [Planned](https://github.com/fsnotify/fsnotify/issues/11) | +| FEN | Solaris 11 | [In Progress](https://github.com/fsnotify/fsnotify/pull/371) | +| fanotify | Linux 5.9+ | [Maybe](https://github.com/fsnotify/fsnotify/issues/114) | +| USN Journals | Windows | [Maybe](https://github.com/fsnotify/fsnotify/issues/53) | +| Polling | *All* | [Maybe](https://github.com/fsnotify/fsnotify/issues/9) | + +Linux and macOS should include Android and iOS, but these are currently untested. + +Usage +----- +A basic example: + +```go +package main + +import ( + "log" + + "github.com/fsnotify/fsnotify" +) + +func main() { + // Create new watcher. + watcher, err := fsnotify.NewWatcher() + if err != nil { + log.Fatal(err) + } + defer watcher.Close() + + // Start listening for events. + go func() { + for { + select { + case event, ok := <-watcher.Events: + if !ok { + return + } + log.Println("event:", event) + if event.Has(fsnotify.Write) { + log.Println("modified file:", event.Name) + } + case err, ok := <-watcher.Errors: + if !ok { + return + } + log.Println("error:", err) + } + } + }() + + // Add a path. + err = watcher.Add("/tmp") + if err != nil { + log.Fatal(err) + } + + // Block main goroutine forever. + <-make(chan struct{}) +} +``` + +Some more examples can be found in [cmd/fsnotify](cmd/fsnotify), which can be +run with: + + % go run ./cmd/fsnotify + +FAQ +--- +### Will a file still be watched when it's moved to another directory? +No, not unless you are watching the location it was moved to. + +### Are subdirectories watched too? +No, you must add watches for any directory you want to watch (a recursive +watcher is on the roadmap: [#18]). + +[#18]: https://github.com/fsnotify/fsnotify/issues/18 + +### Do I have to watch the Error and Event channels in a goroutine? +As of now, yes (you can read both channels in the same goroutine using `select`, +you don't need a separate goroutine for both channels; see the example). + +### Why don't notifications work with NFS, SMB, FUSE, /proc, or /sys? +fsnotify requires support from underlying OS to work. The current NFS and SMB +protocols does not provide network level support for file notifications, and +neither do the /proc and /sys virtual filesystems. + +This could be fixed with a polling watcher ([#9]), but it's not yet implemented. + +[#9]: https://github.com/fsnotify/fsnotify/issues/9 + +Platform-specific notes +----------------------- +### Linux +When a file is removed a REMOVE event won't be emitted until all file +descriptors are closed; it will emit a CHMOD instead: + + fp := os.Open("file") + os.Remove("file") // CHMOD + fp.Close() // REMOVE + +This is the event that inotify sends, so not much can be changed about this. + +The `fs.inotify.max_user_watches` sysctl variable specifies the upper limit for +the number of watches per user, and `fs.inotify.max_user_instances` specifies +the maximum number of inotify instances per user. Every Watcher you create is an +"instance", and every path you add is a "watch". + +These are also exposed in `/proc` as `/proc/sys/fs/inotify/max_user_watches` and +`/proc/sys/fs/inotify/max_user_instances` + +To increase them you can use `sysctl` or write the value to proc file: + + # The default values on Linux 5.18 + sysctl fs.inotify.max_user_watches=124983 + sysctl fs.inotify.max_user_instances=128 + +To make the changes persist on reboot edit `/etc/sysctl.conf` or +`/usr/lib/sysctl.d/50-default.conf` (details differ per Linux distro; check your +distro's documentation): + + fs.inotify.max_user_watches=124983 + fs.inotify.max_user_instances=128 + +Reaching the limit will result in a "no space left on device" or "too many open +files" error. + +### kqueue (macOS, all BSD systems) +kqueue requires opening a file descriptor for every file that's being watched; +so if you're watching a directory with five files then that's six file +descriptors. You will run in to your system's "max open files" limit faster on +these platforms. + +The sysctl variables `kern.maxfiles` and `kern.maxfilesperproc` can be used to +control the maximum number of open files. + +### macOS +Spotlight indexing on macOS can result in multiple events (see [#15]). A temporary +workaround is to add your folder(s) to the *Spotlight Privacy settings* until we +have a native FSEvents implementation (see [#11]). + +[#11]: https://github.com/fsnotify/fsnotify/issues/11 +[#15]: https://github.com/fsnotify/fsnotify/issues/15 diff --git a/vendor/github.com/fsnotify/fsnotify/backend_fen.go b/vendor/github.com/fsnotify/fsnotify/backend_fen.go new file mode 100644 index 0000000000..1a95ad8e7c --- /dev/null +++ b/vendor/github.com/fsnotify/fsnotify/backend_fen.go @@ -0,0 +1,162 @@ +//go:build solaris +// +build solaris + +package fsnotify + +import ( + "errors" +) + +// Watcher watches a set of paths, delivering events on a channel. +// +// A watcher should not be copied (e.g. pass it by pointer, rather than by +// value). +// +// # Linux notes +// +// When a file is removed a Remove event won't be emitted until all file +// descriptors are closed, and deletes will always emit a Chmod. For example: +// +// fp := os.Open("file") +// os.Remove("file") // Triggers Chmod +// fp.Close() // Triggers Remove +// +// This is the event that inotify sends, so not much can be changed about this. +// +// The fs.inotify.max_user_watches sysctl variable specifies the upper limit +// for the number of watches per user, and fs.inotify.max_user_instances +// specifies the maximum number of inotify instances per user. Every Watcher you +// create is an "instance", and every path you add is a "watch". +// +// These are also exposed in /proc as /proc/sys/fs/inotify/max_user_watches and +// /proc/sys/fs/inotify/max_user_instances +// +// To increase them you can use sysctl or write the value to the /proc file: +// +// # Default values on Linux 5.18 +// sysctl fs.inotify.max_user_watches=124983 +// sysctl fs.inotify.max_user_instances=128 +// +// To make the changes persist on reboot edit /etc/sysctl.conf or +// /usr/lib/sysctl.d/50-default.conf (details differ per Linux distro; check +// your distro's documentation): +// +// fs.inotify.max_user_watches=124983 +// fs.inotify.max_user_instances=128 +// +// Reaching the limit will result in a "no space left on device" or "too many open +// files" error. +// +// # kqueue notes (macOS, BSD) +// +// kqueue requires opening a file descriptor for every file that's being watched; +// so if you're watching a directory with five files then that's six file +// descriptors. You will run in to your system's "max open files" limit faster on +// these platforms. +// +// The sysctl variables kern.maxfiles and kern.maxfilesperproc can be used to +// control the maximum number of open files, as well as /etc/login.conf on BSD +// systems. +// +// # macOS notes +// +// Spotlight indexing on macOS can result in multiple events (see [#15]). A +// temporary workaround is to add your folder(s) to the "Spotlight Privacy +// Settings" until we have a native FSEvents implementation (see [#11]). +// +// [#11]: https://github.com/fsnotify/fsnotify/issues/11 +// [#15]: https://github.com/fsnotify/fsnotify/issues/15 +type Watcher struct { + // Events sends the filesystem change events. + // + // fsnotify can send the following events; a "path" here can refer to a + // file, directory, symbolic link, or special file like a FIFO. + // + // fsnotify.Create A new path was created; this may be followed by one + // or more Write events if data also gets written to a + // file. + // + // fsnotify.Remove A path was removed. + // + // fsnotify.Rename A path was renamed. A rename is always sent with the + // old path as Event.Name, and a Create event will be + // sent with the new name. Renames are only sent for + // paths that are currently watched; e.g. moving an + // unmonitored file into a monitored directory will + // show up as just a Create. Similarly, renaming a file + // to outside a monitored directory will show up as + // only a Rename. + // + // fsnotify.Write A file or named pipe was written to. A Truncate will + // also trigger a Write. A single "write action" + // initiated by the user may show up as one or multiple + // writes, depending on when the system syncs things to + // disk. For example when compiling a large Go program + // you may get hundreds of Write events, so you + // probably want to wait until you've stopped receiving + // them (see the dedup example in cmd/fsnotify). + // + // fsnotify.Chmod Attributes were changed. On Linux this is also sent + // when a file is removed (or more accurately, when a + // link to an inode is removed). On kqueue it's sent + // and on kqueue when a file is truncated. On Windows + // it's never sent. + Events chan Event + + // Errors sends any errors. + Errors chan error +} + +// NewWatcher creates a new Watcher. +func NewWatcher() (*Watcher, error) { + return nil, errors.New("FEN based watcher not yet supported for fsnotify\n") +} + +// Close removes all watches and closes the events channel. +func (w *Watcher) Close() error { + return nil +} + +// Add starts monitoring the path for changes. +// +// A path can only be watched once; attempting to watch it more than once will +// return an error. Paths that do not yet exist on the filesystem cannot be +// added. A watch will be automatically removed if the path is deleted. +// +// A path will remain watched if it gets renamed to somewhere else on the same +// filesystem, but the monitor will get removed if the path gets deleted and +// re-created, or if it's moved to a different filesystem. +// +// Notifications on network filesystems (NFS, SMB, FUSE, etc.) or special +// filesystems (/proc, /sys, etc.) generally don't work. +// +// # Watching directories +// +// All files in a directory are monitored, including new files that are created +// after the watcher is started. Subdirectories are not watched (i.e. it's +// non-recursive). +// +// # Watching files +// +// Watching individual files (rather than directories) is generally not +// recommended as many tools update files atomically. Instead of "just" writing +// to the file a temporary file will be written to first, and if successful the +// temporary file is moved to to destination removing the original, or some +// variant thereof. The watcher on the original file is now lost, as it no +// longer exists. +// +// Instead, watch the parent directory and use Event.Name to filter out files +// you're not interested in. There is an example of this in [cmd/fsnotify/file.go]. +func (w *Watcher) Add(name string) error { + return nil +} + +// Remove stops monitoring the path for changes. +// +// Directories are always removed non-recursively. For example, if you added +// /tmp/dir and /tmp/dir/subdir then you will need to remove both. +// +// Removing a path that has not yet been added returns [ErrNonExistentWatch]. +func (w *Watcher) Remove(name string) error { + return nil +} diff --git a/vendor/github.com/fsnotify/fsnotify/backend_inotify.go b/vendor/github.com/fsnotify/fsnotify/backend_inotify.go new file mode 100644 index 0000000000..54c77fbb0e --- /dev/null +++ b/vendor/github.com/fsnotify/fsnotify/backend_inotify.go @@ -0,0 +1,459 @@ +//go:build linux +// +build linux + +package fsnotify + +import ( + "errors" + "fmt" + "io" + "os" + "path/filepath" + "strings" + "sync" + "unsafe" + + "golang.org/x/sys/unix" +) + +// Watcher watches a set of paths, delivering events on a channel. +// +// A watcher should not be copied (e.g. pass it by pointer, rather than by +// value). +// +// # Linux notes +// +// When a file is removed a Remove event won't be emitted until all file +// descriptors are closed, and deletes will always emit a Chmod. For example: +// +// fp := os.Open("file") +// os.Remove("file") // Triggers Chmod +// fp.Close() // Triggers Remove +// +// This is the event that inotify sends, so not much can be changed about this. +// +// The fs.inotify.max_user_watches sysctl variable specifies the upper limit +// for the number of watches per user, and fs.inotify.max_user_instances +// specifies the maximum number of inotify instances per user. Every Watcher you +// create is an "instance", and every path you add is a "watch". +// +// These are also exposed in /proc as /proc/sys/fs/inotify/max_user_watches and +// /proc/sys/fs/inotify/max_user_instances +// +// To increase them you can use sysctl or write the value to the /proc file: +// +// # Default values on Linux 5.18 +// sysctl fs.inotify.max_user_watches=124983 +// sysctl fs.inotify.max_user_instances=128 +// +// To make the changes persist on reboot edit /etc/sysctl.conf or +// /usr/lib/sysctl.d/50-default.conf (details differ per Linux distro; check +// your distro's documentation): +// +// fs.inotify.max_user_watches=124983 +// fs.inotify.max_user_instances=128 +// +// Reaching the limit will result in a "no space left on device" or "too many open +// files" error. +// +// # kqueue notes (macOS, BSD) +// +// kqueue requires opening a file descriptor for every file that's being watched; +// so if you're watching a directory with five files then that's six file +// descriptors. You will run in to your system's "max open files" limit faster on +// these platforms. +// +// The sysctl variables kern.maxfiles and kern.maxfilesperproc can be used to +// control the maximum number of open files, as well as /etc/login.conf on BSD +// systems. +// +// # macOS notes +// +// Spotlight indexing on macOS can result in multiple events (see [#15]). A +// temporary workaround is to add your folder(s) to the "Spotlight Privacy +// Settings" until we have a native FSEvents implementation (see [#11]). +// +// [#11]: https://github.com/fsnotify/fsnotify/issues/11 +// [#15]: https://github.com/fsnotify/fsnotify/issues/15 +type Watcher struct { + // Events sends the filesystem change events. + // + // fsnotify can send the following events; a "path" here can refer to a + // file, directory, symbolic link, or special file like a FIFO. + // + // fsnotify.Create A new path was created; this may be followed by one + // or more Write events if data also gets written to a + // file. + // + // fsnotify.Remove A path was removed. + // + // fsnotify.Rename A path was renamed. A rename is always sent with the + // old path as Event.Name, and a Create event will be + // sent with the new name. Renames are only sent for + // paths that are currently watched; e.g. moving an + // unmonitored file into a monitored directory will + // show up as just a Create. Similarly, renaming a file + // to outside a monitored directory will show up as + // only a Rename. + // + // fsnotify.Write A file or named pipe was written to. A Truncate will + // also trigger a Write. A single "write action" + // initiated by the user may show up as one or multiple + // writes, depending on when the system syncs things to + // disk. For example when compiling a large Go program + // you may get hundreds of Write events, so you + // probably want to wait until you've stopped receiving + // them (see the dedup example in cmd/fsnotify). + // + // fsnotify.Chmod Attributes were changed. On Linux this is also sent + // when a file is removed (or more accurately, when a + // link to an inode is removed). On kqueue it's sent + // and on kqueue when a file is truncated. On Windows + // it's never sent. + Events chan Event + + // Errors sends any errors. + Errors chan error + + // Store fd here as os.File.Read() will no longer return on close after + // calling Fd(). See: https://github.com/golang/go/issues/26439 + fd int + mu sync.Mutex // Map access + inotifyFile *os.File + watches map[string]*watch // Map of inotify watches (key: path) + paths map[int]string // Map of watched paths (key: watch descriptor) + done chan struct{} // Channel for sending a "quit message" to the reader goroutine + doneResp chan struct{} // Channel to respond to Close +} + +// NewWatcher creates a new Watcher. +func NewWatcher() (*Watcher, error) { + // Create inotify fd + // Need to set the FD to nonblocking mode in order for SetDeadline methods to work + // Otherwise, blocking i/o operations won't terminate on close + fd, errno := unix.InotifyInit1(unix.IN_CLOEXEC | unix.IN_NONBLOCK) + if fd == -1 { + return nil, errno + } + + w := &Watcher{ + fd: fd, + inotifyFile: os.NewFile(uintptr(fd), ""), + watches: make(map[string]*watch), + paths: make(map[int]string), + Events: make(chan Event), + Errors: make(chan error), + done: make(chan struct{}), + doneResp: make(chan struct{}), + } + + go w.readEvents() + return w, nil +} + +// Returns true if the event was sent, or false if watcher is closed. +func (w *Watcher) sendEvent(e Event) bool { + select { + case w.Events <- e: + return true + case <-w.done: + } + return false +} + +// Returns true if the error was sent, or false if watcher is closed. +func (w *Watcher) sendError(err error) bool { + select { + case w.Errors <- err: + return true + case <-w.done: + return false + } +} + +func (w *Watcher) isClosed() bool { + select { + case <-w.done: + return true + default: + return false + } +} + +// Close removes all watches and closes the events channel. +func (w *Watcher) Close() error { + w.mu.Lock() + if w.isClosed() { + w.mu.Unlock() + return nil + } + + // Send 'close' signal to goroutine, and set the Watcher to closed. + close(w.done) + w.mu.Unlock() + + // Causes any blocking reads to return with an error, provided the file + // still supports deadline operations. + err := w.inotifyFile.Close() + if err != nil { + return err + } + + // Wait for goroutine to close + <-w.doneResp + + return nil +} + +// Add starts monitoring the path for changes. +// +// A path can only be watched once; attempting to watch it more than once will +// return an error. Paths that do not yet exist on the filesystem cannot be +// added. A watch will be automatically removed if the path is deleted. +// +// A path will remain watched if it gets renamed to somewhere else on the same +// filesystem, but the monitor will get removed if the path gets deleted and +// re-created, or if it's moved to a different filesystem. +// +// Notifications on network filesystems (NFS, SMB, FUSE, etc.) or special +// filesystems (/proc, /sys, etc.) generally don't work. +// +// # Watching directories +// +// All files in a directory are monitored, including new files that are created +// after the watcher is started. Subdirectories are not watched (i.e. it's +// non-recursive). +// +// # Watching files +// +// Watching individual files (rather than directories) is generally not +// recommended as many tools update files atomically. Instead of "just" writing +// to the file a temporary file will be written to first, and if successful the +// temporary file is moved to to destination removing the original, or some +// variant thereof. The watcher on the original file is now lost, as it no +// longer exists. +// +// Instead, watch the parent directory and use Event.Name to filter out files +// you're not interested in. There is an example of this in [cmd/fsnotify/file.go]. +func (w *Watcher) Add(name string) error { + name = filepath.Clean(name) + if w.isClosed() { + return errors.New("inotify instance already closed") + } + + var flags uint32 = unix.IN_MOVED_TO | unix.IN_MOVED_FROM | + unix.IN_CREATE | unix.IN_ATTRIB | unix.IN_MODIFY | + unix.IN_MOVE_SELF | unix.IN_DELETE | unix.IN_DELETE_SELF + + w.mu.Lock() + defer w.mu.Unlock() + watchEntry := w.watches[name] + if watchEntry != nil { + flags |= watchEntry.flags | unix.IN_MASK_ADD + } + wd, errno := unix.InotifyAddWatch(w.fd, name, flags) + if wd == -1 { + return errno + } + + if watchEntry == nil { + w.watches[name] = &watch{wd: uint32(wd), flags: flags} + w.paths[wd] = name + } else { + watchEntry.wd = uint32(wd) + watchEntry.flags = flags + } + + return nil +} + +// Remove stops monitoring the path for changes. +// +// Directories are always removed non-recursively. For example, if you added +// /tmp/dir and /tmp/dir/subdir then you will need to remove both. +// +// Removing a path that has not yet been added returns [ErrNonExistentWatch]. +func (w *Watcher) Remove(name string) error { + name = filepath.Clean(name) + + // Fetch the watch. + w.mu.Lock() + defer w.mu.Unlock() + watch, ok := w.watches[name] + + // Remove it from inotify. + if !ok { + return fmt.Errorf("%w: %s", ErrNonExistentWatch, 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; + // the inotify will already have been removed. + // watches and pathes are deleted in ignoreLinux() implicitly and asynchronously + // by calling inotify_rm_watch() below. e.g. readEvents() goroutine receives IN_IGNORE + // so that EINVAL means that the wd is being rm_watch()ed or its file removed + // by another thread and we have not received IN_IGNORE event. + success, errno := unix.InotifyRmWatch(w.fd, watch.wd) + if success == -1 { + // TODO: Perhaps it's not helpful to return an error here in every case; + // The only two possible errors are: + // + // - EBADF, which happens when w.fd is not a valid file descriptor + // of any kind. + // - EINVAL, which is when fd is not an inotify descriptor or wd + // is not a valid watch descriptor. Watch descriptors are + // invalidated when they are removed explicitly or implicitly; + // explicitly by inotify_rm_watch, implicitly when the file they + // are watching is deleted. + return errno + } + + return nil +} + +// WatchList returns all paths added with [Add] (and are not yet removed). +func (w *Watcher) WatchList() []string { + w.mu.Lock() + defer w.mu.Unlock() + + entries := make([]string, 0, len(w.watches)) + for pathname := range w.watches { + entries = append(entries, pathname) + } + + return entries +} + +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) +} + +// readEvents reads from the inotify file descriptor, converts the +// received events into Event objects and sends them via the Events channel +func (w *Watcher) readEvents() { + defer func() { + close(w.doneResp) + close(w.Errors) + close(w.Events) + }() + + var ( + buf [unix.SizeofInotifyEvent * 4096]byte // Buffer for a maximum of 4096 raw events + errno error // Syscall errno + ) + for { + // See if we have been closed. + if w.isClosed() { + return + } + + n, err := w.inotifyFile.Read(buf[:]) + switch { + case errors.Unwrap(err) == os.ErrClosed: + return + case err != nil: + if !w.sendError(err) { + return + } + continue + } + + if n < unix.SizeofInotifyEvent { + var err error + if n == 0 { + // If EOF is received. This should really never happen. + err = io.EOF + } else if n < 0 { + // If an error occurred while reading. + err = errno + } else { + // Read was too short. + err = errors.New("notify: short read in readEvents()") + } + if !w.sendError(err) { + return + } + continue + } + + var offset uint32 + // We don't know how many events we just read into the buffer + // While the offset points to at least one whole event... + for offset <= uint32(n-unix.SizeofInotifyEvent) { + var ( + // Point "raw" to the event in the buffer + raw = (*unix.InotifyEvent)(unsafe.Pointer(&buf[offset])) + mask = uint32(raw.Mask) + nameLen = uint32(raw.Len) + ) + + if mask&unix.IN_Q_OVERFLOW != 0 { + if !w.sendError(ErrEventOverflow) { + return + } + } + + // 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 + // the "Name" field with a valid filename. We retrieve the path of the watch from + // the "paths" map. + w.mu.Lock() + 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() + + if nameLen > 0 { + // Point "bytes" at the first byte of the filename + bytes := (*[unix.PathMax]byte)(unsafe.Pointer(&buf[offset+unix.SizeofInotifyEvent]))[:nameLen:nameLen] + // The filename is padded with NULL bytes. TrimRight() gets rid of those. + name += "/" + strings.TrimRight(string(bytes[0:nameLen]), "\000") + } + + event := w.newEvent(name, mask) + + // Send the events that are not ignored on the events channel + if mask&unix.IN_IGNORED == 0 { + if !w.sendEvent(event) { + return + } + } + + // Move to the next event in the buffer + offset += unix.SizeofInotifyEvent + nameLen + } + } +} + +// newEvent returns an platform-independent Event based on an inotify mask. +func (w *Watcher) newEvent(name string, mask uint32) Event { + e := Event{Name: name} + if mask&unix.IN_CREATE == unix.IN_CREATE || mask&unix.IN_MOVED_TO == unix.IN_MOVED_TO { + e.Op |= Create + } + if mask&unix.IN_DELETE_SELF == unix.IN_DELETE_SELF || mask&unix.IN_DELETE == unix.IN_DELETE { + e.Op |= Remove + } + if mask&unix.IN_MODIFY == unix.IN_MODIFY { + e.Op |= Write + } + if mask&unix.IN_MOVE_SELF == unix.IN_MOVE_SELF || mask&unix.IN_MOVED_FROM == unix.IN_MOVED_FROM { + e.Op |= Rename + } + if mask&unix.IN_ATTRIB == unix.IN_ATTRIB { + e.Op |= Chmod + } + return e +} diff --git a/vendor/github.com/fsnotify/fsnotify/backend_kqueue.go b/vendor/github.com/fsnotify/fsnotify/backend_kqueue.go new file mode 100644 index 0000000000..29087469bf --- /dev/null +++ b/vendor/github.com/fsnotify/fsnotify/backend_kqueue.go @@ -0,0 +1,707 @@ +//go:build freebsd || openbsd || netbsd || dragonfly || darwin +// +build freebsd openbsd netbsd dragonfly darwin + +package fsnotify + +import ( + "errors" + "fmt" + "io/ioutil" + "os" + "path/filepath" + "sync" + + "golang.org/x/sys/unix" +) + +// Watcher watches a set of paths, delivering events on a channel. +// +// A watcher should not be copied (e.g. pass it by pointer, rather than by +// value). +// +// # Linux notes +// +// When a file is removed a Remove event won't be emitted until all file +// descriptors are closed, and deletes will always emit a Chmod. For example: +// +// fp := os.Open("file") +// os.Remove("file") // Triggers Chmod +// fp.Close() // Triggers Remove +// +// This is the event that inotify sends, so not much can be changed about this. +// +// The fs.inotify.max_user_watches sysctl variable specifies the upper limit +// for the number of watches per user, and fs.inotify.max_user_instances +// specifies the maximum number of inotify instances per user. Every Watcher you +// create is an "instance", and every path you add is a "watch". +// +// These are also exposed in /proc as /proc/sys/fs/inotify/max_user_watches and +// /proc/sys/fs/inotify/max_user_instances +// +// To increase them you can use sysctl or write the value to the /proc file: +// +// # Default values on Linux 5.18 +// sysctl fs.inotify.max_user_watches=124983 +// sysctl fs.inotify.max_user_instances=128 +// +// To make the changes persist on reboot edit /etc/sysctl.conf or +// /usr/lib/sysctl.d/50-default.conf (details differ per Linux distro; check +// your distro's documentation): +// +// fs.inotify.max_user_watches=124983 +// fs.inotify.max_user_instances=128 +// +// Reaching the limit will result in a "no space left on device" or "too many open +// files" error. +// +// # kqueue notes (macOS, BSD) +// +// kqueue requires opening a file descriptor for every file that's being watched; +// so if you're watching a directory with five files then that's six file +// descriptors. You will run in to your system's "max open files" limit faster on +// these platforms. +// +// The sysctl variables kern.maxfiles and kern.maxfilesperproc can be used to +// control the maximum number of open files, as well as /etc/login.conf on BSD +// systems. +// +// # macOS notes +// +// Spotlight indexing on macOS can result in multiple events (see [#15]). A +// temporary workaround is to add your folder(s) to the "Spotlight Privacy +// Settings" until we have a native FSEvents implementation (see [#11]). +// +// [#11]: https://github.com/fsnotify/fsnotify/issues/11 +// [#15]: https://github.com/fsnotify/fsnotify/issues/15 +type Watcher struct { + // Events sends the filesystem change events. + // + // fsnotify can send the following events; a "path" here can refer to a + // file, directory, symbolic link, or special file like a FIFO. + // + // fsnotify.Create A new path was created; this may be followed by one + // or more Write events if data also gets written to a + // file. + // + // fsnotify.Remove A path was removed. + // + // fsnotify.Rename A path was renamed. A rename is always sent with the + // old path as Event.Name, and a Create event will be + // sent with the new name. Renames are only sent for + // paths that are currently watched; e.g. moving an + // unmonitored file into a monitored directory will + // show up as just a Create. Similarly, renaming a file + // to outside a monitored directory will show up as + // only a Rename. + // + // fsnotify.Write A file or named pipe was written to. A Truncate will + // also trigger a Write. A single "write action" + // initiated by the user may show up as one or multiple + // writes, depending on when the system syncs things to + // disk. For example when compiling a large Go program + // you may get hundreds of Write events, so you + // probably want to wait until you've stopped receiving + // them (see the dedup example in cmd/fsnotify). + // + // fsnotify.Chmod Attributes were changed. On Linux this is also sent + // when a file is removed (or more accurately, when a + // link to an inode is removed). On kqueue it's sent + // and on kqueue when a file is truncated. On Windows + // it's never sent. + Events chan Event + + // Errors sends any errors. + Errors chan error + + done chan struct{} + kq int // File descriptor (as returned by the kqueue() syscall). + closepipe [2]int // Pipe used for closing. + mu sync.Mutex // Protects access to watcher data + watches map[string]int // Watched file descriptors (key: path). + watchesByDir map[string]map[int]struct{} // Watched file descriptors indexed by the parent directory (key: dirname(path)). + userWatches map[string]struct{} // Watches added with Watcher.Add() + dirFlags map[string]uint32 // Watched directories to fflags used in kqueue. + paths map[int]pathInfo // File descriptors to path names for processing kqueue events. + fileExists map[string]struct{} // Keep track of if we know this file exists (to stop duplicate create events). + isClosed bool // Set to true when Close() is first called +} + +type pathInfo struct { + name string + isDir bool +} + +// NewWatcher creates a new Watcher. +func NewWatcher() (*Watcher, error) { + kq, closepipe, err := newKqueue() + if err != nil { + return nil, err + } + + w := &Watcher{ + kq: kq, + closepipe: closepipe, + watches: make(map[string]int), + watchesByDir: make(map[string]map[int]struct{}), + dirFlags: make(map[string]uint32), + paths: make(map[int]pathInfo), + fileExists: make(map[string]struct{}), + userWatches: make(map[string]struct{}), + Events: make(chan Event), + Errors: make(chan error), + done: make(chan struct{}), + } + + go w.readEvents() + return w, nil +} + +// newKqueue creates a new kernel event queue and returns a descriptor. +// +// This registers a new event on closepipe, which will trigger an event when +// it's closed. This way we can use kevent() without timeout/polling; without +// the closepipe, it would block forever and we wouldn't be able to stop it at +// all. +func newKqueue() (kq int, closepipe [2]int, err error) { + kq, err = unix.Kqueue() + if kq == -1 { + return kq, closepipe, err + } + + // Register the close pipe. + err = unix.Pipe(closepipe[:]) + if err != nil { + unix.Close(kq) + return kq, closepipe, err + } + + // Register changes to listen on the closepipe. + changes := make([]unix.Kevent_t, 1) + // SetKevent converts int to the platform-specific types. + unix.SetKevent(&changes[0], closepipe[0], unix.EVFILT_READ, + unix.EV_ADD|unix.EV_ENABLE|unix.EV_ONESHOT) + + ok, err := unix.Kevent(kq, changes, nil, nil) + if ok == -1 { + unix.Close(kq) + unix.Close(closepipe[0]) + unix.Close(closepipe[1]) + return kq, closepipe, err + } + return kq, closepipe, nil +} + +// Returns true if the event was sent, or false if watcher is closed. +func (w *Watcher) sendEvent(e Event) bool { + select { + case w.Events <- e: + return true + case <-w.done: + } + return false +} + +// Returns true if the error was sent, or false if watcher is closed. +func (w *Watcher) sendError(err error) bool { + select { + case w.Errors <- err: + return true + case <-w.done: + } + return false +} + +// Close removes all watches and closes the events channel. +func (w *Watcher) Close() error { + w.mu.Lock() + if w.isClosed { + w.mu.Unlock() + return nil + } + w.isClosed = true + + // copy paths to remove while locked + pathsToRemove := make([]string, 0, len(w.watches)) + for name := range w.watches { + pathsToRemove = append(pathsToRemove, name) + } + w.mu.Unlock() // Unlock before calling Remove, which also locks + for _, name := range pathsToRemove { + w.Remove(name) + } + + // Send "quit" message to the reader goroutine. + unix.Close(w.closepipe[1]) + close(w.done) + + return nil +} + +// Add starts monitoring the path for changes. +// +// A path can only be watched once; attempting to watch it more than once will +// return an error. Paths that do not yet exist on the filesystem cannot be +// added. A watch will be automatically removed if the path is deleted. +// +// A path will remain watched if it gets renamed to somewhere else on the same +// filesystem, but the monitor will get removed if the path gets deleted and +// re-created, or if it's moved to a different filesystem. +// +// Notifications on network filesystems (NFS, SMB, FUSE, etc.) or special +// filesystems (/proc, /sys, etc.) generally don't work. +// +// # Watching directories +// +// All files in a directory are monitored, including new files that are created +// after the watcher is started. Subdirectories are not watched (i.e. it's +// non-recursive). +// +// # Watching files +// +// Watching individual files (rather than directories) is generally not +// recommended as many tools update files atomically. Instead of "just" writing +// to the file a temporary file will be written to first, and if successful the +// temporary file is moved to to destination removing the original, or some +// variant thereof. The watcher on the original file is now lost, as it no +// longer exists. +// +// Instead, watch the parent directory and use Event.Name to filter out files +// you're not interested in. There is an example of this in [cmd/fsnotify/file.go]. +func (w *Watcher) Add(name string) error { + w.mu.Lock() + w.userWatches[name] = struct{}{} + w.mu.Unlock() + _, err := w.addWatch(name, noteAllEvents) + return err +} + +// Remove stops monitoring the path for changes. +// +// Directories are always removed non-recursively. For example, if you added +// /tmp/dir and /tmp/dir/subdir then you will need to remove both. +// +// Removing a path that has not yet been added returns [ErrNonExistentWatch]. +func (w *Watcher) Remove(name string) error { + name = filepath.Clean(name) + w.mu.Lock() + watchfd, ok := w.watches[name] + w.mu.Unlock() + if !ok { + return fmt.Errorf("%w: %s", ErrNonExistentWatch, name) + } + + err := w.register([]int{watchfd}, unix.EV_DELETE, 0) + if err != nil { + return err + } + + unix.Close(watchfd) + + w.mu.Lock() + isDir := w.paths[watchfd].isDir + delete(w.watches, name) + delete(w.userWatches, name) + + parentName := filepath.Dir(name) + delete(w.watchesByDir[parentName], watchfd) + + if len(w.watchesByDir[parentName]) == 0 { + delete(w.watchesByDir, parentName) + } + + delete(w.paths, watchfd) + delete(w.dirFlags, name) + delete(w.fileExists, name) + w.mu.Unlock() + + // Find all watched paths that are in this directory that are not external. + if isDir { + var pathsToRemove []string + w.mu.Lock() + for fd := range w.watchesByDir[name] { + path := w.paths[fd] + if _, ok := w.userWatches[path.name]; !ok { + pathsToRemove = append(pathsToRemove, path.name) + } + } + w.mu.Unlock() + for _, name := range pathsToRemove { + // Since these are internal, not much sense in propagating error + // to the user, as that will just confuse them with an error about + // a path they did not explicitly watch themselves. + w.Remove(name) + } + } + + return nil +} + +// WatchList returns all paths added with [Add] (and are not yet removed). +func (w *Watcher) WatchList() []string { + w.mu.Lock() + defer w.mu.Unlock() + + entries := make([]string, 0, len(w.userWatches)) + for pathname := range w.userWatches { + entries = append(entries, pathname) + } + + return entries +} + +// Watch all events (except NOTE_EXTEND, NOTE_LINK, NOTE_REVOKE) +const noteAllEvents = unix.NOTE_DELETE | unix.NOTE_WRITE | unix.NOTE_ATTRIB | unix.NOTE_RENAME + +// addWatch adds name to the watched file set. +// The flags are interpreted as described in kevent(2). +// Returns the real path to the file which was added, if any, which may be different from the one passed in the case of symlinks. +func (w *Watcher) addWatch(name string, flags uint32) (string, error) { + var isDir bool + // Make ./name and name equivalent + name = filepath.Clean(name) + + w.mu.Lock() + if w.isClosed { + w.mu.Unlock() + return "", errors.New("kevent instance already closed") + } + watchfd, alreadyWatching := w.watches[name] + // We already have a watch, but we can still override flags. + if alreadyWatching { + isDir = w.paths[watchfd].isDir + } + w.mu.Unlock() + + if !alreadyWatching { + fi, err := os.Lstat(name) + if err != nil { + return "", err + } + + // Don't watch sockets or named pipes + if (fi.Mode()&os.ModeSocket == os.ModeSocket) || (fi.Mode()&os.ModeNamedPipe == os.ModeNamedPipe) { + return "", nil + } + + // Follow Symlinks + // + // Linux can add unresolvable symlinks to the watch list without issue, + // and Windows can't do symlinks period. To maintain consistency, we + // will act like everything is fine if the link can't be resolved. + // There will simply be no file events for broken symlinks. Hence the + // returns of nil on errors. + if fi.Mode()&os.ModeSymlink == os.ModeSymlink { + name, err = filepath.EvalSymlinks(name) + if err != nil { + return "", nil + } + + w.mu.Lock() + _, alreadyWatching = w.watches[name] + w.mu.Unlock() + + if alreadyWatching { + return name, nil + } + + fi, err = os.Lstat(name) + if err != nil { + return "", nil + } + } + + // Retry on EINTR; open() can return EINTR in practice on macOS. + // See #354, and go issues 11180 and 39237. + for { + watchfd, err = unix.Open(name, openMode, 0) + if err == nil { + break + } + if errors.Is(err, unix.EINTR) { + continue + } + + return "", err + } + + isDir = fi.IsDir() + } + + err := w.register([]int{watchfd}, unix.EV_ADD|unix.EV_CLEAR|unix.EV_ENABLE, flags) + if err != nil { + unix.Close(watchfd) + return "", err + } + + if !alreadyWatching { + w.mu.Lock() + parentName := filepath.Dir(name) + w.watches[name] = watchfd + + watchesByDir, ok := w.watchesByDir[parentName] + if !ok { + watchesByDir = make(map[int]struct{}, 1) + w.watchesByDir[parentName] = watchesByDir + } + watchesByDir[watchfd] = struct{}{} + + w.paths[watchfd] = pathInfo{name: name, isDir: isDir} + w.mu.Unlock() + } + + if isDir { + // Watch the directory if it has not been watched before, + // or if it was watched before, but perhaps only a NOTE_DELETE (watchDirectoryFiles) + w.mu.Lock() + + watchDir := (flags&unix.NOTE_WRITE) == unix.NOTE_WRITE && + (!alreadyWatching || (w.dirFlags[name]&unix.NOTE_WRITE) != unix.NOTE_WRITE) + // Store flags so this watch can be updated later + w.dirFlags[name] = flags + w.mu.Unlock() + + if watchDir { + if err := w.watchDirectoryFiles(name); err != nil { + return "", err + } + } + } + return name, nil +} + +// readEvents reads from kqueue and converts the received kevents into +// Event values that it sends down the Events channel. +func (w *Watcher) readEvents() { + defer func() { + err := unix.Close(w.kq) + if err != nil { + w.Errors <- err + } + unix.Close(w.closepipe[0]) + close(w.Events) + close(w.Errors) + }() + + eventBuffer := make([]unix.Kevent_t, 10) + for closed := false; !closed; { + kevents, err := w.read(eventBuffer) + // EINTR is okay, the syscall was interrupted before timeout expired. + if err != nil && err != unix.EINTR { + if !w.sendError(fmt.Errorf("fsnotify.readEvents: %w", err)) { + closed = true + } + continue + } + + // Flush the events we received to the Events channel + for _, kevent := range kevents { + var ( + watchfd = int(kevent.Ident) + mask = uint32(kevent.Fflags) + ) + + // Shut down the loop when the pipe is closed, but only after all + // other events have been processed. + if watchfd == w.closepipe[0] { + closed = true + continue + } + + w.mu.Lock() + path := w.paths[watchfd] + w.mu.Unlock() + + event := w.newEvent(path.name, mask) + + if path.isDir && !event.Has(Remove) { + // Double check to make sure the directory exists. This can + // happen when we do a rm -fr on a recursively watched folders + // and we receive a modification event first but the folder has + // been deleted and later receive the delete event. + if _, err := os.Lstat(event.Name); os.IsNotExist(err) { + event.Op |= Remove + } + } + + if event.Has(Rename) || event.Has(Remove) { + w.Remove(event.Name) + w.mu.Lock() + delete(w.fileExists, event.Name) + w.mu.Unlock() + } + + if path.isDir && event.Has(Write) && !event.Has(Remove) { + w.sendDirectoryChangeEvents(event.Name) + } else { + if !w.sendEvent(event) { + closed = true + continue + } + } + + if event.Has(Remove) { + // Look for a file that may have overwritten this. + // For example, mv f1 f2 will delete f2, then create f2. + if path.isDir { + fileDir := filepath.Clean(event.Name) + w.mu.Lock() + _, found := w.watches[fileDir] + w.mu.Unlock() + if found { + // make sure the directory exists before we watch for changes. When we + // do a recursive watch and perform rm -fr, the parent directory might + // have gone missing, ignore the missing directory and let the + // upcoming delete event remove the watch from the parent directory. + if _, err := os.Lstat(fileDir); err == nil { + w.sendDirectoryChangeEvents(fileDir) + } + } + } else { + filePath := filepath.Clean(event.Name) + if fileInfo, err := os.Lstat(filePath); err == nil { + w.sendFileCreatedEventIfNew(filePath, fileInfo) + } + } + } + } + } +} + +// newEvent returns an platform-independent Event based on kqueue Fflags. +func (w *Watcher) newEvent(name string, mask uint32) Event { + e := Event{Name: name} + if mask&unix.NOTE_DELETE == unix.NOTE_DELETE { + e.Op |= Remove + } + if mask&unix.NOTE_WRITE == unix.NOTE_WRITE { + e.Op |= Write + } + if mask&unix.NOTE_RENAME == unix.NOTE_RENAME { + e.Op |= Rename + } + if mask&unix.NOTE_ATTRIB == unix.NOTE_ATTRIB { + e.Op |= Chmod + } + return e +} + +// watchDirectoryFiles to mimic inotify when adding a watch on a directory +func (w *Watcher) watchDirectoryFiles(dirPath string) error { + // Get all files + files, err := ioutil.ReadDir(dirPath) + if err != nil { + return err + } + + for _, fileInfo := range files { + path := filepath.Join(dirPath, fileInfo.Name()) + + cleanPath, err := w.internalWatch(path, fileInfo) + if err != nil { + // No permission to read the file; that's not a problem: just skip. + // But do add it to w.fileExists to prevent it from being picked up + // as a "new" file later (it still shows up in the directory + // listing). + switch { + case errors.Is(err, unix.EACCES) || errors.Is(err, unix.EPERM): + cleanPath = filepath.Clean(path) + default: + return fmt.Errorf("%q: %w", filepath.Join(dirPath, fileInfo.Name()), err) + } + } + + w.mu.Lock() + w.fileExists[cleanPath] = struct{}{} + w.mu.Unlock() + } + + return nil +} + +// Search the directory for new files and send an event for them. +// +// This functionality is to have the BSD watcher match the inotify, which sends +// a create event for files created in a watched directory. +func (w *Watcher) sendDirectoryChangeEvents(dir string) { + // Get all files + files, err := ioutil.ReadDir(dir) + if err != nil { + if !w.sendError(fmt.Errorf("fsnotify.sendDirectoryChangeEvents: %w", err)) { + return + } + } + + // Search for new files + for _, fi := range files { + err := w.sendFileCreatedEventIfNew(filepath.Join(dir, fi.Name()), fi) + if err != nil { + return + } + } +} + +// sendFileCreatedEvent sends a create event if the file isn't already being tracked. +func (w *Watcher) sendFileCreatedEventIfNew(filePath string, fileInfo os.FileInfo) (err error) { + w.mu.Lock() + _, doesExist := w.fileExists[filePath] + w.mu.Unlock() + if !doesExist { + if !w.sendEvent(Event{Name: filePath, Op: Create}) { + return + } + } + + // like watchDirectoryFiles (but without doing another ReadDir) + filePath, err = w.internalWatch(filePath, fileInfo) + if err != nil { + return err + } + + w.mu.Lock() + w.fileExists[filePath] = struct{}{} + w.mu.Unlock() + + return nil +} + +func (w *Watcher) internalWatch(name string, fileInfo os.FileInfo) (string, error) { + if fileInfo.IsDir() { + // mimic Linux providing delete events for subdirectories + // but preserve the flags used if currently watching subdirectory + w.mu.Lock() + flags := w.dirFlags[name] + w.mu.Unlock() + + flags |= unix.NOTE_DELETE | unix.NOTE_RENAME + return w.addWatch(name, flags) + } + + // watch file to mimic Linux inotify + return w.addWatch(name, noteAllEvents) +} + +// Register events with the queue. +func (w *Watcher) register(fds []int, flags int, fflags uint32) error { + changes := make([]unix.Kevent_t, len(fds)) + for i, fd := range fds { + // SetKevent converts int to the platform-specific types. + unix.SetKevent(&changes[i], fd, unix.EVFILT_VNODE, flags) + changes[i].Fflags = fflags + } + + // Register the events. + success, err := unix.Kevent(w.kq, changes, nil, nil) + if success == -1 { + return err + } + return nil +} + +// read retrieves pending events, or waits until an event occurs. +func (w *Watcher) read(events []unix.Kevent_t) ([]unix.Kevent_t, error) { + n, err := unix.Kevent(w.kq, nil, events, nil) + if err != nil { + return nil, err + } + return events[0:n], nil +} diff --git a/vendor/github.com/fsnotify/fsnotify/backend_other.go b/vendor/github.com/fsnotify/fsnotify/backend_other.go new file mode 100644 index 0000000000..a9bb1c3c4d --- /dev/null +++ b/vendor/github.com/fsnotify/fsnotify/backend_other.go @@ -0,0 +1,66 @@ +//go:build !darwin && !dragonfly && !freebsd && !openbsd && !linux && !netbsd && !solaris && !windows +// +build !darwin,!dragonfly,!freebsd,!openbsd,!linux,!netbsd,!solaris,!windows + +package fsnotify + +import ( + "fmt" + "runtime" +) + +// Watcher watches a set of files, delivering events to a channel. +type Watcher struct{} + +// NewWatcher creates a new Watcher. +func NewWatcher() (*Watcher, error) { + return nil, fmt.Errorf("fsnotify not supported on %s", runtime.GOOS) +} + +// Close removes all watches and closes the events channel. +func (w *Watcher) Close() error { + return nil +} + +// Add starts monitoring the path for changes. +// +// A path can only be watched once; attempting to watch it more than once will +// return an error. Paths that do not yet exist on the filesystem cannot be +// added. A watch will be automatically removed if the path is deleted. +// +// A path will remain watched if it gets renamed to somewhere else on the same +// filesystem, but the monitor will get removed if the path gets deleted and +// re-created, or if it's moved to a different filesystem. +// +// Notifications on network filesystems (NFS, SMB, FUSE, etc.) or special +// filesystems (/proc, /sys, etc.) generally don't work. +// +// # Watching directories +// +// All files in a directory are monitored, including new files that are created +// after the watcher is started. Subdirectories are not watched (i.e. it's +// non-recursive). +// +// # Watching files +// +// Watching individual files (rather than directories) is generally not +// recommended as many tools update files atomically. Instead of "just" writing +// to the file a temporary file will be written to first, and if successful the +// temporary file is moved to to destination removing the original, or some +// variant thereof. The watcher on the original file is now lost, as it no +// longer exists. +// +// Instead, watch the parent directory and use Event.Name to filter out files +// you're not interested in. There is an example of this in [cmd/fsnotify/file.go]. +func (w *Watcher) Add(name string) error { + return nil +} + +// Remove stops monitoring the path for changes. +// +// Directories are always removed non-recursively. For example, if you added +// /tmp/dir and /tmp/dir/subdir then you will need to remove both. +// +// Removing a path that has not yet been added returns [ErrNonExistentWatch]. +func (w *Watcher) Remove(name string) error { + return nil +} diff --git a/vendor/github.com/fsnotify/fsnotify/backend_windows.go b/vendor/github.com/fsnotify/fsnotify/backend_windows.go new file mode 100644 index 0000000000..ae392867c0 --- /dev/null +++ b/vendor/github.com/fsnotify/fsnotify/backend_windows.go @@ -0,0 +1,746 @@ +//go:build windows +// +build windows + +package fsnotify + +import ( + "errors" + "fmt" + "os" + "path/filepath" + "reflect" + "runtime" + "strings" + "sync" + "unsafe" + + "golang.org/x/sys/windows" +) + +// Watcher watches a set of paths, delivering events on a channel. +// +// A watcher should not be copied (e.g. pass it by pointer, rather than by +// value). +// +// # Linux notes +// +// When a file is removed a Remove event won't be emitted until all file +// descriptors are closed, and deletes will always emit a Chmod. For example: +// +// fp := os.Open("file") +// os.Remove("file") // Triggers Chmod +// fp.Close() // Triggers Remove +// +// This is the event that inotify sends, so not much can be changed about this. +// +// The fs.inotify.max_user_watches sysctl variable specifies the upper limit +// for the number of watches per user, and fs.inotify.max_user_instances +// specifies the maximum number of inotify instances per user. Every Watcher you +// create is an "instance", and every path you add is a "watch". +// +// These are also exposed in /proc as /proc/sys/fs/inotify/max_user_watches and +// /proc/sys/fs/inotify/max_user_instances +// +// To increase them you can use sysctl or write the value to the /proc file: +// +// # Default values on Linux 5.18 +// sysctl fs.inotify.max_user_watches=124983 +// sysctl fs.inotify.max_user_instances=128 +// +// To make the changes persist on reboot edit /etc/sysctl.conf or +// /usr/lib/sysctl.d/50-default.conf (details differ per Linux distro; check +// your distro's documentation): +// +// fs.inotify.max_user_watches=124983 +// fs.inotify.max_user_instances=128 +// +// Reaching the limit will result in a "no space left on device" or "too many open +// files" error. +// +// # kqueue notes (macOS, BSD) +// +// kqueue requires opening a file descriptor for every file that's being watched; +// so if you're watching a directory with five files then that's six file +// descriptors. You will run in to your system's "max open files" limit faster on +// these platforms. +// +// The sysctl variables kern.maxfiles and kern.maxfilesperproc can be used to +// control the maximum number of open files, as well as /etc/login.conf on BSD +// systems. +// +// # macOS notes +// +// Spotlight indexing on macOS can result in multiple events (see [#15]). A +// temporary workaround is to add your folder(s) to the "Spotlight Privacy +// Settings" until we have a native FSEvents implementation (see [#11]). +// +// [#11]: https://github.com/fsnotify/fsnotify/issues/11 +// [#15]: https://github.com/fsnotify/fsnotify/issues/15 +type Watcher struct { + // Events sends the filesystem change events. + // + // fsnotify can send the following events; a "path" here can refer to a + // file, directory, symbolic link, or special file like a FIFO. + // + // fsnotify.Create A new path was created; this may be followed by one + // or more Write events if data also gets written to a + // file. + // + // fsnotify.Remove A path was removed. + // + // fsnotify.Rename A path was renamed. A rename is always sent with the + // old path as Event.Name, and a Create event will be + // sent with the new name. Renames are only sent for + // paths that are currently watched; e.g. moving an + // unmonitored file into a monitored directory will + // show up as just a Create. Similarly, renaming a file + // to outside a monitored directory will show up as + // only a Rename. + // + // fsnotify.Write A file or named pipe was written to. A Truncate will + // also trigger a Write. A single "write action" + // initiated by the user may show up as one or multiple + // writes, depending on when the system syncs things to + // disk. For example when compiling a large Go program + // you may get hundreds of Write events, so you + // probably want to wait until you've stopped receiving + // them (see the dedup example in cmd/fsnotify). + // + // fsnotify.Chmod Attributes were changed. On Linux this is also sent + // when a file is removed (or more accurately, when a + // link to an inode is removed). On kqueue it's sent + // and on kqueue when a file is truncated. On Windows + // it's never sent. + Events chan Event + + // Errors sends any errors. + Errors chan error + + port windows.Handle // Handle to completion port + input chan *input // Inputs to the reader are sent on this channel + quit chan chan<- error + + mu sync.Mutex // Protects access to watches, isClosed + watches watchMap // Map of watches (key: i-number) + isClosed bool // Set to true when Close() is first called +} + +// NewWatcher creates a new Watcher. +func NewWatcher() (*Watcher, error) { + port, err := windows.CreateIoCompletionPort(windows.InvalidHandle, 0, 0, 0) + if err != nil { + return nil, os.NewSyscallError("CreateIoCompletionPort", err) + } + w := &Watcher{ + port: port, + watches: make(watchMap), + input: make(chan *input, 1), + Events: make(chan Event, 50), + Errors: make(chan error), + quit: make(chan chan<- error, 1), + } + go w.readEvents() + return w, nil +} + +func (w *Watcher) sendEvent(name string, mask uint64) bool { + if mask == 0 { + return false + } + + event := w.newEvent(name, uint32(mask)) + select { + case ch := <-w.quit: + w.quit <- ch + case w.Events <- event: + } + return true +} + +// Returns true if the error was sent, or false if watcher is closed. +func (w *Watcher) sendError(err error) bool { + select { + case w.Errors <- err: + return true + case <-w.quit: + } + return false +} + +// Close removes all watches and closes the events channel. +func (w *Watcher) Close() error { + w.mu.Lock() + if w.isClosed { + w.mu.Unlock() + return nil + } + w.isClosed = true + w.mu.Unlock() + + // Send "quit" message to the reader goroutine + ch := make(chan error) + w.quit <- ch + if err := w.wakeupReader(); err != nil { + return err + } + return <-ch +} + +// Add starts monitoring the path for changes. +// +// A path can only be watched once; attempting to watch it more than once will +// return an error. Paths that do not yet exist on the filesystem cannot be +// added. A watch will be automatically removed if the path is deleted. +// +// A path will remain watched if it gets renamed to somewhere else on the same +// filesystem, but the monitor will get removed if the path gets deleted and +// re-created, or if it's moved to a different filesystem. +// +// Notifications on network filesystems (NFS, SMB, FUSE, etc.) or special +// filesystems (/proc, /sys, etc.) generally don't work. +// +// # Watching directories +// +// All files in a directory are monitored, including new files that are created +// after the watcher is started. Subdirectories are not watched (i.e. it's +// non-recursive). +// +// # Watching files +// +// Watching individual files (rather than directories) is generally not +// recommended as many tools update files atomically. Instead of "just" writing +// to the file a temporary file will be written to first, and if successful the +// temporary file is moved to to destination removing the original, or some +// variant thereof. The watcher on the original file is now lost, as it no +// longer exists. +// +// Instead, watch the parent directory and use Event.Name to filter out files +// you're not interested in. There is an example of this in [cmd/fsnotify/file.go]. +func (w *Watcher) Add(name string) error { + w.mu.Lock() + if w.isClosed { + w.mu.Unlock() + return errors.New("watcher already closed") + } + w.mu.Unlock() + + in := &input{ + op: opAddWatch, + path: filepath.Clean(name), + flags: sysFSALLEVENTS, + reply: make(chan error), + } + w.input <- in + if err := w.wakeupReader(); err != nil { + return err + } + return <-in.reply +} + +// Remove stops monitoring the path for changes. +// +// Directories are always removed non-recursively. For example, if you added +// /tmp/dir and /tmp/dir/subdir then you will need to remove both. +// +// Removing a path that has not yet been added returns [ErrNonExistentWatch]. +func (w *Watcher) Remove(name string) error { + in := &input{ + op: opRemoveWatch, + path: filepath.Clean(name), + reply: make(chan error), + } + w.input <- in + if err := w.wakeupReader(); err != nil { + return err + } + return <-in.reply +} + +// WatchList returns all paths added with [Add] (and are not yet removed). +func (w *Watcher) WatchList() []string { + w.mu.Lock() + defer w.mu.Unlock() + + entries := make([]string, 0, len(w.watches)) + for _, entry := range w.watches { + for _, watchEntry := range entry { + entries = append(entries, watchEntry.path) + } + } + + return entries +} + +// These options are from the old golang.org/x/exp/winfsnotify, where you could +// add various options to the watch. This has long since been removed. +// +// The "sys" in the name is misleading as they're not part of any "system". +// +// This should all be removed at some point, and just use windows.FILE_NOTIFY_* +const ( + sysFSALLEVENTS = 0xfff + sysFSATTRIB = 0x4 + sysFSCREATE = 0x100 + sysFSDELETE = 0x200 + sysFSDELETESELF = 0x400 + sysFSMODIFY = 0x2 + sysFSMOVE = 0xc0 + sysFSMOVEDFROM = 0x40 + sysFSMOVEDTO = 0x80 + sysFSMOVESELF = 0x800 + sysFSIGNORED = 0x8000 +) + +func (w *Watcher) newEvent(name string, mask uint32) Event { + e := Event{Name: name} + if mask&sysFSCREATE == sysFSCREATE || mask&sysFSMOVEDTO == sysFSMOVEDTO { + e.Op |= Create + } + if mask&sysFSDELETE == sysFSDELETE || mask&sysFSDELETESELF == sysFSDELETESELF { + e.Op |= Remove + } + if mask&sysFSMODIFY == sysFSMODIFY { + e.Op |= Write + } + if mask&sysFSMOVE == sysFSMOVE || mask&sysFSMOVESELF == sysFSMOVESELF || mask&sysFSMOVEDFROM == sysFSMOVEDFROM { + e.Op |= Rename + } + if mask&sysFSATTRIB == sysFSATTRIB { + e.Op |= Chmod + } + return e +} + +const ( + opAddWatch = iota + opRemoveWatch +) + +const ( + provisional uint64 = 1 << (32 + iota) +) + +type input struct { + op int + path string + flags uint32 + reply chan error +} + +type inode struct { + handle windows.Handle + volume uint32 + index uint64 +} + +type watch struct { + ov windows.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 [65536]byte // 64K buffer +} + +type ( + indexMap map[uint64]*watch + watchMap map[uint32]indexMap +) + +func (w *Watcher) wakeupReader() error { + err := windows.PostQueuedCompletionStatus(w.port, 0, 0, nil) + if err != nil { + return os.NewSyscallError("PostQueuedCompletionStatus", err) + } + return nil +} + +func (w *Watcher) getDir(pathname string) (dir string, err error) { + attr, err := windows.GetFileAttributes(windows.StringToUTF16Ptr(pathname)) + if err != nil { + return "", os.NewSyscallError("GetFileAttributes", err) + } + if attr&windows.FILE_ATTRIBUTE_DIRECTORY != 0 { + dir = pathname + } else { + dir, _ = filepath.Split(pathname) + dir = filepath.Clean(dir) + } + return +} + +func (w *Watcher) getIno(path string) (ino *inode, err error) { + h, err := windows.CreateFile(windows.StringToUTF16Ptr(path), + windows.FILE_LIST_DIRECTORY, + windows.FILE_SHARE_READ|windows.FILE_SHARE_WRITE|windows.FILE_SHARE_DELETE, + nil, windows.OPEN_EXISTING, + windows.FILE_FLAG_BACKUP_SEMANTICS|windows.FILE_FLAG_OVERLAPPED, 0) + if err != nil { + return nil, os.NewSyscallError("CreateFile", err) + } + + var fi windows.ByHandleFileInformation + err = windows.GetFileInformationByHandle(h, &fi) + if err != nil { + windows.CloseHandle(h) + return nil, os.NewSyscallError("GetFileInformationByHandle", err) + } + ino = &inode{ + handle: h, + volume: fi.VolumeSerialNumber, + index: uint64(fi.FileIndexHigh)<<32 | uint64(fi.FileIndexLow), + } + return ino, nil +} + +// Must run within the I/O thread. +func (m watchMap) get(ino *inode) *watch { + if i := m[ino.volume]; i != nil { + return i[ino.index] + } + return nil +} + +// Must run within the I/O thread. +func (m watchMap) set(ino *inode, watch *watch) { + i := m[ino.volume] + if i == nil { + i = make(indexMap) + m[ino.volume] = i + } + i[ino.index] = watch +} + +// Must run within the I/O thread. +func (w *Watcher) addWatch(pathname string, flags uint64) error { + dir, err := w.getDir(pathname) + if err != nil { + return err + } + + ino, err := w.getIno(dir) + if err != nil { + return err + } + w.mu.Lock() + watchEntry := w.watches.get(ino) + w.mu.Unlock() + if watchEntry == nil { + _, err := windows.CreateIoCompletionPort(ino.handle, w.port, 0, 0) + if err != nil { + windows.CloseHandle(ino.handle) + return os.NewSyscallError("CreateIoCompletionPort", err) + } + watchEntry = &watch{ + ino: ino, + path: dir, + names: make(map[string]uint64), + } + w.mu.Lock() + w.watches.set(ino, watchEntry) + w.mu.Unlock() + flags |= provisional + } else { + windows.CloseHandle(ino.handle) + } + if pathname == dir { + watchEntry.mask |= flags + } else { + watchEntry.names[filepath.Base(pathname)] |= flags + } + + err = w.startRead(watchEntry) + if err != nil { + return err + } + + if pathname == dir { + watchEntry.mask &= ^provisional + } else { + watchEntry.names[filepath.Base(pathname)] &= ^provisional + } + return nil +} + +// Must run within the I/O thread. +func (w *Watcher) remWatch(pathname string) error { + dir, err := w.getDir(pathname) + if err != nil { + return err + } + ino, err := w.getIno(dir) + if err != nil { + return err + } + + w.mu.Lock() + watch := w.watches.get(ino) + w.mu.Unlock() + + err = windows.CloseHandle(ino.handle) + if err != nil { + w.sendError(os.NewSyscallError("CloseHandle", err)) + } + if watch == nil { + return fmt.Errorf("%w: %s", ErrNonExistentWatch, pathname) + } + if pathname == dir { + w.sendEvent(watch.path, watch.mask&sysFSIGNORED) + watch.mask = 0 + } else { + name := filepath.Base(pathname) + w.sendEvent(filepath.Join(watch.path, name), watch.names[name]&sysFSIGNORED) + delete(watch.names, name) + } + + return w.startRead(watch) +} + +// Must run within the I/O thread. +func (w *Watcher) deleteWatch(watch *watch) { + for name, mask := range watch.names { + if mask&provisional == 0 { + w.sendEvent(filepath.Join(watch.path, name), mask&sysFSIGNORED) + } + delete(watch.names, name) + } + if watch.mask != 0 { + if watch.mask&provisional == 0 { + w.sendEvent(watch.path, watch.mask&sysFSIGNORED) + } + watch.mask = 0 + } +} + +// Must run within the I/O thread. +func (w *Watcher) startRead(watch *watch) error { + err := windows.CancelIo(watch.ino.handle) + if err != nil { + w.sendError(os.NewSyscallError("CancelIo", err)) + w.deleteWatch(watch) + } + mask := w.toWindowsFlags(watch.mask) + for _, m := range watch.names { + mask |= w.toWindowsFlags(m) + } + if mask == 0 { + err := windows.CloseHandle(watch.ino.handle) + if err != nil { + w.sendError(os.NewSyscallError("CloseHandle", err)) + } + w.mu.Lock() + delete(w.watches[watch.ino.volume], watch.ino.index) + w.mu.Unlock() + return nil + } + + rdErr := windows.ReadDirectoryChanges(watch.ino.handle, &watch.buf[0], + uint32(unsafe.Sizeof(watch.buf)), false, mask, nil, &watch.ov, 0) + if rdErr != nil { + err := os.NewSyscallError("ReadDirectoryChanges", rdErr) + if rdErr == windows.ERROR_ACCESS_DENIED && watch.mask&provisional == 0 { + // Watched directory was probably removed + w.sendEvent(watch.path, watch.mask&sysFSDELETESELF) + err = nil + } + w.deleteWatch(watch) + w.startRead(watch) + return err + } + return nil +} + +// readEvents reads from the I/O completion port, converts the +// received events into Event objects and sends them via the Events channel. +// Entry point to the I/O thread. +func (w *Watcher) readEvents() { + var ( + n uint32 + key uintptr + ov *windows.Overlapped + ) + runtime.LockOSThread() + + for { + qErr := windows.GetQueuedCompletionStatus(w.port, &n, &key, &ov, windows.INFINITE) + // This error is handled after the watch == nil check below. NOTE: this + // seems odd, note sure if it's correct. + + watch := (*watch)(unsafe.Pointer(ov)) + if watch == nil { + select { + case ch := <-w.quit: + w.mu.Lock() + var indexes []indexMap + for _, index := range w.watches { + indexes = append(indexes, index) + } + w.mu.Unlock() + for _, index := range indexes { + for _, watch := range index { + w.deleteWatch(watch) + w.startRead(watch) + } + } + + err := windows.CloseHandle(w.port) + if err != nil { + err = os.NewSyscallError("CloseHandle", err) + } + close(w.Events) + close(w.Errors) + ch <- err + return + case in := <-w.input: + switch in.op { + case opAddWatch: + in.reply <- w.addWatch(in.path, uint64(in.flags)) + case opRemoveWatch: + in.reply <- w.remWatch(in.path) + } + default: + } + continue + } + + switch qErr { + case windows.ERROR_MORE_DATA: + if watch == nil { + w.sendError(errors.New("ERROR_MORE_DATA has unexpectedly null lpOverlapped buffer")) + } else { + // The i/o succeeded but the buffer is full. + // In theory we should be building up a full packet. + // In practice we can get away with just carrying on. + n = uint32(unsafe.Sizeof(watch.buf)) + } + case windows.ERROR_ACCESS_DENIED: + // Watched directory was probably removed + w.sendEvent(watch.path, watch.mask&sysFSDELETESELF) + w.deleteWatch(watch) + w.startRead(watch) + continue + case windows.ERROR_OPERATION_ABORTED: + // CancelIo was called on this handle + continue + default: + w.sendError(os.NewSyscallError("GetQueuedCompletionPort", qErr)) + continue + case nil: + } + + var offset uint32 + for { + if n == 0 { + w.sendError(errors.New("short read in readEvents()")) + break + } + + // Point "raw" to the event in the buffer + raw := (*windows.FileNotifyInformation)(unsafe.Pointer(&watch.buf[offset])) + + // Create a buf that is the size of the path name + size := int(raw.FileNameLength / 2) + var buf []uint16 + // TODO: Use unsafe.Slice in Go 1.17; https://stackoverflow.com/questions/51187973 + sh := (*reflect.SliceHeader)(unsafe.Pointer(&buf)) + sh.Data = uintptr(unsafe.Pointer(&raw.FileName)) + sh.Len = size + sh.Cap = size + name := windows.UTF16ToString(buf) + fullname := filepath.Join(watch.path, name) + + var mask uint64 + switch raw.Action { + case windows.FILE_ACTION_REMOVED: + mask = sysFSDELETESELF + case windows.FILE_ACTION_MODIFIED: + mask = sysFSMODIFY + case windows.FILE_ACTION_RENAMED_OLD_NAME: + watch.rename = name + case windows.FILE_ACTION_RENAMED_NEW_NAME: + // Update saved path of all sub-watches. + old := filepath.Join(watch.path, watch.rename) + w.mu.Lock() + for _, watchMap := range w.watches { + for _, ww := range watchMap { + if strings.HasPrefix(ww.path, old) { + ww.path = filepath.Join(fullname, strings.TrimPrefix(ww.path, old)) + } + } + } + w.mu.Unlock() + + if watch.names[watch.rename] != 0 { + watch.names[name] |= watch.names[watch.rename] + delete(watch.names, watch.rename) + mask = sysFSMOVESELF + } + } + + sendNameEvent := func() { + w.sendEvent(fullname, watch.names[name]&mask) + } + if raw.Action != windows.FILE_ACTION_RENAMED_NEW_NAME { + sendNameEvent() + } + if raw.Action == windows.FILE_ACTION_REMOVED { + w.sendEvent(fullname, watch.names[name]&sysFSIGNORED) + delete(watch.names, name) + } + + w.sendEvent(fullname, watch.mask&w.toFSnotifyFlags(raw.Action)) + if raw.Action == windows.FILE_ACTION_RENAMED_NEW_NAME { + fullname = filepath.Join(watch.path, watch.rename) + sendNameEvent() + } + + // Move to the next event in the buffer + if raw.NextEntryOffset == 0 { + break + } + offset += raw.NextEntryOffset + + // Error! + if offset >= n { + w.sendError(errors.New( + "Windows system assumed buffer larger than it is, events have likely been missed.")) + break + } + } + + if err := w.startRead(watch); err != nil { + w.sendError(err) + } + } +} + +func (w *Watcher) toWindowsFlags(mask uint64) uint32 { + var m uint32 + if mask&sysFSMODIFY != 0 { + m |= windows.FILE_NOTIFY_CHANGE_LAST_WRITE + } + if mask&sysFSATTRIB != 0 { + m |= windows.FILE_NOTIFY_CHANGE_ATTRIBUTES + } + if mask&(sysFSMOVE|sysFSCREATE|sysFSDELETE) != 0 { + m |= windows.FILE_NOTIFY_CHANGE_FILE_NAME | windows.FILE_NOTIFY_CHANGE_DIR_NAME + } + return m +} + +func (w *Watcher) toFSnotifyFlags(action uint32) uint64 { + switch action { + case windows.FILE_ACTION_ADDED: + return sysFSCREATE + case windows.FILE_ACTION_REMOVED: + return sysFSDELETE + case windows.FILE_ACTION_MODIFIED: + return sysFSMODIFY + case windows.FILE_ACTION_RENAMED_OLD_NAME: + return sysFSMOVEDFROM + case windows.FILE_ACTION_RENAMED_NEW_NAME: + return sysFSMOVEDTO + } + return 0 +} diff --git a/vendor/github.com/fsnotify/fsnotify/fsnotify.go b/vendor/github.com/fsnotify/fsnotify/fsnotify.go new file mode 100644 index 0000000000..30a5bf0f07 --- /dev/null +++ b/vendor/github.com/fsnotify/fsnotify/fsnotify.go @@ -0,0 +1,81 @@ +//go:build !plan9 +// +build !plan9 + +// Package fsnotify provides a cross-platform interface for file system +// notifications. +package fsnotify + +import ( + "errors" + "fmt" + "strings" +) + +// Event represents a file system notification. +type Event struct { + // Path to the file or directory. + // + // Paths are relative to the input; for example with Add("dir") the Name + // will be set to "dir/file" if you create that file, but if you use + // Add("/path/to/dir") it will be "/path/to/dir/file". + Name string + + // File operation that triggered the event. + // + // This is a bitmask and some systems may send multiple operations at once. + // Use the Event.Has() method instead of comparing with ==. + Op Op +} + +// Op describes a set of file operations. +type Op uint32 + +// The operations fsnotify can trigger; see the documentation on [Watcher] for a +// full description, and check them with [Event.Has]. +const ( + Create Op = 1 << iota + Write + Remove + Rename + Chmod +) + +// Common errors that can be reported by a watcher +var ( + ErrNonExistentWatch = errors.New("can't remove non-existent watcher") + ErrEventOverflow = errors.New("fsnotify queue overflow") +) + +func (op Op) String() string { + var b strings.Builder + if op.Has(Create) { + b.WriteString("|CREATE") + } + if op.Has(Remove) { + b.WriteString("|REMOVE") + } + if op.Has(Write) { + b.WriteString("|WRITE") + } + if op.Has(Rename) { + b.WriteString("|RENAME") + } + if op.Has(Chmod) { + b.WriteString("|CHMOD") + } + if b.Len() == 0 { + return "[no events]" + } + return b.String()[1:] +} + +// Has reports if this operation has the given operation. +func (o Op) Has(h Op) bool { return o&h == h } + +// Has reports if this event has the given operation. +func (e Event) Has(op Op) bool { return e.Op.Has(op) } + +// String returns a string representation of the event with their path. +func (e Event) String() string { + return fmt.Sprintf("%-13s %q", e.Op.String(), e.Name) +} diff --git a/vendor/github.com/fsnotify/fsnotify/mkdoc.zsh b/vendor/github.com/fsnotify/fsnotify/mkdoc.zsh new file mode 100644 index 0000000000..b09ef76834 --- /dev/null +++ b/vendor/github.com/fsnotify/fsnotify/mkdoc.zsh @@ -0,0 +1,208 @@ +#!/usr/bin/env zsh +[ "${ZSH_VERSION:-}" = "" ] && echo >&2 "Only works with zsh" && exit 1 +setopt err_exit no_unset pipefail extended_glob + +# Simple script to update the godoc comments on all watchers. Probably took me +# more time to write this than doing it manually, but ah well 🙃 + +watcher=$(</tmp/x + print -r -- $cmt >>/tmp/x + tail -n+$(( end + 1 )) $file >>/tmp/x + mv /tmp/x $file + done +} + +set-cmt '^type Watcher struct ' $watcher +set-cmt '^func NewWatcher(' $new +set-cmt '^func (w \*Watcher) Add(' $add +set-cmt '^func (w \*Watcher) Remove(' $remove +set-cmt '^func (w \*Watcher) Close(' $close +set-cmt '^func (w \*Watcher) WatchList(' $watchlist +set-cmt '^[[:space:]]*Events *chan Event$' $events +set-cmt '^[[:space:]]*Errors *chan error$' $errors diff --git a/vendor/github.com/fsnotify/fsnotify/system_bsd.go b/vendor/github.com/fsnotify/fsnotify/system_bsd.go new file mode 100644 index 0000000000..4322b0b885 --- /dev/null +++ b/vendor/github.com/fsnotify/fsnotify/system_bsd.go @@ -0,0 +1,8 @@ +//go:build freebsd || openbsd || netbsd || dragonfly +// +build freebsd openbsd netbsd dragonfly + +package fsnotify + +import "golang.org/x/sys/unix" + +const openMode = unix.O_NONBLOCK | unix.O_RDONLY | unix.O_CLOEXEC diff --git a/vendor/github.com/fsnotify/fsnotify/system_darwin.go b/vendor/github.com/fsnotify/fsnotify/system_darwin.go new file mode 100644 index 0000000000..5da5ffa78f --- /dev/null +++ b/vendor/github.com/fsnotify/fsnotify/system_darwin.go @@ -0,0 +1,9 @@ +//go:build darwin +// +build darwin + +package fsnotify + +import "golang.org/x/sys/unix" + +// note: this constant is not defined on BSD +const openMode = unix.O_EVTONLY | unix.O_CLOEXEC diff --git a/vendor/github.com/rjeczalik/notify/.gitignore b/vendor/github.com/rjeczalik/notify/.gitignore deleted file mode 100644 index 32c6eb987a..0000000000 --- a/vendor/github.com/rjeczalik/notify/.gitignore +++ /dev/null @@ -1,92 +0,0 @@ -# Created by https://www.gitignore.io - -### OSX ### -.DS_Store -.AppleDouble -.LSOverride - -# Icon must end with two \r -Icon - - -# Thumbnails -._* - -# Files that might appear on external disk -.Spotlight-V100 -.Trashes - -# Directories potentially created on remote AFP share -.AppleDB -.AppleDesktop -Network Trash Folder -Temporary Items -.apdisk - - -### Windows ### -# Windows image file caches -Thumbs.db -ehthumbs.db - -# Folder config file -Desktop.ini - -# Recycle Bin used on file shares -$RECYCLE.BIN/ - -# Windows Installer files -*.cab -*.msi -*.msm -*.msp - -# Windows shortcuts -*.lnk - - -### Linux ### -*~ - -# KDE directory preferences -.directory - - -### Go ### -# Compiled Object files, Static and Dynamic libs (Shared Objects) -*.o -*.a -*.so - -# Folders -_obj -_test - -# Architecture specific extensions/prefixes -*.[568vq] -[568vq].out - -*.cgo1.go -*.cgo2.c -_cgo_defun.c -_cgo_gotypes.go -_cgo_export.* - -_testmain.go - -*.exe -*.test -*.prof - - -### vim ### -[._]*.s[a-w][a-z] -[._]s[a-w][a-z] -*.un~ -Session.vim -.netrwhist -*~ - -### JetBrains files ### -.idea/ -*.iml \ No newline at end of file diff --git a/vendor/github.com/rjeczalik/notify/.travis.yml b/vendor/github.com/rjeczalik/notify/.travis.yml deleted file mode 100644 index 720f6613c3..0000000000 --- a/vendor/github.com/rjeczalik/notify/.travis.yml +++ /dev/null @@ -1,32 +0,0 @@ -language: go - -go: - - 1.10.x - - 1.11.x - - master - -os: - - linux - - osx - -matrix: - include: - - os: osx - go: 1.7.5 - env: - - GOFLAGS="-tags kqueue" - allow_failures: - - go: tip - -env: - global: - - GOBIN=$HOME/bin - - PATH=$HOME/bin:$PATH - -install: - - go get -t -v ./... - -script: - - "(go version | grep -q 1.4) || go tool vet -all ." - - go install $GOFLAGS ./... - - go test -v -timeout 60s -race $GOFLAGS ./... diff --git a/vendor/github.com/rjeczalik/notify/AUTHORS b/vendor/github.com/rjeczalik/notify/AUTHORS deleted file mode 100644 index 9262eae69d..0000000000 --- a/vendor/github.com/rjeczalik/notify/AUTHORS +++ /dev/null @@ -1,10 +0,0 @@ -# List of individuals who contributed to the Notify package. -# -# The up-to-date list of the authors one may obtain with: -# -# ~ $ git shortlog -es | cut -f2 | rev | uniq -f1 | rev -# - -Pawel Blaszczyk -Pawel Knap -Rafal Jeczalik diff --git a/vendor/github.com/rjeczalik/notify/LICENSE b/vendor/github.com/rjeczalik/notify/LICENSE deleted file mode 100644 index 3e678817bf..0000000000 --- a/vendor/github.com/rjeczalik/notify/LICENSE +++ /dev/null @@ -1,21 +0,0 @@ -The MIT License (MIT) - -Copyright (c) 2014-2015 The Notify Authors - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. diff --git a/vendor/github.com/rjeczalik/notify/README.md b/vendor/github.com/rjeczalik/notify/README.md deleted file mode 100644 index 0ff880e361..0000000000 --- a/vendor/github.com/rjeczalik/notify/README.md +++ /dev/null @@ -1,23 +0,0 @@ -notify [![GoDoc](https://godoc.org/github.com/rjeczalik/notify?status.svg)](https://godoc.org/github.com/rjeczalik/notify) [![Build Status](https://img.shields.io/travis/rjeczalik/notify/master.svg)](https://travis-ci.org/rjeczalik/notify "inotify + FSEvents + kqueue") [![Build status](https://img.shields.io/appveyor/ci/rjeczalik/notify-246.svg)](https://ci.appveyor.com/project/rjeczalik/notify-246 "ReadDirectoryChangesW") [![Coverage Status](https://img.shields.io/coveralls/rjeczalik/notify/master.svg)](https://coveralls.io/r/rjeczalik/notify?branch=master) -====== - -Filesystem event notification library on steroids. (under active development) - -*Documentation* - -[godoc.org/github.com/rjeczalik/notify](https://godoc.org/github.com/rjeczalik/notify) - -*Installation* - -``` -~ $ go get -u github.com/rjeczalik/notify -``` - -*Projects using notify* - -- [github.com/rjeczalik/cmd/notify](https://godoc.org/github.com/rjeczalik/cmd/notify) -- [github.com/cortesi/devd](https://github.com/cortesi/devd) -- [github.com/cortesi/modd](https://github.com/cortesi/modd) -- [github.com/syncthing/syncthing](https://github.com/syncthing/syncthing) -- [github.com/OrlovEvgeny/TinyJPG](https://github.com/OrlovEvgeny/TinyJPG) -- [github.com/mitranim/gow](https://github.com/mitranim/gow) diff --git a/vendor/github.com/rjeczalik/notify/appveyor.yml b/vendor/github.com/rjeczalik/notify/appveyor.yml deleted file mode 100644 index a0bdc37a38..0000000000 --- a/vendor/github.com/rjeczalik/notify/appveyor.yml +++ /dev/null @@ -1,27 +0,0 @@ -version: "{build}" - -os: Windows Server 2012 R2 - -clone_folder: c:\projects\src\github.com\rjeczalik\notify - -environment: - PATH: c:\projects\bin;%PATH% - GOPATH: c:\projects - NOTIFY_TIMEOUT: 10s - GOVERSION: 1.10.3 - -install: - - rmdir c:\go /s /q - - appveyor DownloadFile https://storage.googleapis.com/golang/go%GOVERSION%.windows-amd64.zip - - 7z x go%GOVERSION%.windows-amd64.zip -y -oC:\ > NUL - - - cd %APPVEYOR_BUILD_FOLDER% - - go version - -build_script: - - go build ./... - - go test -v -timeout 120s -race ./... - -test: off - -deploy: off diff --git a/vendor/github.com/rjeczalik/notify/debug.go b/vendor/github.com/rjeczalik/notify/debug.go deleted file mode 100644 index 2a3eb33700..0000000000 --- a/vendor/github.com/rjeczalik/notify/debug.go +++ /dev/null @@ -1,53 +0,0 @@ -// Copyright (c) 2014-2015 The Notify Authors. All rights reserved. -// Use of this source code is governed by the MIT license that can be -// found in the LICENSE file. - -package notify - -import ( - "log" - "os" - "runtime" - "strings" -) - -var dbgprint func(...interface{}) - -var dbgprintf func(string, ...interface{}) - -var dbgcallstack func(max int) []string - -func init() { - if _, ok := os.LookupEnv("NOTIFY_DEBUG"); ok || debugTag { - log.SetOutput(os.Stdout) - log.SetFlags(log.Ldate | log.Ltime | log.Lmicroseconds) - dbgprint = func(v ...interface{}) { - v = append([]interface{}{"[D] "}, v...) - log.Println(v...) - } - dbgprintf = func(format string, v ...interface{}) { - format = "[D] " + format - log.Printf(format, v...) - } - dbgcallstack = func(max int) []string { - pc, stack := make([]uintptr, max), make([]string, 0, max) - runtime.Callers(2, pc) - for _, pc := range pc { - if f := runtime.FuncForPC(pc); f != nil { - fname := f.Name() - idx := strings.LastIndex(fname, string(os.PathSeparator)) - if idx != -1 { - stack = append(stack, fname[idx+1:]) - } else { - stack = append(stack, fname) - } - } - } - return stack - } - return - } - dbgprint = func(v ...interface{}) {} - dbgprintf = func(format string, v ...interface{}) {} - dbgcallstack = func(max int) []string { return nil } -} diff --git a/vendor/github.com/rjeczalik/notify/debug_debug.go b/vendor/github.com/rjeczalik/notify/debug_debug.go deleted file mode 100644 index e64128975a..0000000000 --- a/vendor/github.com/rjeczalik/notify/debug_debug.go +++ /dev/null @@ -1,10 +0,0 @@ -// Copyright (c) 2014-2018 The Notify Authors. All rights reserved. -// Use of this source code is governed by the MIT license that can be -// found in the LICENSE file. - -//go:build debug -// +build debug - -package notify - -var debugTag = true diff --git a/vendor/github.com/rjeczalik/notify/debug_nodebug.go b/vendor/github.com/rjeczalik/notify/debug_nodebug.go deleted file mode 100644 index 724fe7aa9d..0000000000 --- a/vendor/github.com/rjeczalik/notify/debug_nodebug.go +++ /dev/null @@ -1,10 +0,0 @@ -// Copyright (c) 2014-2018 The Notify Authors. All rights reserved. -// Use of this source code is governed by the MIT license that can be -// found in the LICENSE file. - -//go:build !debug -// +build !debug - -package notify - -var debugTag = false diff --git a/vendor/github.com/rjeczalik/notify/doc.go b/vendor/github.com/rjeczalik/notify/doc.go deleted file mode 100644 index 60543c0838..0000000000 --- a/vendor/github.com/rjeczalik/notify/doc.go +++ /dev/null @@ -1,43 +0,0 @@ -// Copyright (c) 2014-2015 The Notify Authors. All rights reserved. -// Use of this source code is governed by the MIT license that can be -// found in the LICENSE file. - -// Package notify implements access to filesystem events. -// -// Notify is a high-level abstraction over filesystem watchers like inotify, -// kqueue, FSEvents, FEN or ReadDirectoryChangesW. Watcher implementations are -// split into two groups: ones that natively support recursive notifications -// (FSEvents and ReadDirectoryChangesW) and ones that do not (inotify, kqueue, FEN). -// For more details see watcher and recursiveWatcher interfaces in watcher.go -// source file. -// -// On top of filesystem watchers notify maintains a watchpoint tree, which provides -// a strategy for creating and closing filesystem watches and dispatching filesystem -// events to user channels. -// -// An event set is just an event list joint using bitwise OR operator -// into a single event value. -// Both the platform-independent (see Constants) and specific events can be used. -// Refer to the event_*.go source files for information about the available -// events. -// -// A filesystem watch or just a watch is platform-specific entity which represents -// a single path registered for notifications for specific event set. Setting a watch -// means using platform-specific API calls for creating / initializing said watch. -// For each watcher the API call is: -// -// - FSEvents: FSEventStreamCreate -// - inotify: notify_add_watch -// - kqueue: kevent -// - ReadDirectoryChangesW: CreateFile+ReadDirectoryChangesW -// - FEN: port_get -// -// To rewatch means to either shrink or expand an event set that was previously -// registered during watch operation for particular filesystem watch. -// -// A watchpoint is a list of user channel and event set pairs for particular -// path (watchpoint tree's node). A single watchpoint can contain multiple -// different user channels registered to listen for one or more events. A single -// user channel can be registered in one or more watchpoints, recursive and -// non-recursive ones as well. -package notify diff --git a/vendor/github.com/rjeczalik/notify/event.go b/vendor/github.com/rjeczalik/notify/event.go deleted file mode 100644 index 4b4b10220b..0000000000 --- a/vendor/github.com/rjeczalik/notify/event.go +++ /dev/null @@ -1,143 +0,0 @@ -// Copyright (c) 2014-2015 The Notify Authors. All rights reserved. -// Use of this source code is governed by the MIT license that can be -// found in the LICENSE file. - -package notify - -import ( - "fmt" - "strings" -) - -// Event represents the type of filesystem action. -// -// Number of available event values is dependent on the target system or the -// watcher implmenetation used (e.g. it's possible to use either kqueue or -// FSEvents on Darwin). -// -// Please consult documentation for your target platform to see list of all -// available events. -type Event uint32 - -// Create, Remove, Write and Rename are the only event values guaranteed to be -// present on all platforms. -const ( - Create = osSpecificCreate - Remove = osSpecificRemove - Write = osSpecificWrite - Rename = osSpecificRename - - // All is handful alias for all platform-independent event values. - All = Create | Remove | Write | Rename -) - -const internal = recursive | omit - -// String implements fmt.Stringer interface. -func (e Event) String() string { - var s []string - for _, strmap := range []map[Event]string{estr, osestr} { - for ev, str := range strmap { - if e&ev == ev { - s = append(s, str) - } - } - } - return strings.Join(s, "|") -} - -// EventInfo describes an event reported by the underlying filesystem notification -// subsystem. -// -// It always describes single event, even if the OS reported a coalesced action. -// Reported path is absolute and clean. -// -// For non-recursive watchpoints its base is always equal to the path passed -// to corresponding Watch call. -// -// The value of Sys if system-dependent and can be nil. -// -// # Sys -// -// Under Darwin (FSEvents) Sys() always returns a non-nil *notify.FSEvent value, -// which is defined as: -// -// type FSEvent struct { -// Path string // real path of the file or directory -// ID uint64 // ID of the event (FSEventStreamEventId) -// Flags uint32 // joint FSEvents* flags (FSEventStreamEventFlags) -// } -// -// For possible values of Flags see Darwin godoc for notify or FSEvents -// documentation for FSEventStreamEventFlags constants: -// -// https://developer.apple.com/library/mac/documentation/Darwin/Reference/FSEvents_Ref/index.html#//apple_ref/doc/constant_group/FSEventStreamEventFlags -// -// Under Linux (inotify) Sys() always returns a non-nil *unix.InotifyEvent -// value, defined as: -// -// type InotifyEvent struct { -// Wd int32 // Watch descriptor -// Mask uint32 // Mask describing event -// Cookie uint32 // Unique cookie associating related events (for rename(2)) -// Len uint32 // Size of name field -// Name [0]uint8 // Optional null-terminated name -// } -// -// More information about inotify masks and the usage of inotify_event structure -// can be found at: -// -// http://man7.org/linux/man-pages/man7/inotify.7.html -// -// Under Darwin, DragonFlyBSD, FreeBSD, NetBSD, OpenBSD (kqueue) Sys() always -// returns a non-nil *notify.Kevent value, which is defined as: -// -// type Kevent struct { -// Kevent *syscall.Kevent_t // Kevent is a kqueue specific structure -// FI os.FileInfo // FI describes file/dir -// } -// -// More information about syscall.Kevent_t can be found at: -// -// https://www.freebsd.org/cgi/man.cgi?query=kqueue -// -// Under Windows (ReadDirectoryChangesW) Sys() always returns nil. The documentation -// of watcher's WinAPI function can be found at: -// -// https://msdn.microsoft.com/en-us/library/windows/desktop/aa365465%28v=vs.85%29.aspx -type EventInfo interface { - Event() Event // event value for the filesystem action - Path() string // real path of the file or directory - Sys() interface{} // underlying data source (can return nil) -} - -type isDirer interface { - isDir() (bool, error) -} - -var _ fmt.Stringer = (*event)(nil) -var _ isDirer = (*event)(nil) - -// String implements fmt.Stringer interface. -func (e *event) String() string { - return e.Event().String() + `: "` + e.Path() + `"` -} - -var estr = map[Event]string{ - Create: "notify.Create", - Remove: "notify.Remove", - Write: "notify.Write", - Rename: "notify.Rename", - // Display name for recursive event is added only for debugging - // purposes. It's an internal event after all and won't be exposed to the - // user. Having Recursive event printable is helpful, e.g. for reading - // testing failure messages: - // - // --- FAIL: TestWatchpoint (0.00 seconds) - // watchpoint_test.go:64: want diff=[notify.Remove notify.Create|notify.Remove]; - // got [notify.Remove notify.Remove|notify.Create] (i=1) - // - // Yup, here the diff have Recursive event inside. Go figure. - recursive: "recursive", - omit: "omit", -} diff --git a/vendor/github.com/rjeczalik/notify/event_fen.go b/vendor/github.com/rjeczalik/notify/event_fen.go deleted file mode 100644 index 1be3922d56..0000000000 --- a/vendor/github.com/rjeczalik/notify/event_fen.go +++ /dev/null @@ -1,58 +0,0 @@ -// Copyright (c) 2014-2015 The Notify Authors. All rights reserved. -// Use of this source code is governed by the MIT license that can be -// found in the LICENSE file. - -//go:build solaris || illumos -// +build solaris illumos - -package notify - -const ( - osSpecificCreate Event = 0x00000100 << iota - osSpecificRemove - osSpecificWrite - osSpecificRename - // internal - // recursive is used to distinguish recursive eventsets from non-recursive ones - recursive - // omit is used for dispatching internal events; only those events are sent - // for which both the event and the watchpoint has omit in theirs event sets. - omit -) - -const ( - // FileAccess is an event reported when monitored file/directory was accessed. - FileAccess = fileAccess - // FileModified is an event reported when monitored file/directory was modified. - FileModified = fileModified - // FileAttrib is an event reported when monitored file/directory's ATTRIB - // was changed. - FileAttrib = fileAttrib - // FileDelete is an event reported when monitored file/directory was deleted. - FileDelete = fileDelete - // FileRenameTo to is an event reported when monitored file/directory was renamed. - FileRenameTo = fileRenameTo - // FileRenameFrom is an event reported when monitored file/directory was renamed. - FileRenameFrom = fileRenameFrom - // FileTrunc is an event reported when monitored file/directory was truncated. - FileTrunc = fileTrunc - // FileNoFollow is an flag to indicate not to follow symbolic links. - FileNoFollow = fileNoFollow - // Unmounted is an event reported when monitored filesystem was unmounted. - Unmounted = unmounted - // MountedOver is an event reported when monitored file/directory was mounted on. - MountedOver = mountedOver -) - -var osestr = map[Event]string{ - FileAccess: "notify.FileAccess", - FileModified: "notify.FileModified", - FileAttrib: "notify.FileAttrib", - FileDelete: "notify.FileDelete", - FileRenameTo: "notify.FileRenameTo", - FileRenameFrom: "notify.FileRenameFrom", - FileTrunc: "notify.FileTrunc", - FileNoFollow: "notify.FileNoFollow", - Unmounted: "notify.Unmounted", - MountedOver: "notify.MountedOver", -} diff --git a/vendor/github.com/rjeczalik/notify/event_fsevents.go b/vendor/github.com/rjeczalik/notify/event_fsevents.go deleted file mode 100644 index c3edfec8df..0000000000 --- a/vendor/github.com/rjeczalik/notify/event_fsevents.go +++ /dev/null @@ -1,72 +0,0 @@ -// Copyright (c) 2014-2015 The Notify Authors. All rights reserved. -// Use of this source code is governed by the MIT license that can be -// found in the LICENSE file. - -//go:build darwin && !kqueue && cgo -// +build darwin,!kqueue,cgo - -package notify - -const ( - osSpecificCreate = Event(FSEventsCreated) - osSpecificRemove = Event(FSEventsRemoved) - osSpecificWrite = Event(FSEventsModified) - osSpecificRename = Event(FSEventsRenamed) - // internal = Event(0x100000) - // recursive is used to distinguish recursive eventsets from non-recursive ones - recursive = Event(0x200000) - // omit is used for dispatching internal events; only those events are sent - // for which both the event and the watchpoint has omit in theirs event sets. - omit = Event(0x400000) -) - -// FSEvents specific event values. -const ( - FSEventsMustScanSubDirs Event = 0x00001 - FSEventsUserDropped = 0x00002 - FSEventsKernelDropped = 0x00004 - FSEventsEventIdsWrapped = 0x00008 - FSEventsHistoryDone = 0x00010 - FSEventsRootChanged = 0x00020 - FSEventsMount = 0x00040 - FSEventsUnmount = 0x00080 - FSEventsCreated = 0x00100 - FSEventsRemoved = 0x00200 - FSEventsInodeMetaMod = 0x00400 - FSEventsRenamed = 0x00800 - FSEventsModified = 0x01000 - FSEventsFinderInfoMod = 0x02000 - FSEventsChangeOwner = 0x04000 - FSEventsXattrMod = 0x08000 - FSEventsIsFile = 0x10000 - FSEventsIsDir = 0x20000 - FSEventsIsSymlink = 0x40000 -) - -var osestr = map[Event]string{ - FSEventsMustScanSubDirs: "notify.FSEventsMustScanSubDirs", - FSEventsUserDropped: "notify.FSEventsUserDropped", - FSEventsKernelDropped: "notify.FSEventsKernelDropped", - FSEventsEventIdsWrapped: "notify.FSEventsEventIdsWrapped", - FSEventsHistoryDone: "notify.FSEventsHistoryDone", - FSEventsRootChanged: "notify.FSEventsRootChanged", - FSEventsMount: "notify.FSEventsMount", - FSEventsUnmount: "notify.FSEventsUnmount", - FSEventsInodeMetaMod: "notify.FSEventsInodeMetaMod", - FSEventsFinderInfoMod: "notify.FSEventsFinderInfoMod", - FSEventsChangeOwner: "notify.FSEventsChangeOwner", - FSEventsXattrMod: "notify.FSEventsXattrMod", - FSEventsIsFile: "notify.FSEventsIsFile", - FSEventsIsDir: "notify.FSEventsIsDir", - FSEventsIsSymlink: "notify.FSEventsIsSymlink", -} - -type event struct { - fse FSEvent - event Event -} - -func (ei *event) Event() Event { return ei.event } -func (ei *event) Path() string { return ei.fse.Path } -func (ei *event) Sys() interface{} { return &ei.fse } -func (ei *event) isDir() (bool, error) { return ei.fse.Flags&FSEventsIsDir != 0, nil } diff --git a/vendor/github.com/rjeczalik/notify/event_inotify.go b/vendor/github.com/rjeczalik/notify/event_inotify.go deleted file mode 100644 index cea42ecb3e..0000000000 --- a/vendor/github.com/rjeczalik/notify/event_inotify.go +++ /dev/null @@ -1,76 +0,0 @@ -// Copyright (c) 2014-2015 The Notify Authors. All rights reserved. -// Use of this source code is governed by the MIT license that can be -// found in the LICENSE file. - -//go:build linux -// +build linux - -package notify - -import "golang.org/x/sys/unix" - -// Platform independent event values. -const ( - osSpecificCreate Event = 0x100000 << iota - osSpecificRemove - osSpecificWrite - osSpecificRename - // internal - // recursive is used to distinguish recursive eventsets from non-recursive ones - recursive - // omit is used for dispatching internal events; only those events are sent - // for which both the event and the watchpoint has omit in theirs event sets. - omit -) - -// Inotify specific masks are legal, implemented events that are guaranteed to -// work with notify package on linux-based systems. -const ( - InAccess = Event(unix.IN_ACCESS) // File was accessed - InModify = Event(unix.IN_MODIFY) // File was modified - InAttrib = Event(unix.IN_ATTRIB) // Metadata changed - InCloseWrite = Event(unix.IN_CLOSE_WRITE) // Writtable file was closed - InCloseNowrite = Event(unix.IN_CLOSE_NOWRITE) // Unwrittable file closed - InOpen = Event(unix.IN_OPEN) // File was opened - InMovedFrom = Event(unix.IN_MOVED_FROM) // File was moved from X - InMovedTo = Event(unix.IN_MOVED_TO) // File was moved to Y - InCreate = Event(unix.IN_CREATE) // Subfile was created - InDelete = Event(unix.IN_DELETE) // Subfile was deleted - InDeleteSelf = Event(unix.IN_DELETE_SELF) // Self was deleted - InMoveSelf = Event(unix.IN_MOVE_SELF) // Self was moved -) - -var osestr = map[Event]string{ - InAccess: "notify.InAccess", - InModify: "notify.InModify", - InAttrib: "notify.InAttrib", - InCloseWrite: "notify.InCloseWrite", - InCloseNowrite: "notify.InCloseNowrite", - InOpen: "notify.InOpen", - InMovedFrom: "notify.InMovedFrom", - InMovedTo: "notify.InMovedTo", - InCreate: "notify.InCreate", - InDelete: "notify.InDelete", - InDeleteSelf: "notify.InDeleteSelf", - InMoveSelf: "notify.InMoveSelf", -} - -// Inotify behavior events are not **currently** supported by notify package. -const ( - inDontFollow = Event(unix.IN_DONT_FOLLOW) - inExclUnlink = Event(unix.IN_EXCL_UNLINK) - inMaskAdd = Event(unix.IN_MASK_ADD) - inOneshot = Event(unix.IN_ONESHOT) - inOnlydir = Event(unix.IN_ONLYDIR) -) - -type event struct { - sys unix.InotifyEvent - path string - event Event -} - -func (e *event) Event() Event { return e.event } -func (e *event) Path() string { return e.path } -func (e *event) Sys() interface{} { return &e.sys } -func (e *event) isDir() (bool, error) { return e.sys.Mask&unix.IN_ISDIR != 0, nil } diff --git a/vendor/github.com/rjeczalik/notify/event_kqueue.go b/vendor/github.com/rjeczalik/notify/event_kqueue.go deleted file mode 100644 index 866118538a..0000000000 --- a/vendor/github.com/rjeczalik/notify/event_kqueue.go +++ /dev/null @@ -1,60 +0,0 @@ -// Copyright (c) 2014-2015 The Notify Authors. All rights reserved. -// Use of this source code is governed by the MIT license that can be -// found in the LICENSE file. - -//go:build (darwin && kqueue) || (darwin && !cgo) || dragonfly || freebsd || netbsd || openbsd -// +build darwin,kqueue darwin,!cgo dragonfly freebsd netbsd openbsd - -package notify - -import "syscall" - -// TODO(pblaszczyk): ensure in runtime notify built-in event values do not -// overlap with platform-defined ones. - -// Platform independent event values. -const ( - osSpecificCreate Event = 0x0100 << iota - osSpecificRemove - osSpecificWrite - osSpecificRename - // internal - // recursive is used to distinguish recursive eventsets from non-recursive ones - recursive - // omit is used for dispatching internal events; only those events are sent - // for which both the event and the watchpoint has omit in theirs event sets. - omit -) - -const ( - // NoteDelete is an event reported when the unlink() system call was called - // on the file referenced by the descriptor. - NoteDelete = Event(syscall.NOTE_DELETE) - // NoteWrite is an event reported when a write occurred on the file - // referenced by the descriptor. - NoteWrite = Event(syscall.NOTE_WRITE) - // NoteExtend is an event reported when the file referenced by the - // descriptor was extended. - NoteExtend = Event(syscall.NOTE_EXTEND) - // NoteAttrib is an event reported when the file referenced - // by the descriptor had its attributes changed. - NoteAttrib = Event(syscall.NOTE_ATTRIB) - // NoteLink is an event reported when the link count on the file changed. - NoteLink = Event(syscall.NOTE_LINK) - // NoteRename is an event reported when the file referenced - // by the descriptor was renamed. - NoteRename = Event(syscall.NOTE_RENAME) - // NoteRevoke is an event reported when access to the file was revoked via - // revoke(2) or the underlying file system was unmounted. - NoteRevoke = Event(syscall.NOTE_REVOKE) -) - -var osestr = map[Event]string{ - NoteDelete: "notify.NoteDelete", - NoteWrite: "notify.NoteWrite", - NoteExtend: "notify.NoteExtend", - NoteAttrib: "notify.NoteAttrib", - NoteLink: "notify.NoteLink", - NoteRename: "notify.NoteRename", - NoteRevoke: "notify.NoteRevoke", -} diff --git a/vendor/github.com/rjeczalik/notify/event_readdcw.go b/vendor/github.com/rjeczalik/notify/event_readdcw.go deleted file mode 100644 index 4ae3a063f6..0000000000 --- a/vendor/github.com/rjeczalik/notify/event_readdcw.go +++ /dev/null @@ -1,119 +0,0 @@ -// Copyright (c) 2014-2015 The Notify Authors. All rights reserved. -// Use of this source code is governed by the MIT license that can be -// found in the LICENSE file. - -//go:build windows -// +build windows - -package notify - -import ( - "os" - "path/filepath" - "syscall" -) - -// Platform independent event values. -const ( - osSpecificCreate Event = 1 << (20 + iota) - osSpecificRemove - osSpecificWrite - osSpecificRename - // recursive is used to distinguish recursive eventsets from non-recursive ones - recursive - // omit is used for dispatching internal events; only those events are sent - // for which both the event and the watchpoint has omit in theirs event sets. - omit - // dirmarker TODO(pknap) - dirmarker -) - -// ReadDirectoryChangesW filters -// On Windows the following events can be passed to Watch. A different set of -// events (see actions below) are received on the channel passed to Watch. -// For more information refer to -// https://msdn.microsoft.com/en-us/library/windows/desktop/aa365465(v=vs.85).aspx -const ( - FileNotifyChangeFileName = Event(syscall.FILE_NOTIFY_CHANGE_FILE_NAME) - FileNotifyChangeDirName = Event(syscall.FILE_NOTIFY_CHANGE_DIR_NAME) - FileNotifyChangeAttributes = Event(syscall.FILE_NOTIFY_CHANGE_ATTRIBUTES) - FileNotifyChangeSize = Event(syscall.FILE_NOTIFY_CHANGE_SIZE) - FileNotifyChangeLastWrite = Event(syscall.FILE_NOTIFY_CHANGE_LAST_WRITE) - FileNotifyChangeLastAccess = Event(syscall.FILE_NOTIFY_CHANGE_LAST_ACCESS) - FileNotifyChangeCreation = Event(syscall.FILE_NOTIFY_CHANGE_CREATION) - FileNotifyChangeSecurity = Event(syscallFileNotifyChangeSecurity) -) - -const ( - fileNotifyChangeAll = 0x17f // logical sum of all FileNotifyChange* events. - fileNotifyChangeModified = fileNotifyChangeAll &^ (FileNotifyChangeFileName | FileNotifyChangeDirName) -) - -// according to: http://msdn.microsoft.com/en-us/library/windows/desktop/aa365465(v=vs.85).aspx -// this flag should be declared in: http://golang.org/src/pkg/syscall/ztypes_windows.go -const syscallFileNotifyChangeSecurity = 0x00000100 - -// ReadDirectoryChangesW actions -// The following events are returned on the channel passed to Watch, but cannot -// be passed to Watch itself (see filters above). You can find a table showing -// the relation between actions and filteres at -// https://github.com/rjeczalik/notify/issues/10#issuecomment-66179535 -// The msdn documentation on actions is part of -// https://msdn.microsoft.com/en-us/library/windows/desktop/aa364391(v=vs.85).aspx -const ( - FileActionAdded = Event(syscall.FILE_ACTION_ADDED) << 12 - FileActionRemoved = Event(syscall.FILE_ACTION_REMOVED) << 12 - FileActionModified = Event(syscall.FILE_ACTION_MODIFIED) << 14 - FileActionRenamedOldName = Event(syscall.FILE_ACTION_RENAMED_OLD_NAME) << 15 - FileActionRenamedNewName = Event(syscall.FILE_ACTION_RENAMED_NEW_NAME) << 16 -) - -const fileActionAll = 0x7f000 // logical sum of all FileAction* events. - -var osestr = map[Event]string{ - FileNotifyChangeFileName: "notify.FileNotifyChangeFileName", - FileNotifyChangeDirName: "notify.FileNotifyChangeDirName", - FileNotifyChangeAttributes: "notify.FileNotifyChangeAttributes", - FileNotifyChangeSize: "notify.FileNotifyChangeSize", - FileNotifyChangeLastWrite: "notify.FileNotifyChangeLastWrite", - FileNotifyChangeLastAccess: "notify.FileNotifyChangeLastAccess", - FileNotifyChangeCreation: "notify.FileNotifyChangeCreation", - FileNotifyChangeSecurity: "notify.FileNotifyChangeSecurity", - - FileActionAdded: "notify.FileActionAdded", - FileActionRemoved: "notify.FileActionRemoved", - FileActionModified: "notify.FileActionModified", - FileActionRenamedOldName: "notify.FileActionRenamedOldName", - FileActionRenamedNewName: "notify.FileActionRenamedNewName", -} - -const ( - fTypeUnknown uint8 = iota - fTypeFile - fTypeDirectory -) - -// TODO(ppknap) : doc. -type event struct { - pathw []uint16 - name string - ftype uint8 - action uint32 - filter uint32 - e Event -} - -func (e *event) Event() Event { return e.e } -func (e *event) Path() string { return filepath.Join(syscall.UTF16ToString(e.pathw), e.name) } -func (e *event) Sys() interface{} { return e.ftype } - -func (e *event) isDir() (bool, error) { - if e.ftype != fTypeUnknown { - return e.ftype == fTypeDirectory, nil - } - fi, err := os.Stat(e.Path()) - if err != nil { - return false, err - } - return fi.IsDir(), nil -} diff --git a/vendor/github.com/rjeczalik/notify/event_stub.go b/vendor/github.com/rjeczalik/notify/event_stub.go deleted file mode 100644 index 68edc7e2ad..0000000000 --- a/vendor/github.com/rjeczalik/notify/event_stub.go +++ /dev/null @@ -1,31 +0,0 @@ -// Copyright (c) 2014-2015 The Notify Authors. All rights reserved. -// Use of this source code is governed by the MIT license that can be -// found in the LICENSE file. - -//go:build !darwin && !linux && !freebsd && !dragonfly && !netbsd && !openbsd && !windows && !kqueue && !solaris && !illumos -// +build !darwin,!linux,!freebsd,!dragonfly,!netbsd,!openbsd,!windows,!kqueue,!solaris,!illumos - -package notify - -// Platform independent event values. -const ( - osSpecificCreate Event = 1 << iota - osSpecificRemove - osSpecificWrite - osSpecificRename - // internal - // recursive is used to distinguish recursive eventsets from non-recursive ones - recursive - // omit is used for dispatching internal events; only those events are sent - // for which both the event and the watchpoint has omit in theirs event sets. - omit -) - -var osestr = map[Event]string{} - -type event struct{} - -func (e *event) Event() (_ Event) { return } -func (e *event) Path() (_ string) { return } -func (e *event) Sys() (_ interface{}) { return } -func (e *event) isDir() (_ bool, _ error) { return } diff --git a/vendor/github.com/rjeczalik/notify/event_trigger.go b/vendor/github.com/rjeczalik/notify/event_trigger.go deleted file mode 100644 index 6d8cd1c3e1..0000000000 --- a/vendor/github.com/rjeczalik/notify/event_trigger.go +++ /dev/null @@ -1,23 +0,0 @@ -// Copyright (c) 2014-2015 The Notify Authors. All rights reserved. -// Use of this source code is governed by the MIT license that can be -// found in the LICENSE file. - -//go:build (darwin && kqueue) || (darwin && !cgo) || dragonfly || freebsd || netbsd || openbsd || solaris || illumos -// +build darwin,kqueue darwin,!cgo dragonfly freebsd netbsd openbsd solaris illumos - -package notify - -type event struct { - p string - e Event - d bool - pe interface{} -} - -func (e *event) Event() Event { return e.e } - -func (e *event) Path() string { return e.p } - -func (e *event) Sys() interface{} { return e.pe } - -func (e *event) isDir() (bool, error) { return e.d, nil } diff --git a/vendor/github.com/rjeczalik/notify/node.go b/vendor/github.com/rjeczalik/notify/node.go deleted file mode 100644 index ad7d04f250..0000000000 --- a/vendor/github.com/rjeczalik/notify/node.go +++ /dev/null @@ -1,275 +0,0 @@ -// Copyright (c) 2014-2015 The Notify Authors. All rights reserved. -// Use of this source code is governed by the MIT license that can be -// found in the LICENSE file. - -package notify - -import ( - "errors" - "io/fs" - "os" - "path/filepath" -) - -var errSkip = errors.New("notify: skip") - -type walkPathFunc func(nd node, isbase bool) error - -type walkFunc func(node) error - -func errnotexist(name string) error { - return &os.PathError{ - Op: "Node", - Path: name, - Err: os.ErrNotExist, - } -} - -type node struct { - Name string - Watch watchpoint - Child map[string]node -} - -func newnode(name string) node { - return node{ - Name: name, - Watch: make(watchpoint), - Child: make(map[string]node), - } -} - -func (nd node) addchild(name, base string) node { - child, ok := nd.Child[base] - if !ok { - child = newnode(name) - nd.Child[base] = child - } - return child -} - -func (nd node) Add(name string) node { - i := indexrel(nd.Name, name) - if i == -1 { - return node{} - } - for j := indexSep(name[i:]); j != -1; j = indexSep(name[i:]) { - nd = nd.addchild(name[:i+j], name[i:i+j]) - i += j + 1 - } - return nd.addchild(name, name[i:]) -} - -func (nd node) AddDir(fn walkFunc) error { - stack := []node{nd} -Traverse: - for n := len(stack); n != 0; n = len(stack) { - nd, stack = stack[n-1], stack[:n-1] - switch err := fn(nd); err { - case nil: - case errSkip: - continue Traverse - default: - return &os.PathError{ - Op: "error while traversing", - Path: nd.Name, - Err: err, - } - } - // TODO(rjeczalik): tolerate open failures - add failed names to - // AddDirError and notify users which names are not added to the tree. - fi, err := os.ReadDir(nd.Name) - if err != nil { - return err - } - for _, fi := range fi { - if fi.Type()&(fs.ModeSymlink|fs.ModeDir) == fs.ModeDir { - name := filepath.Join(nd.Name, fi.Name()) - stack = append(stack, nd.addchild(name, name[len(nd.Name)+1:])) - } - } - } - return nil -} - -func (nd node) Get(name string) (node, error) { - i := indexrel(nd.Name, name) - if i == -1 { - return node{}, errnotexist(name) - } - ok := false - for j := indexSep(name[i:]); j != -1; j = indexSep(name[i:]) { - if nd, ok = nd.Child[name[i:i+j]]; !ok { - return node{}, errnotexist(name) - } - i += j + 1 - } - if nd, ok = nd.Child[name[i:]]; !ok { - return node{}, errnotexist(name) - } - return nd, nil -} - -func (nd node) Del(name string) error { - i := indexrel(nd.Name, name) - if i == -1 { - return errnotexist(name) - } - stack := []node{nd} - ok := false - for j := indexSep(name[i:]); j != -1; j = indexSep(name[i:]) { - if nd, ok = nd.Child[name[i:i+j]]; !ok { - return errnotexist(name[:i+j]) - } - stack = append(stack, nd) - i += j + 1 - } - if _, ok = nd.Child[name[i:]]; !ok { - return errnotexist(name) - } - delete(nd.Child, name[i:]) - for name, i = name[i:], len(stack); i != 0; name, i = base(nd.Name), i-1 { - nd = stack[i-1] - if nd := nd.Child[name]; len(nd.Watch) > 1 || len(nd.Child) != 0 { - break - } else { - nd.Child = nil - nd.Watch = nil - } - delete(nd.Child, name) - } - return nil -} - -func (nd node) Walk(fn walkFunc) error { - stack := []node{nd} -Traverse: - for n := len(stack); n != 0; n = len(stack) { - nd, stack = stack[n-1], stack[:n-1] - switch err := fn(nd); err { - case nil: - case errSkip: - continue Traverse - default: - return err - } - for name, nd := range nd.Child { - if name == "" { - // Node storing inactive watchpoints has empty name, skip it - // form traversing. Root node has also an empty name, but it - // never has a parent node. - continue - } - stack = append(stack, nd) - } - } - return nil -} - -func (nd node) WalkPath(name string, fn walkPathFunc) error { - i := indexrel(nd.Name, name) - if i == -1 { - return errnotexist(name) - } - ok := false - for j := indexSep(name[i:]); j != -1; j = indexSep(name[i:]) { - switch err := fn(nd, false); err { - case nil: - case errSkip: - return nil - default: - return err - } - if nd, ok = nd.Child[name[i:i+j]]; !ok { - return errnotexist(name[:i+j]) - } - i += j + 1 - } - switch err := fn(nd, false); err { - case nil: - case errSkip: - return nil - default: - return err - } - if nd, ok = nd.Child[name[i:]]; !ok { - return errnotexist(name) - } - switch err := fn(nd, true); err { - case nil, errSkip: - return nil - default: - return err - } -} - -type root struct { - nd node -} - -func (r root) addroot(name string) node { - if vol := filepath.VolumeName(name); vol != "" { - root, ok := r.nd.Child[vol] - if !ok { - root = r.nd.addchild(vol, vol) - } - return root - } - return r.nd -} - -func (r root) root(name string) (node, error) { - if vol := filepath.VolumeName(name); vol != "" { - nd, ok := r.nd.Child[vol] - if !ok { - return node{}, errnotexist(name) - } - return nd, nil - } - return r.nd, nil -} - -func (r root) Add(name string) node { - return r.addroot(name).Add(name) -} - -func (r root) AddDir(dir string, fn walkFunc) error { - return r.Add(dir).AddDir(fn) -} - -func (r root) Del(name string) error { - nd, err := r.root(name) - if err != nil { - return err - } - return nd.Del(name) -} - -func (r root) Get(name string) (node, error) { - nd, err := r.root(name) - if err != nil { - return node{}, err - } - if nd.Name != name { - if nd, err = nd.Get(name); err != nil { - return node{}, err - } - } - return nd, nil -} - -func (r root) Walk(name string, fn walkFunc) error { - nd, err := r.Get(name) - if err != nil { - return err - } - return nd.Walk(fn) -} - -func (r root) WalkPath(name string, fn walkPathFunc) error { - nd, err := r.root(name) - if err != nil { - return err - } - return nd.WalkPath(name, fn) -} diff --git a/vendor/github.com/rjeczalik/notify/notify.go b/vendor/github.com/rjeczalik/notify/notify.go deleted file mode 100644 index aa57660b94..0000000000 --- a/vendor/github.com/rjeczalik/notify/notify.go +++ /dev/null @@ -1,74 +0,0 @@ -// Copyright (c) 2014-2015 The Notify Authors. All rights reserved. -// Use of this source code is governed by the MIT license that can be -// found in the LICENSE file. - -// BUG(rjeczalik): Notify does not collect watchpoints, when underlying watches -// were removed by their os-specific watcher implementations. Instead users are -// advised to listen on persistent paths to have guarantee they receive events -// for the whole lifetime of their applications (to discuss see #69). - -// BUG(ppknap): Linux (inotify) does not support watcher behavior masks like -// InOneshot, InOnlydir etc. Instead users are advised to perform the filtering -// themselves (to discuss see #71). - -// BUG(ppknap): Notify was not tested for short path name support under Windows -// (ReadDirectoryChangesW). - -// BUG(ppknap): Windows (ReadDirectoryChangesW) cannot recognize which notification -// triggers FileActionModified event. (to discuss see #75). - -package notify - -var defaultTree = newTree() - -// Watch sets up a watchpoint on path listening for events given by the events -// argument. -// -// File or directory given by the path must exist, otherwise Watch will fail -// with non-nil error. Notify resolves, for its internal purpose, any symlinks -// the provided path may contain, so it may fail if the symlinks form a cycle. -// It does so, since not all watcher implementations treat passed paths as-is. -// E.g. FSEvents reports a real path for every event, setting a watchpoint -// on /tmp will report events with paths rooted at /private/tmp etc. -// -// The c almost always is a buffered channel. Watch will not block sending to c -// - the caller must ensure that c has sufficient buffer space to keep up with -// the expected event rate. -// -// It is allowed to pass the same channel multiple times with different event -// list or different paths. Calling Watch with different event lists for a single -// watchpoint expands its event set. The only way to shrink it, is to call -// Stop on its channel. -// -// Calling Watch with empty event list does not expand nor shrink watchpoint's -// event set. If c is the first channel to listen for events on the given path, -// Watch will seamlessly create a watch on the filesystem. -// -// Notify dispatches copies of single filesystem event to all channels registered -// for each path. If a single filesystem event contains multiple coalesced events, -// each of them is dispatched separately. E.g. the following filesystem change: -// -// ~ $ echo Hello > Notify.txt -// -// dispatches two events - notify.Create and notify.Write. However, it may depend -// on the underlying watcher implementation whether OS reports both of them. -// -// # Windows and recursive watches -// -// If a directory which path was used to create recursive watch under Windows -// gets deleted, the OS will not report such event. It is advised to keep in -// mind this limitation while setting recursive watchpoints for your application, -// e.g. use persistent paths like %userprofile% or watch additionally parent -// directory of a recursive watchpoint in order to receive delete events for it. -func Watch(path string, c chan<- EventInfo, events ...Event) error { - return defaultTree.Watch(path, c, events...) -} - -// Stop removes all watchpoints registered for c. All underlying watches are -// also removed, for which c was the last channel listening for events. -// -// Stop does not close c. When Stop returns, it is guaranteed that c will -// receive no more signals. -func Stop(c chan<- EventInfo) { - defaultTree.Stop(c) -} diff --git a/vendor/github.com/rjeczalik/notify/tree.go b/vendor/github.com/rjeczalik/notify/tree.go deleted file mode 100644 index cd6afd60d0..0000000000 --- a/vendor/github.com/rjeczalik/notify/tree.go +++ /dev/null @@ -1,22 +0,0 @@ -// Copyright (c) 2014-2015 The Notify Authors. All rights reserved. -// Use of this source code is governed by the MIT license that can be -// found in the LICENSE file. - -package notify - -const buffer = 128 - -type tree interface { - Watch(string, chan<- EventInfo, ...Event) error - Stop(chan<- EventInfo) - Close() error -} - -func newTree() tree { - c := make(chan EventInfo, buffer) - w := newWatcher(c) - if rw, ok := w.(recursiveWatcher); ok { - return newRecursiveTree(rw, c) - } - return newNonrecursiveTree(w, c, make(chan EventInfo, buffer)) -} diff --git a/vendor/github.com/rjeczalik/notify/tree_nonrecursive.go b/vendor/github.com/rjeczalik/notify/tree_nonrecursive.go deleted file mode 100644 index 6e233408a6..0000000000 --- a/vendor/github.com/rjeczalik/notify/tree_nonrecursive.go +++ /dev/null @@ -1,309 +0,0 @@ -// Copyright (c) 2014-2015 The Notify Authors. All rights reserved. -// Use of this source code is governed by the MIT license that can be -// found in the LICENSE file. - -package notify - -import "sync" - -// nonrecursiveTree TODO(rjeczalik) -type nonrecursiveTree struct { - rw sync.RWMutex // protects root - root root - w watcher - c chan EventInfo - rec chan EventInfo -} - -// newNonrecursiveTree TODO(rjeczalik) -func newNonrecursiveTree(w watcher, c, rec chan EventInfo) *nonrecursiveTree { - if rec == nil { - rec = make(chan EventInfo, buffer) - } - t := &nonrecursiveTree{ - root: root{nd: newnode("")}, - w: w, - c: c, - rec: rec, - } - go t.dispatch(c) - go t.internal(rec) - return t -} - -// dispatch TODO(rjeczalik) -func (t *nonrecursiveTree) dispatch(c <-chan EventInfo) { - for ei := range c { - dbgprintf("dispatching %v on %q", ei.Event(), ei.Path()) - go func(ei EventInfo) { - var nd node - var isrec bool - dir, base := split(ei.Path()) - fn := func(it node, isbase bool) error { - isrec = isrec || it.Watch.IsRecursive() - if isbase { - nd = it - } else { - it.Watch.Dispatch(ei, recursive) - } - return nil - } - t.rw.RLock() - // Notify recursive watchpoints found on the path. - if err := t.root.WalkPath(dir, fn); err != nil { - dbgprint("dispatch did not reach leaf:", err) - t.rw.RUnlock() - return - } - // Notify parent watchpoint. - nd.Watch.Dispatch(ei, 0) - isrec = isrec || nd.Watch.IsRecursive() - // If leaf watchpoint exists, notify it. - if nd, ok := nd.Child[base]; ok { - isrec = isrec || nd.Watch.IsRecursive() - nd.Watch.Dispatch(ei, 0) - } - t.rw.RUnlock() - // If the event describes newly leaf directory created within - if !isrec || ei.Event()&(Create|Remove) == 0 { - return - } - if ok, err := ei.(isDirer).isDir(); !ok || err != nil { - return - } - t.rec <- ei - }(ei) - } -} - -// internal TODO(rjeczalik) -func (t *nonrecursiveTree) internal(rec <-chan EventInfo) { - for ei := range rec { - t.rw.Lock() - if ei.Event() == Remove { - nd, err := t.root.Get(ei.Path()) - if err != nil { - t.rw.Unlock() - continue - } - t.walkWatchpoint(nd, func(_ Event, nd node) error { - t.w.Unwatch(nd.Name) - return nil - }) - t.root.Del(ei.Path()) - t.rw.Unlock() - continue - } - var nd node - var eset = internal - t.root.WalkPath(ei.Path(), func(it node, _ bool) error { - if e := it.Watch[t.rec]; e != 0 && e > eset { - eset = e - } - nd = it - return nil - }) - if eset == internal { - t.rw.Unlock() - continue - } - if ei.Path() != nd.Name { - nd = nd.Add(ei.Path()) - } - err := nd.AddDir(t.recFunc(eset)) - t.rw.Unlock() - if err != nil { - dbgprintf("internal(%p) error: %v", rec, err) - } - } -} - -// watchAdd TODO(rjeczalik) -func (t *nonrecursiveTree) watchAdd(nd node, c chan<- EventInfo, e Event) eventDiff { - if e&recursive != 0 { - diff := nd.Watch.Add(t.rec, e|Create|omit) - nd.Watch.Add(c, e) - return diff - } - return nd.Watch.Add(c, e) -} - -// watchDelMin TODO(rjeczalik) -func (t *nonrecursiveTree) watchDelMin(min Event, nd node, c chan<- EventInfo, e Event) eventDiff { - old, ok := nd.Watch[t.rec] - if ok { - nd.Watch[t.rec] = min - } - diff := nd.Watch.Del(c, e) - if ok { - switch old &^= diff[0] &^ diff[1]; { - case old|internal == internal: - delete(nd.Watch, t.rec) - if set, ok := nd.Watch[nil]; ok && len(nd.Watch) == 1 && set == 0 { - delete(nd.Watch, nil) - } - default: - nd.Watch.Add(t.rec, old|Create) - switch { - case diff == none: - case diff[1]|Create == diff[0]: - diff = none - default: - diff[1] |= Create - } - } - } - return diff -} - -// watchDel TODO(rjeczalik) -func (t *nonrecursiveTree) watchDel(nd node, c chan<- EventInfo, e Event) eventDiff { - return t.watchDelMin(0, nd, c, e) -} - -// Watch TODO(rjeczalik) -func (t *nonrecursiveTree) Watch(path string, c chan<- EventInfo, events ...Event) error { - if c == nil { - panic("notify: Watch using nil channel") - } - // Expanding with empty event set is a nop. - if len(events) == 0 { - return nil - } - path, isrec, err := cleanpath(path) - if err != nil { - return err - } - eset := joinevents(events) - t.rw.Lock() - defer t.rw.Unlock() - nd := t.root.Add(path) - if isrec { - return t.watchrec(nd, c, eset|recursive) - } - return t.watch(nd, c, eset) -} - -func (t *nonrecursiveTree) watch(nd node, c chan<- EventInfo, e Event) (err error) { - diff := nd.Watch.Add(c, e) - switch { - case diff == none: - return nil - case diff[1] == 0: - // TODO(rjeczalik): cleanup this panic after implementation is stable - panic("eset is empty: " + nd.Name) - case diff[0] == 0: - err = t.w.Watch(nd.Name, diff[1]) - default: - err = t.w.Rewatch(nd.Name, diff[0], diff[1]) - } - if err != nil { - nd.Watch.Del(c, diff.Event()) - return err - } - return nil -} - -func (t *nonrecursiveTree) recFunc(e Event) walkFunc { - return func(nd node) error { - switch diff := nd.Watch.Add(t.rec, e|omit|Create); { - case diff == none: - case diff[1] == 0: - // TODO(rjeczalik): cleanup this panic after implementation is stable - panic("eset is empty: " + nd.Name) - case diff[0] == 0: - t.w.Watch(nd.Name, diff[1]) - default: - t.w.Rewatch(nd.Name, diff[0], diff[1]) - } - return nil - } -} - -func (t *nonrecursiveTree) watchrec(nd node, c chan<- EventInfo, e Event) error { - var traverse func(walkFunc) error - // Non-recursive tree listens on Create event for every recursive - // watchpoint in order to automagically set a watch for every - // created directory. - switch diff := nd.Watch.dryAdd(t.rec, e|Create); { - case diff == none: - t.watchAdd(nd, c, e) - nd.Watch.Add(t.rec, e|omit|Create) - return nil - case diff[1] == 0: - // TODO(rjeczalik): cleanup this panic after implementation is stable - panic("eset is empty: " + nd.Name) - case diff[0] == 0: - // TODO(rjeczalik): BFS into directories and skip subtree as soon as first - // recursive watchpoint is encountered. - traverse = nd.AddDir - default: - traverse = nd.Walk - } - // TODO(rjeczalik): account every path that failed to be (re)watched - // and retry. - if err := traverse(t.recFunc(e)); err != nil { - return err - } - t.watchAdd(nd, c, e) - return nil -} - -type walkWatchpointFunc func(Event, node) error - -func (t *nonrecursiveTree) walkWatchpoint(nd node, fn walkWatchpointFunc) error { - type minode struct { - min Event - nd node - } - mnd := minode{nd: nd} - stack := []minode{mnd} -Traverse: - for n := len(stack); n != 0; n = len(stack) { - mnd, stack = stack[n-1], stack[:n-1] - // There must be no recursive watchpoints if the node has no watchpoints - // itself (every node in subtree rooted at recursive watchpoints must - // have at least nil (total) and t.rec watchpoints). - if len(mnd.nd.Watch) != 0 { - switch err := fn(mnd.min, mnd.nd); err { - case nil: - case errSkip: - continue Traverse - default: - return err - } - } - for _, nd := range mnd.nd.Child { - stack = append(stack, minode{mnd.nd.Watch[t.rec], nd}) - } - } - return nil -} - -// Stop TODO(rjeczalik) -func (t *nonrecursiveTree) Stop(c chan<- EventInfo) { - fn := func(min Event, nd node) error { - // TODO(rjeczalik): aggregate watcher errors and retry; in worst case - // forward to the user. - switch diff := t.watchDelMin(min, nd, c, all); { - case diff == none: - return nil - case diff[1] == 0: - t.w.Unwatch(nd.Name) - default: - t.w.Rewatch(nd.Name, diff[0], diff[1]) - } - return nil - } - t.rw.Lock() - err := t.walkWatchpoint(t.root.nd, fn) // TODO(rjeczalik): store max root per c - t.rw.Unlock() - dbgprintf("Stop(%p) error: %v\n", c, err) -} - -// Close TODO(rjeczalik) -func (t *nonrecursiveTree) Close() error { - err := t.w.Close() - close(t.c) - return err -} diff --git a/vendor/github.com/rjeczalik/notify/tree_recursive.go b/vendor/github.com/rjeczalik/notify/tree_recursive.go deleted file mode 100644 index 7f00dfe35a..0000000000 --- a/vendor/github.com/rjeczalik/notify/tree_recursive.go +++ /dev/null @@ -1,354 +0,0 @@ -// Copyright (c) 2014-2015 The Notify Authors. All rights reserved. -// Use of this source code is governed by the MIT license that can be -// found in the LICENSE file. - -package notify - -import "sync" - -// watchAdd TODO(rjeczalik) -func watchAdd(nd node, c chan<- EventInfo, e Event) eventDiff { - diff := nd.Watch.Add(c, e) - if wp := nd.Child[""].Watch; len(wp) != 0 { - e = wp.Total() - diff[0] |= e - diff[1] |= e - if diff[0] == diff[1] { - return none - } - } - return diff -} - -// watchAddInactive TODO(rjeczalik) -func watchAddInactive(nd node, c chan<- EventInfo, e Event) eventDiff { - wp := nd.Child[""].Watch - if wp == nil { - wp = make(watchpoint) - nd.Child[""] = node{Watch: wp} - } - diff := wp.Add(c, e) - e = nd.Watch.Total() - diff[0] |= e - diff[1] |= e - if diff[0] == diff[1] { - return none - } - return diff -} - -// watchCopy TODO(rjeczalik) -func watchCopy(src, dst node) { - for c, e := range src.Watch { - if c == nil { - continue - } - watchAddInactive(dst, c, e) - } - if wpsrc := src.Child[""].Watch; len(wpsrc) != 0 { - wpdst := dst.Child[""].Watch - for c, e := range wpsrc { - if c == nil { - continue - } - wpdst.Add(c, e) - } - } -} - -// watchDel TODO(rjeczalik) -func watchDel(nd node, c chan<- EventInfo, e Event) eventDiff { - diff := nd.Watch.Del(c, e) - if wp := nd.Child[""].Watch; len(wp) != 0 { - diffInactive := wp.Del(c, e) - e = wp.Total() - // TODO(rjeczalik): add e if e != all? - diff[0] |= diffInactive[0] | e - diff[1] |= diffInactive[1] | e - if diff[0] == diff[1] { - return none - } - } - return diff -} - -// watchTotal TODO(rjeczalik) -func watchTotal(nd node) Event { - e := nd.Watch.Total() - if wp := nd.Child[""].Watch; len(wp) != 0 { - e |= wp.Total() - } - return e -} - -// watchIsRecursive TODO(rjeczalik) -func watchIsRecursive(nd node) bool { - ok := nd.Watch.IsRecursive() - // TODO(rjeczalik): add a test for len(wp) != 0 change the condition. - if wp := nd.Child[""].Watch; len(wp) != 0 { - // If a watchpoint holds inactive watchpoints, it means it's a parent - // one, which is recursive by nature even though it may be not recursive - // itself. - ok = true - } - return ok -} - -// recursiveTree TODO(rjeczalik) -type recursiveTree struct { - rw sync.RWMutex // protects root - root root - // TODO(rjeczalik): merge watcher + recursiveWatcher after #5 and #6 - w interface { - watcher - recursiveWatcher - } - c chan EventInfo -} - -// newRecursiveTree TODO(rjeczalik) -func newRecursiveTree(w recursiveWatcher, c chan EventInfo) *recursiveTree { - t := &recursiveTree{ - root: root{nd: newnode("")}, - w: struct { - watcher - recursiveWatcher - }{w.(watcher), w}, - c: c, - } - go t.dispatch() - return t -} - -// dispatch TODO(rjeczalik) -func (t *recursiveTree) dispatch() { - for ei := range t.c { - dbgprintf("dispatching %v on %q", ei.Event(), ei.Path()) - go func(ei EventInfo) { - nd, ok := node{}, false - dir, base := split(ei.Path()) - fn := func(it node, isbase bool) error { - if isbase { - nd = it - } else { - it.Watch.Dispatch(ei, recursive) - } - return nil - } - t.rw.RLock() - defer t.rw.RUnlock() - // Notify recursive watchpoints found on the path. - if err := t.root.WalkPath(dir, fn); err != nil { - dbgprint("dispatch did not reach leaf:", err) - return - } - // Notify parent watchpoint. - nd.Watch.Dispatch(ei, 0) - // If leaf watchpoint exists, notify it. - if nd, ok = nd.Child[base]; ok { - nd.Watch.Dispatch(ei, 0) - } - }(ei) - } -} - -// Watch TODO(rjeczalik) -func (t *recursiveTree) Watch(path string, c chan<- EventInfo, events ...Event) error { - if c == nil { - panic("notify: Watch using nil channel") - } - // Expanding with empty event set is a nop. - if len(events) == 0 { - return nil - } - path, isrec, err := cleanpath(path) - if err != nil { - return err - } - eventset := joinevents(events) - if isrec { - eventset |= recursive - } - t.rw.Lock() - defer t.rw.Unlock() - // case 1: cur is a child - // - // Look for parent watch which already covers the given path. - parent := node{} - self := false - err = t.root.WalkPath(path, func(nd node, isbase bool) error { - if watchTotal(nd) != 0 { - parent = nd - self = isbase - return errSkip - } - return nil - }) - cur := t.root.Add(path) // add after the walk, so it's less to traverse - if err == nil && parent.Watch != nil { - // Parent watch found. Register inactive watchpoint, so we have enough - // information to shrink the eventset on eventual Stop. - // return t.resetwatchpoint(parent, parent, c, eventset|inactive) - var diff eventDiff - if self { - diff = watchAdd(cur, c, eventset) - } else { - diff = watchAddInactive(parent, c, eventset) - } - switch { - case diff == none: - // the parent watchpoint already covers requested subtree with its - // eventset - case diff[0] == 0: - // TODO(rjeczalik): cleanup this panic after implementation is stable - panic("dangling watchpoint: " + parent.Name) - default: - if isrec || watchIsRecursive(parent) { - err = t.w.RecursiveRewatch(parent.Name, parent.Name, diff[0], diff[1]) - } else { - err = t.w.Rewatch(parent.Name, diff[0], diff[1]) - } - if err != nil { - watchDel(parent, c, diff.Event()) - return err - } - watchAdd(cur, c, eventset) - // TODO(rjeczalik): account top-most path for c - return nil - } - if !self { - watchAdd(cur, c, eventset) - } - return nil - } - // case 2: cur is new parent - // - // Look for children nodes, unwatch n-1 of them and rewatch the last one. - var children []node - fn := func(nd node) error { - if len(nd.Watch) == 0 { - return nil - } - children = append(children, nd) - return errSkip - } - switch must(cur.Walk(fn)); len(children) { - case 0: - // no child watches, cur holds a new watch - case 1: - watchAdd(cur, c, eventset) // TODO(rjeczalik): update cache c subtree root? - watchCopy(children[0], cur) - err = t.w.RecursiveRewatch(children[0].Name, cur.Name, watchTotal(children[0]), - watchTotal(cur)) - if err != nil { - // Clean inactive watchpoint. The c chan did not exist before. - cur.Child[""] = node{} - delete(cur.Watch, c) - return err - } - return nil - default: - watchAdd(cur, c, eventset) - // Copy children inactive watchpoints to the new parent. - for _, nd := range children { - watchCopy(nd, cur) - } - // Watch parent subtree. - if err = t.w.RecursiveWatch(cur.Name, watchTotal(cur)); err != nil { - // Clean inactive watchpoint. The c chan did not exist before. - cur.Child[""] = node{} - delete(cur.Watch, c) - return err - } - // Unwatch children subtrees. - var e error - for _, nd := range children { - if watchIsRecursive(nd) { - e = t.w.RecursiveUnwatch(nd.Name) - } else { - e = t.w.Unwatch(nd.Name) - } - if e != nil { - err = nonil(err, e) - // TODO(rjeczalik): child is still watched, warn all its watchpoints - // about possible duplicate events via Error event - } - } - return err - } - // case 3: cur is new, alone node - switch diff := watchAdd(cur, c, eventset); { - case diff == none: - // TODO(rjeczalik): cleanup this panic after implementation is stable - panic("watch requested but no parent watchpoint found: " + cur.Name) - case diff[0] == 0: - if isrec { - err = t.w.RecursiveWatch(cur.Name, diff[1]) - } else { - err = t.w.Watch(cur.Name, diff[1]) - } - if err != nil { - watchDel(cur, c, diff.Event()) - return err - } - default: - // TODO(rjeczalik): cleanup this panic after implementation is stable - panic("watch requested but no parent watchpoint found: " + cur.Name) - } - return nil -} - -// Stop TODO(rjeczalik) -// -// TODO(rjeczalik): Split parent watchpoint - transfer watches to children -// if parent is no longer needed. This carries a risk that underlying -// watcher calls could fail - reconsider if it's worth the effort. -func (t *recursiveTree) Stop(c chan<- EventInfo) { - var err error - fn := func(nd node) (e error) { - diff := watchDel(nd, c, all) - switch { - case diff == none && watchTotal(nd) == 0: - // TODO(rjeczalik): There's no watchpoints deeper in the tree, - // probably we should remove the nodes as well. - return nil - case diff == none: - // Removing c from nd does not require shrinking its eventset. - case diff[1] == 0: - if watchIsRecursive(nd) { - e = t.w.RecursiveUnwatch(nd.Name) - } else { - e = t.w.Unwatch(nd.Name) - } - default: - if watchIsRecursive(nd) { - e = t.w.RecursiveRewatch(nd.Name, nd.Name, diff[0], diff[1]) - } else { - e = t.w.Rewatch(nd.Name, diff[0], diff[1]) - } - } - fn := func(nd node) error { - watchDel(nd, c, all) - return nil - } - err = nonil(err, e, nd.Walk(fn)) - // TODO(rjeczalik): if e != nil store dummy chan in nd.Watch just to - // retry un/rewatching next time and/or let the user handle the failure - // vie Error event? - return errSkip - } - t.rw.Lock() - e := t.root.Walk("", fn) // TODO(rjeczalik): use max root per c - t.rw.Unlock() - if e != nil { - err = nonil(err, e) - } - dbgprintf("Stop(%p) error: %v\n", c, err) -} - -// Close TODO(rjeczalik) -func (t *recursiveTree) Close() error { - err := t.w.Close() - close(t.c) - return err -} diff --git a/vendor/github.com/rjeczalik/notify/util.go b/vendor/github.com/rjeczalik/notify/util.go deleted file mode 100644 index 7b50b0c011..0000000000 --- a/vendor/github.com/rjeczalik/notify/util.go +++ /dev/null @@ -1,152 +0,0 @@ -// Copyright (c) 2014-2015 The Notify Authors. All rights reserved. -// Use of this source code is governed by the MIT license that can be -// found in the LICENSE file. - -package notify - -import ( - "errors" - "os" - "path/filepath" - "strings" -) - -const all = ^Event(0) -const sep = string(os.PathSeparator) - -var errDepth = errors.New("exceeded allowed iteration count (circular symlink?)") - -func min(i, j int) int { - if i > j { - return j - } - return i -} - -func max(i, j int) int { - if i < j { - return j - } - return i -} - -// must panics if err is non-nil. -func must(err error) { - if err != nil { - panic(err) - } -} - -// nonil gives first non-nil error from the given arguments. -func nonil(err ...error) error { - for _, err := range err { - if err != nil { - return err - } - } - return nil -} - -func cleanpath(path string) (realpath string, isrec bool, err error) { - if strings.HasSuffix(path, "...") { - isrec = true - path = path[:len(path)-3] - } - if path, err = filepath.Abs(path); err != nil { - return "", false, err - } - if path, err = canonical(path); err != nil { - return "", false, err - } - return path, isrec, nil -} - -// canonical resolves any symlink in the given path and returns it in a clean form. -// It expects the path to be absolute. It fails to resolve circular symlinks by -// maintaining a simple iteration limit. -func canonical(p string) (string, error) { - p, err := filepath.Abs(p) - if err != nil { - return "", err - } - for i, j, depth := 1, 0, 1; i < len(p); i, depth = i+1, depth+1 { - if depth > 128 { - return "", &os.PathError{Op: "canonical", Path: p, Err: errDepth} - } - if j = strings.IndexRune(p[i:], '/'); j == -1 { - j, i = i, len(p) - } else { - j, i = i, i+j - } - fi, err := os.Lstat(p[:i]) - if err != nil { - return "", err - } - if fi.Mode()&os.ModeSymlink == os.ModeSymlink { - s, err := os.Readlink(p[:i]) - if err != nil { - return "", err - } - if filepath.IsAbs(s) { - p = "/" + s + p[i:] - } else { - p = p[:j] + s + p[i:] - } - i = 1 // no guarantee s is canonical, start all over - } - } - return filepath.Clean(p), nil -} - -func joinevents(events []Event) (e Event) { - if len(events) == 0 { - e = All - } else { - for _, event := range events { - e |= event - } - } - return -} - -func split(s string) (string, string) { - if i := lastIndexSep(s); i != -1 { - return s[:i], s[i+1:] - } - return "", s -} - -func base(s string) string { - if i := lastIndexSep(s); i != -1 { - return s[i+1:] - } - return s -} - -// indexrel returns the index of the first char of name that is -// below/relative to root. It returns -1 if name is not a child of root. -func indexrel(root, name string) int { - if n, m := len(root), len(name); m > n && name[:n] == root && - name[n] == os.PathSeparator { - return n + 1 - } - return -1 -} - -func indexSep(s string) int { - for i := 0; i < len(s); i++ { - if s[i] == os.PathSeparator { - return i - } - } - return -1 -} - -func lastIndexSep(s string) int { - for i := len(s) - 1; i >= 0; i-- { - if s[i] == os.PathSeparator { - return i - } - } - return -1 -} diff --git a/vendor/github.com/rjeczalik/notify/watcher.go b/vendor/github.com/rjeczalik/notify/watcher.go deleted file mode 100644 index 34148eff39..0000000000 --- a/vendor/github.com/rjeczalik/notify/watcher.go +++ /dev/null @@ -1,85 +0,0 @@ -// Copyright (c) 2014-2015 The Notify Authors. All rights reserved. -// Use of this source code is governed by the MIT license that can be -// found in the LICENSE file. - -package notify - -import "errors" - -var ( - errAlreadyWatched = errors.New("path is already watched") - errNotWatched = errors.New("path is not being watched") - errInvalidEventSet = errors.New("invalid event set provided") -) - -// Watcher is a intermediate interface for wrapping inotify, ReadDirChangesW, -// FSEvents, kqueue and poller implementations. -// -// The watcher implementation is expected to do its own mapping between paths and -// create watchers if underlying event notification does not support it. For -// the ease of implementation it is guaranteed that paths provided via Watch and -// Unwatch methods are absolute and clean. -type watcher interface { - // Watch requests a watcher creation for the given path and given event set. - Watch(path string, event Event) error - - // Unwatch requests a watcher deletion for the given path and given event set. - Unwatch(path string) error - - // Rewatch provides a functionality for modifying existing watch-points, like - // expanding its event set. - // - // Rewatch modifies existing watch-point under for the given path. It passes - // the existing event set currently registered for the given path, and the - // new, requested event set. - // - // It is guaranteed that Tree will not pass to Rewatch zero value for any - // of its arguments. If old == new and watcher can be upgraded to - // recursiveWatcher interface, a watch for the corresponding path is expected - // to be changed from recursive to the non-recursive one. - Rewatch(path string, old, new Event) error - - // Close unwatches all paths that are registered. When Close returns, it - // is expected it will report no more events. - Close() error -} - -// RecursiveWatcher is an interface for a Watcher for those OS, which do support -// recursive watching over directories. -type recursiveWatcher interface { - RecursiveWatch(path string, event Event) error - - // RecursiveUnwatch removes a recursive watch-point given by the path. For - // native recursive implementation there is no difference in functionality - // between Unwatch and RecursiveUnwatch, however for those platforms, that - // requires emulation for recursive watch-points, the implementation differs. - RecursiveUnwatch(path string) error - - // RecursiveRewatcher provides a functionality for modifying and/or relocating - // existing recursive watch-points. - // - // To relocate a watch-point means to unwatch oldpath and set a watch-point on - // newpath. - // - // To modify a watch-point means either to expand or shrink its event set. - // - // Tree can want to either relocate, modify or relocate and modify a watch-point - // via single RecursiveRewatch call. - // - // If oldpath == newpath, the watch-point is expected to change its event set value - // from oldevent to newevent. - // - // If oldevent == newevent, the watch-point is expected to relocate from oldpath - // to the newpath. - // - // If oldpath != newpath and oldevent != newevent, the watch-point is expected - // to relocate from oldpath to the newpath first and then change its event set - // value from oldevent to the newevent. In other words the end result must be - // a watch-point set on newpath with newevent value of its event set. - // - // It is guaranteed that Tree will not pass to RecurisveRewatcha zero value - // for any of its arguments. If oldpath == newpath and oldevent == newevent, - // a watch for the corresponding path is expected to be changed for - // non-recursive to the recursive one. - RecursiveRewatch(oldpath, newpath string, oldevent, newevent Event) error -} diff --git a/vendor/github.com/rjeczalik/notify/watcher_fen.go b/vendor/github.com/rjeczalik/notify/watcher_fen.go deleted file mode 100644 index 114ec7f751..0000000000 --- a/vendor/github.com/rjeczalik/notify/watcher_fen.go +++ /dev/null @@ -1,162 +0,0 @@ -// Copyright (c) 2014-2015 The Notify Authors. All rights reserved. -// Use of this source code is governed by the MIT license that can be -// found in the LICENSE file. - -//go:build solaris || illumos -// +build solaris illumos - -package notify - -import ( - "fmt" - "os" - "syscall" -) - -// newTrigger returns implementation of trigger. -func newTrigger(pthLkp map[string]*watched) trigger { - return &fen{ - pthLkp: pthLkp, - cf: newCfen(), - } -} - -// fen is a structure implementing trigger for FEN. -type fen struct { - // p is a FEN port identifier - p int - // pthLkp is a structure mapping monitored files/dir with data about them, - // shared with parent trg structure - pthLkp map[string]*watched - // cf wraps C operations for FEN - cf cfen -} - -// watched is a data structure representing watched file/directory. -type watched struct { - trgWatched -} - -// Stop implements trigger. -func (f *fen) Stop() error { - return f.cf.portAlert(f.p) -} - -// Close implements trigger. -func (f *fen) Close() (err error) { - return syscall.Close(f.p) -} - -// NewWatched implements trigger. -func (*fen) NewWatched(p string, fi os.FileInfo) (*watched, error) { - return &watched{trgWatched{p: p, fi: fi}}, nil -} - -// Record implements trigger. -func (f *fen) Record(w *watched) { - f.pthLkp[w.p] = w -} - -// Del implements trigger. -func (f *fen) Del(w *watched) { - delete(f.pthLkp, w.p) -} - -func inter2pe(n interface{}) PortEvent { - pe, ok := n.(PortEvent) - if !ok { - panic(fmt.Sprintf("fen: type should be PortEvent, %T instead", n)) - } - return pe -} - -// Watched implements trigger. -func (f *fen) Watched(n interface{}) (*watched, int64, error) { - pe := inter2pe(n) - fo, ok := pe.PortevObject.(*FileObj) - if !ok || fo == nil { - panic(fmt.Sprintf("fen: type should be *FileObj, %T instead", fo)) - } - w, ok := f.pthLkp[fo.Name] - if !ok { - return nil, 0, errNotWatched - } - return w, int64(pe.PortevEvents), nil -} - -// init initializes FEN. -func (f *fen) Init() (err error) { - f.p, err = f.cf.portCreate() - return -} - -func fi2fo(fi os.FileInfo, p string) FileObj { - st, ok := fi.Sys().(*syscall.Stat_t) - if !ok { - panic(fmt.Sprintf("fen: type should be *syscall.Stat_t, %T instead", st)) - } - return FileObj{Name: p, Atim: st.Atim, Mtim: st.Mtim, Ctim: st.Ctim} -} - -// Unwatch implements trigger. -func (f *fen) Unwatch(w *watched) error { - return f.cf.portDissociate(f.p, FileObj{Name: w.p}) -} - -// Watch implements trigger. -func (f *fen) Watch(fi os.FileInfo, w *watched, e int64) error { - return f.cf.portAssociate(f.p, fi2fo(fi, w.p), int(e)) -} - -// Wait implements trigger. -func (f *fen) Wait() (interface{}, error) { - var ( - pe PortEvent - err error - ) - err = f.cf.portGet(f.p, &pe) - return pe, err -} - -// IsStop implements trigger. -func (f *fen) IsStop(n interface{}, err error) bool { - return err == syscall.EBADF || inter2pe(n).PortevSource == srcAlert -} - -func init() { - encode = func(e Event, dir bool) (o int64) { - // Create event is not supported by FEN. Instead FileModified event will - // be registered. If this event will be reported on dir which is to be - // monitored for Create, dir will be rescanned and Create events will - // be generated and returned for new files. In case of files, - // if not requested FileModified event is reported, it will be ignored. - o = int64(e &^ Create) - if (e&Create != 0 && dir) || e&Write != 0 { - o = (o &^ int64(Write)) | int64(FileModified) - } - // Following events are 'exception events' and as such cannot be requested - // explicitly for monitoring or filtered out. If the will be reported - // by FEN and not subscribed with by user, they will be filtered out by - // watcher's logic. - o &= int64(^Rename & ^Remove &^ FileDelete &^ FileRenameTo &^ - FileRenameFrom &^ Unmounted &^ MountedOver) - return - } - nat2not = map[Event]Event{ - FileModified: Write, - FileRenameFrom: Rename, - FileDelete: Remove, - FileAccess: Event(0), - FileAttrib: Event(0), - FileRenameTo: Event(0), - FileTrunc: Event(0), - FileNoFollow: Event(0), - Unmounted: Event(0), - MountedOver: Event(0), - } - not2nat = map[Event]Event{ - Write: FileModified, - Rename: FileRenameFrom, - Remove: FileDelete, - } -} diff --git a/vendor/github.com/rjeczalik/notify/watcher_fen_cgo.go b/vendor/github.com/rjeczalik/notify/watcher_fen_cgo.go deleted file mode 100644 index 50f289deae..0000000000 --- a/vendor/github.com/rjeczalik/notify/watcher_fen_cgo.go +++ /dev/null @@ -1,142 +0,0 @@ -// Copyright (c) 2014-2015 The Notify Authors. All rights reserved. -// Use of this source code is governed by the MIT license that can be -// found in the LICENSE file. - -//go:build solaris || illumos -// +build solaris illumos - -package notify - -// #include -// #include -// #include -// struct file_obj* newFo() { return (struct file_obj*) malloc(sizeof(struct file_obj)); } -// port_event_t* newPe() { return (port_event_t*) malloc(sizeof(port_event_t)); } -// uintptr_t conv(struct file_obj* fo) { return (uintptr_t) fo; } -// struct file_obj* dconv(uintptr_t fo) { return (struct file_obj*) fo; } -import "C" - -import ( - "syscall" - "unsafe" -) - -const ( - fileAccess = Event(C.FILE_ACCESS) - fileModified = Event(C.FILE_MODIFIED) - fileAttrib = Event(C.FILE_ATTRIB) - fileDelete = Event(C.FILE_DELETE) - fileRenameTo = Event(C.FILE_RENAME_TO) - fileRenameFrom = Event(C.FILE_RENAME_FROM) - fileTrunc = Event(C.FILE_TRUNC) - fileNoFollow = Event(C.FILE_NOFOLLOW) - unmounted = Event(C.UNMOUNTED) - mountedOver = Event(C.MOUNTEDOVER) -) - -// PortEvent is a notify's equivalent of port_event_t. -type PortEvent struct { - PortevEvents int // PortevEvents is an equivalent of portev_events. - PortevSource uint8 // PortevSource is an equivalent of portev_source. - PortevPad uint8 // Portevpad is an equivalent of portev_pad. - PortevObject interface{} // PortevObject is an equivalent of portev_object. - PortevUser uintptr // PortevUser is an equivalent of portev_user. -} - -// FileObj is a notify's equivalent of file_obj. -type FileObj struct { - Atim syscall.Timespec // Atim is an equivalent of fo_atime. - Mtim syscall.Timespec // Mtim is an equivalent of fo_mtime. - Ctim syscall.Timespec // Ctim is an equivalent of fo_ctime. - Pad [3]uintptr // Pad is an equivalent of fo_pad. - Name string // Name is an equivalent of fo_name. -} - -type cfen struct { - p2pe map[string]*C.port_event_t - p2fo map[string]*C.struct_file_obj -} - -func newCfen() cfen { - return cfen{ - p2pe: make(map[string]*C.port_event_t), - p2fo: make(map[string]*C.struct_file_obj), - } -} - -func unix2C(sec int64, nsec int64) (C.time_t, C.long) { - return C.time_t(sec), C.long(nsec) -} - -func (c *cfen) portAssociate(p int, fo FileObj, e int) (err error) { - cfo := C.newFo() - cfo.fo_atime.tv_sec, cfo.fo_atime.tv_nsec = unix2C(fo.Atim.Unix()) - cfo.fo_mtime.tv_sec, cfo.fo_mtime.tv_nsec = unix2C(fo.Mtim.Unix()) - cfo.fo_ctime.tv_sec, cfo.fo_ctime.tv_nsec = unix2C(fo.Ctim.Unix()) - cfo.fo_name = C.CString(fo.Name) - c.p2fo[fo.Name] = cfo - _, err = C.port_associate(C.int(p), srcFile, C.conv(cfo), C.int(e), nil) - return -} - -func (c *cfen) portDissociate(port int, fo FileObj) (err error) { - cfo, ok := c.p2fo[fo.Name] - if !ok { - return errNotWatched - } - _, err = C.port_dissociate(C.int(port), srcFile, C.conv(cfo)) - C.free(unsafe.Pointer(cfo.fo_name)) - C.free(unsafe.Pointer(cfo)) - delete(c.p2fo, fo.Name) - return -} - -const srcAlert = C.PORT_SOURCE_ALERT -const srcFile = C.PORT_SOURCE_FILE -const alertSet = C.PORT_ALERT_SET - -func cfo2fo(cfo *C.struct_file_obj) *FileObj { - // Currently remaining attributes are not used. - if cfo == nil { - return nil - } - var fo FileObj - fo.Name = C.GoString(cfo.fo_name) - return &fo -} - -func (c *cfen) portGet(port int, pe *PortEvent) (err error) { - cpe := C.newPe() - if _, err = C.port_get(C.int(port), cpe, nil); err != nil { - C.free(unsafe.Pointer(cpe)) - return - } - pe.PortevEvents, pe.PortevSource, pe.PortevPad = - int(cpe.portev_events), uint8(cpe.portev_source), uint8(cpe.portev_pad) - pe.PortevObject = cfo2fo(C.dconv(cpe.portev_object)) - pe.PortevUser = uintptr(cpe.portev_user) - C.free(unsafe.Pointer(cpe)) - return -} - -func (c *cfen) portCreate() (int, error) { - p, err := C.port_create() - return int(p), err -} - -func (c *cfen) portAlert(p int) (err error) { - _, err = C.port_alert(C.int(p), alertSet, C.int(666), nil) - return -} - -func (c *cfen) free() { - for i := range c.p2fo { - C.free(unsafe.Pointer(c.p2fo[i].fo_name)) - C.free(unsafe.Pointer(c.p2fo[i])) - } - for i := range c.p2pe { - C.free(unsafe.Pointer(c.p2pe[i])) - } - c.p2fo = make(map[string]*C.struct_file_obj) - c.p2pe = make(map[string]*C.port_event_t) -} diff --git a/vendor/github.com/rjeczalik/notify/watcher_fsevents.go b/vendor/github.com/rjeczalik/notify/watcher_fsevents.go deleted file mode 100644 index dab5286ef6..0000000000 --- a/vendor/github.com/rjeczalik/notify/watcher_fsevents.go +++ /dev/null @@ -1,311 +0,0 @@ -// Copyright (c) 2014-2015 The Notify Authors. All rights reserved. -// Use of this source code is governed by the MIT license that can be -// found in the LICENSE file. - -//go:build darwin && !kqueue && cgo -// +build darwin,!kqueue,cgo - -package notify - -import ( - "errors" - "strings" - "sync/atomic" -) - -const ( - failure = uint32(FSEventsMustScanSubDirs | FSEventsUserDropped | FSEventsKernelDropped) - filter = uint32(FSEventsCreated | FSEventsRemoved | FSEventsRenamed | - FSEventsModified | FSEventsInodeMetaMod) -) - -// FSEvent represents single file event. It is created out of values passed by -// FSEvents to FSEventStreamCallback function. -type FSEvent struct { - Path string // real path of the file or directory - ID uint64 // ID of the event (FSEventStreamEventId) - Flags uint32 // joint FSEvents* flags (FSEventStreamEventFlags) -} - -// splitflags separates event flags from single set into slice of flags. -func splitflags(set uint32) (e []uint32) { - for i := uint32(1); set != 0; i, set = i<<1, set>>1 { - if (set & 1) != 0 { - e = append(e, i) - } - } - return -} - -// watch represents a filesystem watchpoint. It is a higher level abstraction -// over FSEvents' stream, which implements filtering of file events based -// on path and event set. It emulates non-recursive watch-point by filtering out -// events which paths are more than 1 level deeper than the watched path. -type watch struct { - // prev stores last event set per path in order to filter out old flags - // for new events, which appratenly FSEvents likes to retain. It's a disgusting - // hack, it should be researched how to get rid of it. - prev map[string]uint32 - c chan<- EventInfo - stream *stream - path string - events uint32 - isrec int32 - flushed bool -} - -// Example format: -// -// ~ $ (trigger command) # (event set) -> (effective event set) -// -// Heuristics: -// -// 1. Create event is removed when it was present in previous event set. -// Example: -// -// ~ $ echo > file # Create|Write -> Create|Write -// ~ $ echo > file # Create|Write|InodeMetaMod -> Write|InodeMetaMod -// -// 2. Remove event is removed if it was present in previouse event set. -// Example: -// -// ~ $ touch file # Create -> Create -// ~ $ rm file # Create|Remove -> Remove -// ~ $ touch file # Create|Remove -> Create -// -// 3. Write event is removed if not followed by InodeMetaMod on existing -// file. Example: -// -// ~ $ echo > file # Create|Write -> Create|Write -// ~ $ chmod +x file # Create|Write|ChangeOwner -> ChangeOwner -// -// 4. Write&InodeMetaMod is removed when effective event set contain Remove event. -// Example: -// -// ~ $ echo > file # Write|InodeMetaMod -> Write|InodeMetaMod -// ~ $ rm file # Remove|Write|InodeMetaMod -> Remove -func (w *watch) strip(base string, set uint32) uint32 { - const ( - write = FSEventsModified | FSEventsInodeMetaMod - both = FSEventsCreated | FSEventsRemoved - ) - switch w.prev[base] { - case FSEventsCreated: - set &^= FSEventsCreated - if set&FSEventsRemoved != 0 { - w.prev[base] = FSEventsRemoved - set &^= write - } - case FSEventsRemoved: - set &^= FSEventsRemoved - if set&FSEventsCreated != 0 { - w.prev[base] = FSEventsCreated - } - default: - switch set & both { - case FSEventsCreated: - w.prev[base] = FSEventsCreated - case FSEventsRemoved: - w.prev[base] = FSEventsRemoved - set &^= write - } - } - dbgprintf("split()=%v\n", Event(set)) - return set -} - -// Dispatch is a stream function which forwards given file events for the watched -// path to underlying FileInfo channel. -func (w *watch) Dispatch(ev []FSEvent) { - events := atomic.LoadUint32(&w.events) - isrec := (atomic.LoadInt32(&w.isrec) == 1) - for i := range ev { - if ev[i].Flags&FSEventsHistoryDone != 0 { - w.flushed = true - continue - } - if !w.flushed { - continue - } - dbgprintf("%v (0x%x) (%s, i=%d, ID=%d, len=%d)\n", Event(ev[i].Flags), - ev[i].Flags, ev[i].Path, i, ev[i].ID, len(ev)) - if ev[i].Flags&failure != 0 && failure&events == 0 { - // TODO(rjeczalik): missing error handling - continue - } - if !strings.HasPrefix(ev[i].Path, w.path) { - continue - } - n := len(w.path) - base := "" - if len(ev[i].Path) > n { - if ev[i].Path[n] != '/' { - continue - } - base = ev[i].Path[n+1:] - if !isrec && strings.IndexByte(base, '/') != -1 { - continue - } - } - // TODO(rjeczalik): get diff only from filtered events? - e := w.strip(string(base), ev[i].Flags) & events - if e == 0 { - continue - } - for _, e := range splitflags(e) { - dbgprintf("%d: single event: %v", ev[i].ID, Event(e)) - w.c <- &event{ - fse: ev[i], - event: Event(e), - } - } - } -} - -// Stop closes underlying FSEvents stream and stops dispatching events. -func (w *watch) Stop() { - w.stream.Stop() - // TODO(rjeczalik): make (*stream).Stop flush synchronously undelivered events, - // so the following hack can be removed. It should flush all the streams - // concurrently as we care not to block too much here. - atomic.StoreUint32(&w.events, 0) - atomic.StoreInt32(&w.isrec, 0) -} - -// fsevents implements Watcher and RecursiveWatcher interfaces backed by FSEvents -// framework. -type fsevents struct { - watches map[string]*watch - c chan<- EventInfo -} - -func newWatcher(c chan<- EventInfo) watcher { - return &fsevents{ - watches: make(map[string]*watch), - c: c, - } -} - -func (fse *fsevents) watch(path string, event Event, isrec int32) (err error) { - if _, ok := fse.watches[path]; ok { - return errAlreadyWatched - } - w := &watch{ - prev: make(map[string]uint32), - c: fse.c, - path: path, - events: uint32(event), - isrec: isrec, - } - w.stream = newStream(path, w.Dispatch) - if err = w.stream.Start(); err != nil { - return err - } - fse.watches[path] = w - return nil -} - -func (fse *fsevents) unwatch(path string) (err error) { - w, ok := fse.watches[path] - if !ok { - return errNotWatched - } - w.stream.Stop() - delete(fse.watches, path) - return nil -} - -// Watch implements Watcher interface. It fails with non-nil error when setting -// the watch-point by FSEvents fails or with errAlreadyWatched error when -// the given path is already watched. -func (fse *fsevents) Watch(path string, event Event) error { - return fse.watch(path, event, 0) -} - -// Unwatch implements Watcher interface. It fails with errNotWatched when -// the given path is not being watched. -func (fse *fsevents) Unwatch(path string) error { - return fse.unwatch(path) -} - -// Rewatch implements Watcher interface. It fails with errNotWatched when -// the given path is not being watched or with errInvalidEventSet when oldevent -// does not match event set the watch-point currently holds. -func (fse *fsevents) Rewatch(path string, oldevent, newevent Event) error { - w, ok := fse.watches[path] - if !ok { - return errNotWatched - } - if !atomic.CompareAndSwapUint32(&w.events, uint32(oldevent), uint32(newevent)) { - return errInvalidEventSet - } - atomic.StoreInt32(&w.isrec, 0) - return nil -} - -// RecursiveWatch implements RecursiveWatcher interface. It fails with non-nil -// error when setting the watch-point by FSEvents fails or with errAlreadyWatched -// error when the given path is already watched. -func (fse *fsevents) RecursiveWatch(path string, event Event) error { - return fse.watch(path, event, 1) -} - -// RecursiveUnwatch implements RecursiveWatcher interface. It fails with -// errNotWatched when the given path is not being watched. -// -// TODO(rjeczalik): fail if w.isrec == 0? -func (fse *fsevents) RecursiveUnwatch(path string) error { - return fse.unwatch(path) -} - -// RecursiveRewatch implements RecursiveWatcher interface. It fails: -// -// - with errNotWatched when the given path is not being watched -// - with errInvalidEventSet when oldevent does not match the current event set -// - with errAlreadyWatched when watch-point given by the oldpath was meant to -// be relocated to newpath, but the newpath is already watched -// - a non-nil error when setting the watch-point with FSEvents fails -// -// TODO(rjeczalik): Improve handling of watch-point relocation? See two TODOs -// that follows. -func (fse *fsevents) RecursiveRewatch(oldpath, newpath string, oldevent, newevent Event) error { - switch [2]bool{oldpath == newpath, oldevent == newevent} { - case [2]bool{true, true}: - w, ok := fse.watches[oldpath] - if !ok { - return errNotWatched - } - atomic.StoreInt32(&w.isrec, 1) - return nil - case [2]bool{true, false}: - w, ok := fse.watches[oldpath] - if !ok { - return errNotWatched - } - if !atomic.CompareAndSwapUint32(&w.events, uint32(oldevent), uint32(newevent)) { - return errors.New("invalid event state diff") - } - atomic.StoreInt32(&w.isrec, 1) - return nil - default: - // TODO(rjeczalik): rewatch newpath only if exists? - // TODO(rjeczalik): migrate w.prev to new watch? - if _, ok := fse.watches[newpath]; ok { - return errAlreadyWatched - } - if err := fse.Unwatch(oldpath); err != nil { - return err - } - // TODO(rjeczalik): revert unwatch if watch fails? - return fse.watch(newpath, newevent, 1) - } -} - -// Close unwatches all watch-points. -func (fse *fsevents) Close() error { - for _, w := range fse.watches { - w.Stop() - } - fse.watches = nil - return nil -} diff --git a/vendor/github.com/rjeczalik/notify/watcher_fsevents_cgo.go b/vendor/github.com/rjeczalik/notify/watcher_fsevents_cgo.go deleted file mode 100644 index 7cf7d71a99..0000000000 --- a/vendor/github.com/rjeczalik/notify/watcher_fsevents_cgo.go +++ /dev/null @@ -1,163 +0,0 @@ -// Copyright (c) 2014-2015 The Notify Authors. All rights reserved. -// Use of this source code is governed by the MIT license that can be -// found in the LICENSE file. - -//go:build darwin && !kqueue && cgo -// +build darwin,!kqueue,cgo - -package notify - -/* -#include -#include - -void gostream(uintptr_t, uintptr_t, size_t, uintptr_t, uintptr_t, uintptr_t); - -static FSEventStreamRef EventStreamCreate(FSEventStreamContext * context, uintptr_t info, CFArrayRef paths, FSEventStreamEventId since, CFTimeInterval latency, FSEventStreamCreateFlags flags) { - context->info = (void*) info; - return FSEventStreamCreate(NULL, (FSEventStreamCallback) gostream, context, paths, since, latency, flags); -} - -#cgo LDFLAGS: -framework CoreServices -*/ -import "C" - -import ( - "errors" - "os" - "sync" - "sync/atomic" - "unsafe" -) - -var nilstream C.FSEventStreamRef - -// Default arguments for FSEventStreamCreate function. -var ( - latency C.CFTimeInterval - flags = C.FSEventStreamCreateFlags(C.kFSEventStreamCreateFlagFileEvents | C.kFSEventStreamCreateFlagNoDefer) - since = uint64(C.FSEventsGetCurrentEventId()) -) - -// global dispatch queue which all streams are registered with -var q C.dispatch_queue_t = C.dispatch_queue_create( - C.CString("com.github.rjeczalik.notify"), - (C.dispatch_queue_attr_t)(C.DISPATCH_QUEUE_SERIAL), -) - -// Errors returned when FSEvents functions fail. -var ( - errCreate = os.NewSyscallError("FSEventStreamCreate", errors.New("NULL")) - errStart = os.NewSyscallError("FSEventStreamStart", errors.New("false")) -) - -//export gostream -func gostream(_, info uintptr, n C.size_t, paths, flags, ids uintptr) { - const ( - offchar = unsafe.Sizeof((*C.char)(nil)) - offflag = unsafe.Sizeof(C.FSEventStreamEventFlags(0)) - offid = unsafe.Sizeof(C.FSEventStreamEventId(0)) - ) - if n == 0 { - return - } - fn := streamFuncs.get(info) - if fn == nil { - return - } - ev := make([]FSEvent, 0, int(n)) - for i := uintptr(0); i < uintptr(n); i++ { - switch flags := *(*uint32)(unsafe.Pointer((flags + i*offflag))); { - case flags&uint32(FSEventsEventIdsWrapped) != 0: - atomic.StoreUint64(&since, uint64(C.FSEventsGetCurrentEventId())) - default: - ev = append(ev, FSEvent{ - Path: C.GoString(*(**C.char)(unsafe.Pointer(paths + i*offchar))), - Flags: flags, - ID: *(*uint64)(unsafe.Pointer(ids + i*offid)), - }) - } - - } - fn(ev) -} - -// StreamFunc is a callback called when stream receives file events. -type streamFunc func([]FSEvent) - -var streamFuncs = streamFuncRegistry{m: map[uintptr]streamFunc{}} - -type streamFuncRegistry struct { - mu sync.Mutex - m map[uintptr]streamFunc - i uintptr -} - -func (r *streamFuncRegistry) get(id uintptr) streamFunc { - r.mu.Lock() - defer r.mu.Unlock() - return r.m[id] -} - -func (r *streamFuncRegistry) add(fn streamFunc) uintptr { - r.mu.Lock() - defer r.mu.Unlock() - r.i++ - r.m[r.i] = fn - return r.i -} - -func (r *streamFuncRegistry) delete(id uintptr) { - r.mu.Lock() - defer r.mu.Unlock() - delete(r.m, id) -} - -// Stream represents a single watch-point which listens for events scheduled on the global dispatch queue. -type stream struct { - path string - ref C.FSEventStreamRef - info uintptr -} - -// NewStream creates a stream for given path, listening for file events and -// calling fn upon receiving any. -func newStream(path string, fn streamFunc) *stream { - return &stream{ - path: path, - info: streamFuncs.add(fn), - } -} - -// Start creates a FSEventStream for the given path and schedules on the global dispatch queue. -// It's a nop if the stream was already started. -func (s *stream) Start() error { - if s.ref != nilstream { - return nil - } - p := C.CFStringCreateWithCStringNoCopy(C.kCFAllocatorDefault, C.CString(s.path), C.kCFStringEncodingUTF8, C.kCFAllocatorDefault) - path := C.CFArrayCreate(C.kCFAllocatorDefault, (*unsafe.Pointer)(unsafe.Pointer(&p)), 1, nil) - ctx := C.FSEventStreamContext{} - ref := C.EventStreamCreate(&ctx, C.uintptr_t(s.info), path, C.FSEventStreamEventId(atomic.LoadUint64(&since)), latency, flags) - if ref == nilstream { - return errCreate - } - C.FSEventStreamSetDispatchQueue(ref, q) - if C.FSEventStreamStart(ref) == C.Boolean(0) { - C.FSEventStreamInvalidate(ref) - return errStart - } - s.ref = ref - return nil -} - -// Stop stops underlying FSEventStream and unregisters it from the global dispatch queue. -func (s *stream) Stop() { - if s.ref == nilstream { - return - } - C.FSEventStreamStop(s.ref) - C.FSEventStreamInvalidate(s.ref) - s.ref = nilstream - streamFuncs.delete(s.info) -} diff --git a/vendor/github.com/rjeczalik/notify/watcher_inotify.go b/vendor/github.com/rjeczalik/notify/watcher_inotify.go deleted file mode 100644 index 02b4328449..0000000000 --- a/vendor/github.com/rjeczalik/notify/watcher_inotify.go +++ /dev/null @@ -1,400 +0,0 @@ -// Copyright (c) 2014-2015 The Notify Authors. All rights reserved. -// Use of this source code is governed by the MIT license that can be -// found in the LICENSE file. - -//go:build linux -// +build linux - -package notify - -import ( - "bytes" - "errors" - "path/filepath" - "runtime" - "sync" - "sync/atomic" - "unsafe" - - "golang.org/x/sys/unix" -) - -// eventBufferSize defines the size of the buffer given to read(2) function. One -// should not depend on this value, since it was arbitrary chosen and may be -// changed in the future. -const eventBufferSize = 64 * (unix.SizeofInotifyEvent + unix.PathMax + 1) - -// consumersCount defines the number of consumers in producer-consumer based -// implementation. Each consumer is run in a separate goroutine and has read -// access to watched files map. -const consumersCount = 2 - -const invalidDescriptor = -1 - -// watched is a pair of file path and inotify mask used as a value in -// watched files map. -type watched struct { - path string - mask uint32 -} - -// inotify implements Watcher interface. -type inotify struct { - sync.RWMutex // protects inotify.m map - m map[int32]*watched // watch descriptor to watched object - fd int32 // inotify file descriptor - pipefd []int // pipe's read and write descriptors - epfd int // epoll descriptor - epes []unix.EpollEvent // epoll events - buffer [eventBufferSize]byte // inotify event buffer - wg sync.WaitGroup // wait group used to close main loop - c chan<- EventInfo // event dispatcher channel -} - -// NewWatcher creates new non-recursive inotify backed by inotify. -func newWatcher(c chan<- EventInfo) watcher { - i := &inotify{ - m: make(map[int32]*watched), - fd: invalidDescriptor, - pipefd: []int{invalidDescriptor, invalidDescriptor}, - epfd: invalidDescriptor, - epes: make([]unix.EpollEvent, 0), - c: c, - } - runtime.SetFinalizer(i, func(i *inotify) { - i.epollclose() - if i.fd != invalidDescriptor { - unix.Close(int(i.fd)) - } - }) - return i -} - -// Watch implements notify.watcher interface. -func (i *inotify) Watch(path string, e Event) error { - return i.watch(path, e) -} - -// Rewatch implements notify.watcher interface. -func (i *inotify) Rewatch(path string, _, newevent Event) error { - return i.watch(path, newevent) -} - -// watch adds a new watcher to the set of watched objects or modifies the existing -// one. If called for the first time, this function initializes inotify filesystem -// monitor and starts producer-consumers goroutines. -func (i *inotify) watch(path string, e Event) (err error) { - if e&^(All|Event(unix.IN_ALL_EVENTS)) != 0 { - return errors.New("notify: unknown event") - } - if err = i.lazyinit(); err != nil { - return - } - iwd, err := unix.InotifyAddWatch(int(i.fd), path, encode(e)) - if err != nil { - return - } - i.Lock() - if wd, ok := i.m[int32(iwd)]; !ok { - i.m[int32(iwd)] = &watched{path: path, mask: uint32(e)} - } else { - wd.path = path - wd.mask = uint32(e) - } - i.Unlock() - return nil -} - -// lazyinit sets up all required file descriptors and starts 1+consumersCount -// goroutines. The producer goroutine blocks until file-system notifications -// occur. Then, all events are read from system buffer and sent to consumer -// goroutines which construct valid notify events. This method uses -// Double-Checked Locking optimization. -func (i *inotify) lazyinit() error { - if atomic.LoadInt32(&i.fd) == invalidDescriptor { - i.Lock() - defer i.Unlock() - if atomic.LoadInt32(&i.fd) == invalidDescriptor { - fd, err := unix.InotifyInit1(unix.IN_CLOEXEC) - if err != nil { - return err - } - i.fd = int32(fd) - if err = i.epollinit(); err != nil { - _, _ = i.epollclose(), unix.Close(int(fd)) // Ignore errors. - i.fd = invalidDescriptor - return err - } - esch := make(chan []*event) - go i.loop(esch) - i.wg.Add(consumersCount) - for n := 0; n < consumersCount; n++ { - go i.send(esch) - } - } - } - return nil -} - -// epollinit opens an epoll file descriptor and creates a pipe which will be -// used to wake up the epoll_wait(2) function. Then, file descriptor associated -// with inotify event queue and the read end of the pipe are added to epoll set. -// Note that `fd` member must be set before this function is called. -func (i *inotify) epollinit() (err error) { - if i.epfd, err = unix.EpollCreate1(0); err != nil { - return - } - if err = unix.Pipe(i.pipefd); err != nil { - return - } - i.epes = []unix.EpollEvent{ - {Events: unix.EPOLLIN, Fd: i.fd}, - {Events: unix.EPOLLIN, Fd: int32(i.pipefd[0])}, - } - if err = unix.EpollCtl(i.epfd, unix.EPOLL_CTL_ADD, int(i.fd), &i.epes[0]); err != nil { - return - } - return unix.EpollCtl(i.epfd, unix.EPOLL_CTL_ADD, i.pipefd[0], &i.epes[1]) -} - -// epollclose closes the file descriptor created by the call to epoll_create(2) -// and two file descriptors opened by pipe(2) function. -func (i *inotify) epollclose() (err error) { - if i.epfd != invalidDescriptor { - if err = unix.Close(i.epfd); err == nil { - i.epfd = invalidDescriptor - } - } - for n, fd := range i.pipefd { - if fd != invalidDescriptor { - switch e := unix.Close(fd); { - case e != nil && err == nil: - err = e - case e == nil: - i.pipefd[n] = invalidDescriptor - } - } - } - return -} - -// loop blocks until either inotify or pipe file descriptor is ready for I/O. -// All read operations triggered by filesystem notifications are forwarded to -// one of the event's consumers. If pipe fd became ready, loop function closes -// all file descriptors opened by lazyinit method and returns afterwards. -func (i *inotify) loop(esch chan<- []*event) { - epes := make([]unix.EpollEvent, 1) - fd := atomic.LoadInt32(&i.fd) - for { - switch _, err := unix.EpollWait(i.epfd, epes, -1); err { - case nil: - switch epes[0].Fd { - case fd: - esch <- i.read() - epes[0].Fd = 0 - case int32(i.pipefd[0]): - i.Lock() - defer i.Unlock() - if err = unix.Close(int(fd)); err != nil && err != unix.EINTR { - panic("notify: close(2) error " + err.Error()) - } - atomic.StoreInt32(&i.fd, invalidDescriptor) - if err = i.epollclose(); err != nil && err != unix.EINTR { - panic("notify: epollclose error " + err.Error()) - } - close(esch) - return - } - case unix.EINTR: - continue - default: // We should never reach this line. - panic("notify: epoll_wait(2) error " + err.Error()) - } - } -} - -// read reads events from an inotify file descriptor. It does not handle errors -// returned from read(2) function since they are not critical to watcher logic. -func (i *inotify) read() (es []*event) { - n, err := unix.Read(int(i.fd), i.buffer[:]) - if err != nil || n < unix.SizeofInotifyEvent { - return - } - var sys *unix.InotifyEvent - nmin := n - unix.SizeofInotifyEvent - for pos, path := 0, ""; pos <= nmin; { - sys = (*unix.InotifyEvent)(unsafe.Pointer(&i.buffer[pos])) - pos += unix.SizeofInotifyEvent - if path = ""; sys.Len > 0 { - endpos := pos + int(sys.Len) - path = string(bytes.TrimRight(i.buffer[pos:endpos], "\x00")) - pos = endpos - } - es = append(es, &event{ - sys: unix.InotifyEvent{ - Wd: sys.Wd, - Mask: sys.Mask, - Cookie: sys.Cookie, - }, - path: path, - }) - } - return -} - -// send is a consumer function which sends events to event dispatcher channel. -// It is run in a separate goroutine in order to not block loop method when -// possibly expensive write operations are performed on inotify map. -func (i *inotify) send(esch <-chan []*event) { - for es := range esch { - for _, e := range i.transform(es) { - if e != nil { - i.c <- e - } - } - } - i.wg.Done() -} - -// transform prepares events read from inotify file descriptor for sending to -// user. It removes invalid events and these which are no longer present in -// inotify map. This method may also split one raw event into two different ones -// when system-dependent result is required. -func (i *inotify) transform(es []*event) []*event { - var multi []*event - i.RLock() - for idx, e := range es { - if e.sys.Mask&(unix.IN_IGNORED|unix.IN_Q_OVERFLOW) != 0 { - es[idx] = nil - continue - } - wd, ok := i.m[e.sys.Wd] - if !ok || e.sys.Mask&encode(Event(wd.mask)) == 0 { - es[idx] = nil - continue - } - if e.path == "" { - e.path = wd.path - } else { - e.path = filepath.Join(wd.path, e.path) - } - multi = append(multi, decode(Event(wd.mask), e)) - if e.event == 0 { - es[idx] = nil - } - } - i.RUnlock() - es = append(es, multi...) - return es -} - -// encode converts notify system-independent events to valid inotify mask -// which can be passed to inotify_add_watch(2) function. -func encode(e Event) uint32 { - if e&Create != 0 { - e = (e ^ Create) | InCreate | InMovedTo - } - if e&Remove != 0 { - e = (e ^ Remove) | InDelete | InDeleteSelf - } - if e&Write != 0 { - e = (e ^ Write) | InModify - } - if e&Rename != 0 { - e = (e ^ Rename) | InMovedFrom | InMoveSelf - } - return uint32(e) -} - -// decode uses internally stored mask to distinguish whether system-independent -// or system-dependent event is requested. The first one is created by modifying -// `e` argument. decode method sets e.event value to 0 when an event should be -// skipped. System-dependent event is set as the function's return value which -// can be nil when the event should not be passed on. -func decode(mask Event, e *event) (syse *event) { - if sysmask := uint32(mask) & e.sys.Mask; sysmask != 0 { - syse = &event{sys: unix.InotifyEvent{ - Wd: e.sys.Wd, - Mask: e.sys.Mask, - Cookie: e.sys.Cookie, - }, event: Event(sysmask), path: e.path} - } - imask := encode(mask) - switch { - case mask&Create != 0 && imask&uint32(InCreate|InMovedTo)&e.sys.Mask != 0: - e.event = Create - case mask&Remove != 0 && imask&uint32(InDelete|InDeleteSelf)&e.sys.Mask != 0: - e.event = Remove - case mask&Write != 0 && imask&uint32(InModify)&e.sys.Mask != 0: - e.event = Write - case mask&Rename != 0 && imask&uint32(InMovedFrom|InMoveSelf)&e.sys.Mask != 0: - e.event = Rename - default: - e.event = 0 - } - return -} - -// Unwatch implements notify.watcher interface. It looks for watch descriptor -// related to registered path and if found, calls inotify_rm_watch(2) function. -// This method is allowed to return EINVAL error when concurrently requested to -// delete identical path. -func (i *inotify) Unwatch(path string) (err error) { - iwd := int32(invalidDescriptor) - i.RLock() - for iwdkey, wd := range i.m { - if wd.path == path { - iwd = iwdkey - break - } - } - i.RUnlock() - if iwd == invalidDescriptor { - return errors.New("notify: path " + path + " is already watched") - } - fd := atomic.LoadInt32(&i.fd) - if err = removeInotifyWatch(fd, iwd); err != nil { - return - } - i.Lock() - delete(i.m, iwd) - i.Unlock() - return nil -} - -// Close implements notify.watcher interface. It removes all existing watch -// descriptors and wakes up producer goroutine by sending data to the write end -// of the pipe. The function waits for a signal from producer which means that -// all operations on current monitoring instance are done. -func (i *inotify) Close() (err error) { - i.Lock() - if fd := atomic.LoadInt32(&i.fd); fd == invalidDescriptor { - i.Unlock() - return nil - } - for iwd := range i.m { - if e := removeInotifyWatch(i.fd, iwd); e != nil && err == nil { - err = e - } - delete(i.m, iwd) - } - switch _, errwrite := unix.Write(i.pipefd[1], []byte{0x00}); { - case errwrite != nil && err == nil: - err = errwrite - fallthrough - case errwrite != nil: - i.Unlock() - default: - i.Unlock() - i.wg.Wait() - } - return -} - -// if path was removed, notify already removed the watch and returns EINVAL error -func removeInotifyWatch(fd int32, iwd int32) (err error) { - if _, err = unix.InotifyRmWatch(int(fd), uint32(iwd)); err != nil && err != unix.EINVAL { - return - } - return nil -} diff --git a/vendor/github.com/rjeczalik/notify/watcher_kqueue.go b/vendor/github.com/rjeczalik/notify/watcher_kqueue.go deleted file mode 100644 index 715edfb25c..0000000000 --- a/vendor/github.com/rjeczalik/notify/watcher_kqueue.go +++ /dev/null @@ -1,202 +0,0 @@ -// Copyright (c) 2014-2015 The Notify Authors. All rights reserved. -// Use of this source code is governed by the MIT license that can be -// found in the LICENSE file. - -//go:build (darwin && kqueue) || (darwin && !cgo) || dragonfly || freebsd || netbsd || openbsd -// +build darwin,kqueue darwin,!cgo dragonfly freebsd netbsd openbsd - -package notify - -import ( - "errors" - "fmt" - "os" - "syscall" -) - -// newTrigger returns implementation of trigger. -func newTrigger(pthLkp map[string]*watched) trigger { - return &kq{ - pthLkp: pthLkp, - idLkp: make(map[int]*watched), - } -} - -// kq is a structure implementing trigger for kqueue. -type kq struct { - // fd is a kqueue file descriptor - fd int - // pipefds are file descriptors used to stop `Kevent` call. - pipefds [2]int - // idLkp is a data structure mapping file descriptors with data about watching - // represented by them files/directories. - idLkp map[int]*watched - // pthLkp is a structure mapping monitored files/dir with data about them, - // shared with parent trg structure - pthLkp map[string]*watched -} - -// watched is a data structure representing watched file/directory. -type watched struct { - trgWatched - // fd is a file descriptor for watched file/directory. - fd int -} - -// Stop implements trigger. -func (k *kq) Stop() (err error) { - // trigger event used to interrupt Kevent call. - _, err = syscall.Write(k.pipefds[1], []byte{0x00}) - return -} - -// Close implements trigger. -func (k *kq) Close() error { - return syscall.Close(k.fd) -} - -// NewWatched implements trigger. -func (*kq) NewWatched(p string, fi os.FileInfo) (*watched, error) { - fd, err := syscall.Open(p, syscall.O_NONBLOCK|syscall.O_RDONLY, 0) - if err != nil { - // BSDs can't open symlinks and return an error if the symlink - // cannot be followed - ignore it instead of failing. See e.g. - // https://github.com/libinotify-kqueue/libinotify-kqueue/blob/a822c8f1d75404fe3132f695a898dcd42fe8afbc/patches/freebsd11-O_SYMLINK.patch - if os.IsNotExist(err) && fi.Mode()&os.ModeSymlink == os.ModeSymlink { - return nil, errSkip - } - // FreeBSD can't open unix domain sockets and returns "operation not supported" error. - // Ignore it instead of failing. - if errors.Is(err, syscall.ENOTSUP) && fi.Mode()&os.ModeSocket == os.ModeSocket { - return nil, errSkip - } - return nil, err - } - return &watched{ - trgWatched: trgWatched{p: p, fi: fi}, - fd: fd, - }, nil -} - -// Record implements trigger. -func (k *kq) Record(w *watched) { - k.idLkp[w.fd], k.pthLkp[w.p] = w, w -} - -// Del implements trigger. -func (k *kq) Del(w *watched) { - syscall.Close(w.fd) - delete(k.idLkp, w.fd) - delete(k.pthLkp, w.p) -} - -func inter2kq(n interface{}) syscall.Kevent_t { - kq, ok := n.(syscall.Kevent_t) - if !ok { - panic(fmt.Sprintf("kqueue: type should be Kevent_t, %T instead", n)) - } - return kq -} - -// Init implements trigger. -func (k *kq) Init() (err error) { - if k.fd, err = syscall.Kqueue(); err != nil { - return - } - // Creates pipe used to stop `Kevent` call by registering it, - // watching read end and writing to other end of it. - if err = syscall.Pipe(k.pipefds[:]); err != nil { - return nonil(err, k.Close()) - } - var kevn [1]syscall.Kevent_t - syscall.SetKevent(&kevn[0], k.pipefds[0], syscall.EVFILT_READ, syscall.EV_ADD) - if _, err = syscall.Kevent(k.fd, kevn[:], nil, nil); err != nil { - return nonil(err, k.Close()) - } - return -} - -// Unwatch implements trigger. -func (k *kq) Unwatch(w *watched) (err error) { - var kevn [1]syscall.Kevent_t - syscall.SetKevent(&kevn[0], w.fd, syscall.EVFILT_VNODE, syscall.EV_DELETE) - - _, err = syscall.Kevent(k.fd, kevn[:], nil, nil) - return -} - -// Watch implements trigger. -func (k *kq) Watch(fi os.FileInfo, w *watched, e int64) (err error) { - var kevn [1]syscall.Kevent_t - syscall.SetKevent(&kevn[0], w.fd, syscall.EVFILT_VNODE, - syscall.EV_ADD|syscall.EV_CLEAR) - kevn[0].Fflags = uint32(e) - - _, err = syscall.Kevent(k.fd, kevn[:], nil, nil) - return -} - -// Wait implements trigger. -func (k *kq) Wait() (interface{}, error) { - var ( - kevn [1]syscall.Kevent_t - err error - ) - kevn[0] = syscall.Kevent_t{} - _, err = syscall.Kevent(k.fd, nil, kevn[:], nil) - - return kevn[0], err -} - -// Watched implements trigger. -func (k *kq) Watched(n interface{}) (*watched, int64, error) { - kevn, ok := n.(syscall.Kevent_t) - if !ok { - panic(fmt.Sprintf("kq: type should be syscall.Kevent_t, %T instead", kevn)) - } - if _, ok = k.idLkp[int(kevn.Ident)]; !ok { - return nil, 0, errNotWatched - } - return k.idLkp[int(kevn.Ident)], int64(kevn.Fflags), nil -} - -// IsStop implements trigger. -func (k *kq) IsStop(n interface{}, err error) bool { - return int(inter2kq(n).Ident) == k.pipefds[0] -} - -func init() { - encode = func(e Event, dir bool) (o int64) { - // Create event is not supported by kqueue. Instead NoteWrite event will - // be registered for a directory. If this event will be reported on dir - // which is to be monitored for Create, dir will be rescanned - // and Create events will be generated and returned for new files. - // In case of files, if not requested NoteRename event is reported, - // it will be ignored. - o = int64(e &^ Create) - if (e&Create != 0 && dir) || e&Write != 0 { - o = (o &^ int64(Write)) | int64(NoteWrite) - } - if e&Rename != 0 { - o = (o &^ int64(Rename)) | int64(NoteRename) - } - if e&Remove != 0 { - o = (o &^ int64(Remove)) | int64(NoteDelete) - } - return - } - nat2not = map[Event]Event{ - NoteWrite: Write, - NoteRename: Rename, - NoteDelete: Remove, - NoteExtend: Event(0), - NoteAttrib: Event(0), - NoteRevoke: Event(0), - NoteLink: Event(0), - } - not2nat = map[Event]Event{ - Write: NoteWrite, - Rename: NoteRename, - Remove: NoteDelete, - } -} diff --git a/vendor/github.com/rjeczalik/notify/watcher_notimplemented.go b/vendor/github.com/rjeczalik/notify/watcher_notimplemented.go deleted file mode 100644 index 9e51766924..0000000000 --- a/vendor/github.com/rjeczalik/notify/watcher_notimplemented.go +++ /dev/null @@ -1,15 +0,0 @@ -// Copyright (c) 2014-2018 The Notify Authors. All rights reserved. -// Use of this source code is governed by the MIT license that can be -// found in the LICENSE file. - -//go:build !darwin && !linux && !freebsd && !dragonfly && !netbsd && !openbsd && !windows && !kqueue && !solaris && !illumos -// +build !darwin,!linux,!freebsd,!dragonfly,!netbsd,!openbsd,!windows,!kqueue,!solaris,!illumos - -package notify - -import "errors" - -// newWatcher stub. -func newWatcher(chan<- EventInfo) watcher { - return watcherStub{errors.New("notify: not implemented")} -} diff --git a/vendor/github.com/rjeczalik/notify/watcher_readdcw.go b/vendor/github.com/rjeczalik/notify/watcher_readdcw.go deleted file mode 100644 index b0dee4126b..0000000000 --- a/vendor/github.com/rjeczalik/notify/watcher_readdcw.go +++ /dev/null @@ -1,612 +0,0 @@ -// Copyright (c) 2014-2020 The Notify Authors. All rights reserved. -// Use of this source code is governed by the MIT license that can be -// found in the LICENSE file. - -//go:build windows -// +build windows - -package notify - -import ( - "errors" - "runtime" - "sync" - "sync/atomic" - "syscall" - "unsafe" -) - -// readBufferSize defines the size of an array in which read statuses are stored. -// The buffer have to be DWORD-aligned and, if notify is used in monitoring a -// directory over the network, its size must not be greater than 64KB. Each of -// watched directories uses its own buffer for storing events. -const readBufferSize = 4096 - -// Since all operations which go through the Windows completion routine are done -// asynchronously, filter may set one of the constants below. They were defined -// in order to distinguish whether current folder should be re-registered in -// ReadDirectoryChangesW function or some control operations need to be executed. -const ( - stateRewatch uint32 = 1 << (28 + iota) - stateUnwatch - stateCPClose -) - -// Filter used in current implementation was split into four segments: -// - bits 0-11 store ReadDirectoryChangesW filters, -// - bits 12-19 store File notify actions, -// - bits 20-27 store notify specific events and flags, -// - bits 28-31 store states which are used in loop's FSM. -// -// Constants below are used as masks to retrieve only specific filter parts. -const ( - onlyNotifyChanges uint32 = 0x00000FFF - onlyNGlobalEvents uint32 = 0x0FF00000 - onlyMachineStates uint32 = 0xF0000000 -) - -// grip represents a single watched directory. It stores the data required by -// ReadDirectoryChangesW function. Only the filter, recursive, and handle members -// may by modified by watcher implementation. Rest of the them have to remain -// constant since they are used by Windows completion routine. This indicates that -// grip can be removed only when all operations on the file handle are finished. -type grip struct { - handle syscall.Handle - filter uint32 - recursive bool - pathw []uint16 - buffer [readBufferSize]byte - parent *watched - ovlapped *overlappedEx -} - -// overlappedEx stores information used in asynchronous input and output. -// Additionally, overlappedEx contains a pointer to 'grip' item which is used in -// order to gather the structure in which the overlappedEx object was created. -type overlappedEx struct { - syscall.Overlapped - parent *grip -} - -// newGrip creates a new file handle that can be used in overlapped operations. -// Then, the handle is associated with I/O completion port 'cph' and its value -// is stored in newly created 'grip' object. -func newGrip(cph syscall.Handle, parent *watched, filter uint32) (*grip, error) { - g := &grip{ - handle: syscall.InvalidHandle, - filter: filter, - recursive: parent.recursive, - pathw: parent.pathw, - parent: parent, - ovlapped: &overlappedEx{}, - } - if err := g.register(cph); err != nil { - return nil, err - } - g.ovlapped.parent = g - return g, nil -} - -// NOTE : Thread safe -func (g *grip) register(cph syscall.Handle) (err error) { - if g.handle, err = syscall.CreateFile( - &g.pathw[0], - syscall.FILE_LIST_DIRECTORY, - syscall.FILE_SHARE_READ|syscall.FILE_SHARE_WRITE|syscall.FILE_SHARE_DELETE, - nil, - syscall.OPEN_EXISTING, - syscall.FILE_FLAG_BACKUP_SEMANTICS|syscall.FILE_FLAG_OVERLAPPED, - 0, - ); err != nil { - return - } - if _, err = syscall.CreateIoCompletionPort(g.handle, cph, 0, 0); err != nil { - syscall.CloseHandle(g.handle) - return - } - return g.readDirChanges() -} - -// readDirChanges tells the system to store file change information in grip's -// buffer. Directory changes that occur between calls to this function are added -// to the buffer and then, returned with the next call. -func (g *grip) readDirChanges() error { - handle := syscall.Handle(atomic.LoadUintptr((*uintptr)(&g.handle))) - if handle == syscall.InvalidHandle { - return nil // Handle was closed. - } - - return syscall.ReadDirectoryChanges( - handle, - &g.buffer[0], - uint32(unsafe.Sizeof(g.buffer)), - g.recursive, - encode(g.filter), - nil, - (*syscall.Overlapped)(unsafe.Pointer(g.ovlapped)), - 0, - ) -} - -// encode transforms a generic filter, which contains platform independent and -// implementation specific bit fields, to value that can be used as NotifyFilter -// parameter in ReadDirectoryChangesW function. -func encode(filter uint32) uint32 { - e := Event(filter & (onlyNGlobalEvents | onlyNotifyChanges)) - if e&dirmarker != 0 { - return uint32(FileNotifyChangeDirName) - } - if e&Create != 0 { - e = (e ^ Create) | FileNotifyChangeFileName - } - if e&Remove != 0 { - e = (e ^ Remove) | FileNotifyChangeFileName - } - if e&Write != 0 { - e = (e ^ Write) | FileNotifyChangeAttributes | FileNotifyChangeSize | - FileNotifyChangeCreation | FileNotifyChangeSecurity - } - if e&Rename != 0 { - e = (e ^ Rename) | FileNotifyChangeFileName - } - return uint32(e) -} - -// watched is made in order to check whether an action comes from a directory or -// file. This approach requires two file handlers per single monitored folder. The -// second grip handles actions which include creating or deleting a directory. If -// these processes are not monitored, only the first grip is created. -type watched struct { - filter uint32 - recursive bool - count uint8 - pathw []uint16 - digrip [2]*grip -} - -// newWatched creates a new watched instance. It splits the filter variable into -// two parts. The first part is responsible for watching all events which can be -// created for a file in watched directory structure and the second one watches -// only directory Create/Remove actions. If all operations succeed, the Create -// message is sent to I/O completion port queue for further processing. -func newWatched(cph syscall.Handle, filter uint32, recursive bool, - path string) (wd *watched, err error) { - wd = &watched{ - filter: filter, - recursive: recursive, - } - if wd.pathw, err = syscall.UTF16FromString(path); err != nil { - return - } - if err = wd.recreate(cph); err != nil { - return - } - return wd, nil -} - -// TODO : doc -func (wd *watched) recreate(cph syscall.Handle) (err error) { - filefilter := wd.filter &^ uint32(FileNotifyChangeDirName) - if err = wd.updateGrip(0, cph, filefilter == 0, filefilter); err != nil { - return - } - dirfilter := wd.filter & uint32(FileNotifyChangeDirName|Create|Remove) - if err = wd.updateGrip(1, cph, dirfilter == 0, wd.filter|uint32(dirmarker)); err != nil { - return - } - wd.filter &^= onlyMachineStates - return -} - -// TODO : doc -func (wd *watched) updateGrip(idx int, cph syscall.Handle, reset bool, - newflag uint32) (err error) { - if reset { - wd.digrip[idx] = nil - } else { - if wd.digrip[idx] == nil { - if wd.digrip[idx], err = newGrip(cph, wd, newflag); err != nil { - wd.closeHandle() - return - } - } else { - wd.digrip[idx].filter = newflag - wd.digrip[idx].recursive = wd.recursive - if err = wd.digrip[idx].register(cph); err != nil { - wd.closeHandle() - return - } - } - wd.count++ - } - return -} - -// closeHandle closes handles that are stored in digrip array. Function always -// tries to close all of the handlers before it exits, even when there are errors -// returned from the operating system kernel. -func (wd *watched) closeHandle() (err error) { - for _, g := range wd.digrip { - if g == nil { - continue - } - - for { - handle := syscall.Handle(atomic.LoadUintptr((*uintptr)(&g.handle))) - if handle == syscall.InvalidHandle { - break // Already closed. - } - - e := syscall.CloseHandle(handle) - if e != nil && err == nil { - err = e - } - - // Set invalid handle even when CloseHandle fails. This will leak - // the handle but, since we can't close it anyway, there won't be - // any difference. - if atomic.CompareAndSwapUintptr((*uintptr)(&g.handle), - (uintptr)(handle), (uintptr)(syscall.InvalidHandle)) { - break - } - } - } - return -} - -// watcher implements Watcher interface. It stores a set of watched directories. -// All operations which remove watched objects from map `m` must be performed in -// loop goroutine since these structures are used internally by operating system. -type readdcw struct { - sync.Mutex - m map[string]*watched - cph syscall.Handle - start bool - wg sync.WaitGroup - c chan<- EventInfo -} - -// NewWatcher creates new non-recursive watcher backed by ReadDirectoryChangesW. -func newWatcher(c chan<- EventInfo) watcher { - r := &readdcw{ - m: make(map[string]*watched), - cph: syscall.InvalidHandle, - c: c, - } - runtime.SetFinalizer(r, func(r *readdcw) { - if r.cph != syscall.InvalidHandle { - syscall.CloseHandle(r.cph) - } - }) - return r -} - -// Watch implements notify.Watcher interface. -func (r *readdcw) Watch(path string, event Event) error { - return r.watch(path, event, false) -} - -// RecursiveWatch implements notify.RecursiveWatcher interface. -func (r *readdcw) RecursiveWatch(path string, event Event) error { - return r.watch(path, event, true) -} - -// watch inserts a directory to the group of watched folders. If watched folder -// already exists, function tries to rewatch it with new filters(NOT VALID). Moreover, -// watch starts the main event loop goroutine when called for the first time. -func (r *readdcw) watch(path string, event Event, recursive bool) error { - if event&^(All|fileNotifyChangeAll) != 0 { - return errors.New("notify: unknown event") - } - - r.Lock() - defer r.Unlock() - - if wd, ok := r.m[path]; ok { - dbgprint("watch: already exists") - wd.filter &^= stateUnwatch - return nil - } - - if err := r.lazyinit(); err != nil { - return err - } - - wd, err := newWatched(r.cph, uint32(event), recursive, path) - if err != nil { - return err - } - - r.m[path] = wd - dbgprint("watch: new watch added") - - return nil -} - -// lazyinit creates an I/O completion port and starts the main event loop. -func (r *readdcw) lazyinit() (err error) { - invalid := uintptr(syscall.InvalidHandle) - - if atomic.LoadUintptr((*uintptr)(&r.cph)) == invalid { - cph := syscall.InvalidHandle - if cph, err = syscall.CreateIoCompletionPort(cph, 0, 0, 0); err != nil { - return - } - - r.cph, r.start = cph, true - go r.loop() - } - - return -} - -// TODO(pknap) : doc -func (r *readdcw) loop() { - var n, key uint32 - var overlapped *syscall.Overlapped - for { - err := syscall.GetQueuedCompletionStatus(r.cph, &n, &key, &overlapped, syscall.INFINITE) - if key == stateCPClose { - r.Lock() - handle := r.cph - r.cph = syscall.InvalidHandle - r.Unlock() - syscall.CloseHandle(handle) - r.wg.Done() - return - } - if overlapped == nil { - // TODO: check key == rewatch delete or 0(panic) - continue - } - overEx := (*overlappedEx)(unsafe.Pointer(overlapped)) - if overEx == nil || overEx.parent == nil { - dbgprintf("incomplete completion status transferred=%d, overlapped=%#v, key=%#b", n, overEx, key) - continue - } else if n != 0 { - r.loopevent(n, overEx) - } - if err = overEx.parent.readDirChanges(); err != nil { - // TODO: error handling - } - r.loopstate(overEx) - } -} - -// TODO(pknap) : doc -func (r *readdcw) loopstate(overEx *overlappedEx) { - r.Lock() - defer r.Unlock() - filter := overEx.parent.parent.filter - if filter&onlyMachineStates == 0 { - return - } - if overEx.parent.parent.count--; overEx.parent.parent.count == 0 { - switch filter & onlyMachineStates { - case stateRewatch: - dbgprint("loopstate rewatch") - overEx.parent.parent.recreate(r.cph) - case stateUnwatch: - dbgprint("loopstate unwatch") - overEx.parent.parent.closeHandle() - delete(r.m, syscall.UTF16ToString(overEx.parent.pathw)) - case stateCPClose: - default: - panic(`notify: windows loopstate logic error`) - } - } -} - -// TODO(pknap) : doc -func (r *readdcw) loopevent(n uint32, overEx *overlappedEx) { - events := []*event{} - var currOffset uint32 - for { - raw := (*syscall.FileNotifyInformation)(unsafe.Pointer(&overEx.parent.buffer[currOffset])) - name := syscall.UTF16ToString((*[syscall.MAX_LONG_PATH]uint16)(unsafe.Pointer(&raw.FileName))[:raw.FileNameLength>>1]) - events = append(events, &event{ - pathw: overEx.parent.pathw, - filter: overEx.parent.filter, - action: raw.Action, - name: name, - }) - if raw.NextEntryOffset == 0 { - break - } - if currOffset += raw.NextEntryOffset; currOffset >= n { - break - } - } - r.send(events) -} - -// TODO(pknap) : doc -func (r *readdcw) send(es []*event) { - for _, e := range es { - var syse Event - if e.e, syse = decode(e.filter, e.action); e.e == 0 && syse == 0 { - continue - } - switch { - case e.action == syscall.FILE_ACTION_MODIFIED: - e.ftype = fTypeUnknown - case e.filter&uint32(dirmarker) != 0: - e.ftype = fTypeDirectory - default: - e.ftype = fTypeFile - } - switch { - case e.e == 0: - e.e = syse - case syse != 0: - r.c <- &event{ - pathw: e.pathw, - name: e.name, - ftype: e.ftype, - action: e.action, - filter: e.filter, - e: syse, - } - } - r.c <- e - } -} - -// Rewatch implements notify.Rewatcher interface. -func (r *readdcw) Rewatch(path string, oldevent, newevent Event) error { - return r.rewatch(path, uint32(oldevent), uint32(newevent), false) -} - -// RecursiveRewatch implements notify.RecursiveRewatcher interface. -func (r *readdcw) RecursiveRewatch(oldpath, newpath string, oldevent, - newevent Event) error { - if oldpath != newpath { - if err := r.unwatch(oldpath); err != nil { - return err - } - return r.watch(newpath, newevent, true) - } - return r.rewatch(newpath, uint32(oldevent), uint32(newevent), true) -} - -// TODO : (pknap) doc. -func (r *readdcw) rewatch(path string, oldevent, newevent uint32, recursive bool) (err error) { - if Event(newevent)&^(All|fileNotifyChangeAll) != 0 { - return errors.New("notify: unknown event") - } - var wd *watched - r.Lock() - defer r.Unlock() - if wd, err = r.nonStateWatchedLocked(path); err != nil { - return - } - if wd.filter&(onlyNotifyChanges|onlyNGlobalEvents) != oldevent { - panic(`notify: windows re-watcher logic error`) - } - wd.filter = stateRewatch | newevent - wd.recursive, recursive = recursive, wd.recursive - if err = wd.closeHandle(); err != nil { - wd.filter = oldevent - wd.recursive = recursive - return - } - return -} - -// TODO : pknap -func (r *readdcw) nonStateWatchedLocked(path string) (wd *watched, err error) { - wd, ok := r.m[path] - if !ok || wd == nil { - err = errors.New(`notify: ` + path + ` path is unwatched`) - return - } - if wd.filter&onlyMachineStates != 0 { - err = errors.New(`notify: another re/unwatching operation in progress`) - return - } - return -} - -// Unwatch implements notify.Watcher interface. -func (r *readdcw) Unwatch(path string) error { - return r.unwatch(path) -} - -// RecursiveUnwatch implements notify.RecursiveWatcher interface. -func (r *readdcw) RecursiveUnwatch(path string) error { - return r.unwatch(path) -} - -// TODO : pknap -func (r *readdcw) unwatch(path string) (err error) { - var wd *watched - - r.Lock() - defer r.Unlock() - if wd, err = r.nonStateWatchedLocked(path); err != nil { - return - } - - wd.filter |= stateUnwatch - dbgprint("unwatch: set unwatch state") - - if _, attrErr := syscall.GetFileAttributes(&wd.pathw[0]); attrErr != nil { - for _, g := range wd.digrip { - if g == nil { - continue - } - - dbgprint("unwatch: posting") - if err = syscall.PostQueuedCompletionStatus(r.cph, 0, 0, (*syscall.Overlapped)(unsafe.Pointer(g.ovlapped))); err != nil { - wd.filter &^= stateUnwatch - return - } - } - } - - return -} - -// Close resets the whole watcher object, closes all existing file descriptors, -// and sends stateCPClose state as completion key to the main watcher's loop. -func (r *readdcw) Close() (err error) { - r.Lock() - if !r.start { - r.Unlock() - return nil - } - for _, wd := range r.m { - wd.filter &^= onlyMachineStates - wd.filter |= stateCPClose - if e := wd.closeHandle(); e != nil && err == nil { - err = e - } - } - r.start = false - r.Unlock() - r.wg.Add(1) - if e := syscall.PostQueuedCompletionStatus(r.cph, 0, stateCPClose, nil); e != nil && err == nil { - return e - } - r.wg.Wait() - return -} - -// decode creates a notify event from both non-raw filter and action which was -// returned from completion routine. Function may return Event(0) in case when -// filter was replaced by a new value which does not contain fields that are -// valid with passed action. -func decode(filter, action uint32) (Event, Event) { - switch action { - case syscall.FILE_ACTION_ADDED: - return gensys(filter, Create, FileActionAdded) - case syscall.FILE_ACTION_REMOVED: - return gensys(filter, Remove, FileActionRemoved) - case syscall.FILE_ACTION_MODIFIED: - return gensys(filter, Write, FileActionModified) - case syscall.FILE_ACTION_RENAMED_OLD_NAME: - return gensys(filter, Rename, FileActionRenamedOldName) - case syscall.FILE_ACTION_RENAMED_NEW_NAME: - return gensys(filter, Rename, FileActionRenamedNewName) - } - dbgprintf("cannot decode internal mask: %d", action) - - return 0, 0 -} - -// gensys decides whether the Windows action, system-independent event or both -// of them should be returned. Since the grip's filter may be atomically changed -// during watcher lifetime, it is possible that neither Windows nor notify masks -// are watched by the user when this function is called. -func gensys(filter uint32, ge, se Event) (gene, syse Event) { - isdir := filter&uint32(dirmarker) != 0 - if isdir && filter&uint32(FileNotifyChangeDirName) != 0 || - !isdir && filter&uint32(FileNotifyChangeFileName) != 0 || - filter&uint32(fileNotifyChangeModified) != 0 { - syse = se - } - if filter&uint32(ge) != 0 { - gene = ge - } - return -} diff --git a/vendor/github.com/rjeczalik/notify/watcher_stub.go b/vendor/github.com/rjeczalik/notify/watcher_stub.go deleted file mode 100644 index 9b284ddc85..0000000000 --- a/vendor/github.com/rjeczalik/notify/watcher_stub.go +++ /dev/null @@ -1,13 +0,0 @@ -// Copyright (c) 2014-2018 The Notify Authors. All rights reserved. -// Use of this source code is governed by the MIT license that can be -// found in the LICENSE file. - -package notify - -type watcherStub struct{ error } - -// Following methods implement notify.watcher interface. -func (s watcherStub) Watch(string, Event) error { return s } -func (s watcherStub) Rewatch(string, Event, Event) error { return s } -func (s watcherStub) Unwatch(string) (err error) { return s } -func (s watcherStub) Close() error { return s } diff --git a/vendor/github.com/rjeczalik/notify/watcher_trigger.go b/vendor/github.com/rjeczalik/notify/watcher_trigger.go deleted file mode 100644 index 7cd0824e39..0000000000 --- a/vendor/github.com/rjeczalik/notify/watcher_trigger.go +++ /dev/null @@ -1,454 +0,0 @@ -// Copyright (c) 2014-2015 The Notify Authors. All rights reserved. -// Use of this source code is governed by the MIT license that can be -// found in the LICENSE file. - -//go:build (darwin && kqueue) || (darwin && !cgo) || dragonfly || freebsd || netbsd || openbsd || solaris || illumos -// +build darwin,kqueue darwin,!cgo dragonfly freebsd netbsd openbsd solaris illumos - -// watcher_trigger is used for FEN and kqueue which behave similarly: -// only files and dirs can be watched directly, but not files inside dirs. -// As a result Create events have to be generated by implementation when -// after Write event is returned for watched dir, it is rescanned and Create -// event is returned for new files and these are automatically added -// to watchlist. In case of removal of watched directory, native system returns -// events for all files, but for Rename, they also need to be generated. -// As a result native system works as something like trigger for rescan, -// but contains additional data about dir in which changes occurred. For files -// detailed data is returned. -// Usage of watcher_trigger requires: -// - trigger implementation, -// - encode func, -// - not2nat, nat2not maps. -// Required manual operations on filesystem can lead to loss of precision. - -package notify - -import ( - "fmt" - "os" - "path/filepath" - "strings" - "sync" - "syscall" -) - -// trigger is to be implemented by platform implementation like FEN or kqueue. -type trigger interface { - // Close closes watcher's main native file descriptor. - Close() error - // Stop waiting for new events. - Stop() error - // Create new instance of watched. - NewWatched(string, os.FileInfo) (*watched, error) - // Record internally new *watched instance. - Record(*watched) - // Del removes internal copy of *watched instance. - Del(*watched) - // Watched returns *watched instance and native events for native type. - Watched(interface{}) (*watched, int64, error) - // Init initializes native watcher call. - Init() error - // Watch starts watching provided file/dir. - Watch(os.FileInfo, *watched, int64) error - // Unwatch stops watching provided file/dir. - Unwatch(*watched) error - // Wait for new events. - Wait() (interface{}, error) - // IsStop checks if Wait finished because of request watcher's stop. - IsStop(n interface{}, err error) bool -} - -// trgWatched is a the base data structure representing watched file/directory. -// The platform specific full data structure (watched) must embed this type. -type trgWatched struct { - // p is a path to watched file/directory. - p string - // fi provides information about watched file/dir. - fi os.FileInfo - // eDir represents events watched directly. - eDir Event - // eNonDir represents events watched indirectly. - eNonDir Event -} - -// encode Event to native representation. Implementation is to be provided by -// platform specific implementation. -var encode func(Event, bool) int64 - -var ( - // nat2not matches native events to notify's ones. To be initialized by - // platform dependent implementation. - nat2not map[Event]Event - // not2nat matches notify's events to native ones. To be initialized by - // platform dependent implementation. - not2nat map[Event]Event -) - -// trg is a main structure implementing watcher. -type trg struct { - sync.Mutex - // s is a channel used to stop monitoring. - s chan struct{} - // c is a channel used to pass events further. - c chan<- EventInfo - // pthLkp is a data structure mapping file names with data about watching - // represented by them files/directories. - pthLkp map[string]*watched - // t is a platform dependent implementation of trigger. - t trigger -} - -// newWatcher returns new watcher's implementation. -func newWatcher(c chan<- EventInfo) watcher { - t := &trg{ - s: make(chan struct{}, 1), - pthLkp: make(map[string]*watched, 0), - c: c, - } - t.t = newTrigger(t.pthLkp) - if err := t.t.Init(); err != nil { - t.Close() - return watcherStub{fmt.Errorf("failed setting up watcher: %v", err)} - } - go t.monitor() - return t -} - -// Close implements watcher. -func (t *trg) Close() (err error) { - t.Lock() - if err = t.t.Stop(); err != nil { - t.Unlock() - return - } - <-t.s - var e error - for _, w := range t.pthLkp { - if e = t.unwatch(w.p, w.fi); e != nil { - dbgprintf("trg: unwatch %q failed: %q\n", w.p, e) - err = nonil(err, e) - } - } - if e = t.t.Close(); e != nil { - dbgprintf("trg: closing native watch failed: %q\n", e) - err = nonil(err, e) - } - if remaining := len(t.pthLkp); remaining != 0 { - err = nonil(err, fmt.Errorf("Not all watches were removed: len(t.pthLkp) == %v", len(t.pthLkp))) - } - t.Unlock() - return -} - -// send reported events one by one through chan. -func (t *trg) send(evn []event) { - for i := range evn { - t.c <- &evn[i] - } -} - -// singlewatch starts to watch given p file/directory. -func (t *trg) singlewatch(p string, e Event, direct mode, fi os.FileInfo) (err error) { - w, ok := t.pthLkp[p] - if !ok { - if w, err = t.t.NewWatched(p, fi); err != nil { - if err == errSkip { - err = nil - } - return - } - } - switch direct { - case dir: - w.eDir |= e - case ndir: - w.eNonDir |= e - case both: - w.eDir |= e - w.eNonDir |= e - } - if err = t.t.Watch(fi, w, encode(w.eDir|w.eNonDir, fi.IsDir())); err != nil { - return - } - if !ok { - t.t.Record(w) - return nil - } - return errAlreadyWatched -} - -// decode converts event received from native to notify.Event -// representation taking into account requested events (w). -func decode(o int64, w Event) (e Event) { - for f, n := range nat2not { - if o&int64(f) != 0 { - if w&f != 0 { - e |= f - } - if w&n != 0 { - e |= n - } - } - } - - return -} - -func (t *trg) watch(p string, e Event, fi os.FileInfo) error { - if err := t.singlewatch(p, e, dir, fi); err != nil { - if err != errAlreadyWatched { - return err - } - } - if fi.IsDir() { - err := t.walk(p, func(fi os.FileInfo) (err error) { - if err = t.singlewatch(filepath.Join(p, fi.Name()), e, ndir, - fi); err != nil { - if err != errAlreadyWatched { - return - } - } - return nil - }) - if err != nil { - return err - } - } - return nil -} - -// walk runs f func on each file/dir from p directory. -func (t *trg) walk(p string, fn func(os.FileInfo) error) error { - fp, err := os.Open(p) - if err != nil { - return err - } - ls, err := fp.Readdir(0) - fp.Close() - if err != nil { - return err - } - for i := range ls { - if err := fn(ls[i]); err != nil { - return err - } - } - return nil -} - -func (t *trg) unwatch(p string, fi os.FileInfo) error { - if fi.IsDir() { - err := t.walk(p, func(fi os.FileInfo) error { - err := t.singleunwatch(filepath.Join(p, fi.Name()), ndir) - if err != errNotWatched { - return err - } - return nil - }) - if err != nil { - return err - } - } - return t.singleunwatch(p, dir) -} - -// Watch implements Watcher interface. -func (t *trg) Watch(p string, e Event) error { - fi, err := os.Stat(p) - if err != nil { - return err - } - t.Lock() - err = t.watch(p, e, fi) - t.Unlock() - return err -} - -// Unwatch implements Watcher interface. -func (t *trg) Unwatch(p string) error { - fi, err := os.Stat(p) - if err != nil { - return err - } - t.Lock() - err = t.unwatch(p, fi) - t.Unlock() - return err -} - -// Rewatch implements Watcher interface. -// -// TODO(rjeczalik): This is a naive hack. Rewrite might help. -func (t *trg) Rewatch(p string, _, e Event) error { - fi, err := os.Stat(p) - if err != nil { - return err - } - t.Lock() - if err = t.unwatch(p, fi); err == nil { - // TODO(rjeczalik): If watch fails then we leave trigger in inconsistent - // state. Handle? Panic? Native version of rewatch? - err = t.watch(p, e, fi) - } - t.Unlock() - return nil -} - -func (*trg) file(w *watched, n interface{}, e Event) (evn []event) { - evn = append(evn, event{w.p, e, w.fi.IsDir(), n}) - return -} - -func (t *trg) dir(w *watched, n interface{}, e, ge Event) (evn []event) { - // If it's dir and delete we have to send it and continue, because - // other processing relies on opening (in this case not existing) dir. - // Events for contents of this dir are reported by native impl. - // However events for rename must be generated for all monitored files - // inside of moved directory, because native impl does not report it independently - // for each file descriptor being moved in result of move action on - // parent directory. - if (ge & (not2nat[Rename] | not2nat[Remove])) != 0 { - // Write is reported also for Remove on directory. Because of that - // we have to filter it out explicitly. - evn = append(evn, event{w.p, e & ^Write & ^not2nat[Write], true, n}) - if ge¬2nat[Rename] != 0 { - for p := range t.pthLkp { - if strings.HasPrefix(p, w.p+string(os.PathSeparator)) { - if err := t.singleunwatch(p, both); err != nil && err != errNotWatched && - !os.IsNotExist(err) { - dbgprintf("trg: failed stop watching moved file (%q): %q\n", - p, err) - } - if (w.eDir|w.eNonDir)&(not2nat[Rename]|Rename) != 0 { - evn = append(evn, event{ - p, (w.eDir | w.eNonDir) & e &^ Write &^ not2nat[Write], - w.fi.IsDir(), nil, - }) - } - } - } - } - t.t.Del(w) - return - } - if (ge & not2nat[Write]) != 0 { - switch err := t.walk(w.p, func(fi os.FileInfo) error { - p := filepath.Join(w.p, fi.Name()) - switch err := t.singlewatch(p, w.eDir, ndir, fi); { - case os.IsNotExist(err) && ((w.eDir & Remove) != 0): - evn = append(evn, event{p, Remove, fi.IsDir(), n}) - case err == errAlreadyWatched: - case err != nil: - dbgprintf("trg: watching %q failed: %q", p, err) - case (w.eDir & Create) != 0: - evn = append(evn, event{p, Create, fi.IsDir(), n}) - default: - } - return nil - }); { - case os.IsNotExist(err): - return - case err != nil: - dbgprintf("trg: dir processing failed: %q", err) - default: - } - } - return -} - -type mode uint - -const ( - dir mode = iota - ndir - both -) - -// unwatch stops watching p file/directory. -func (t *trg) singleunwatch(p string, direct mode) error { - w, ok := t.pthLkp[p] - if !ok { - return errNotWatched - } - switch direct { - case dir: - w.eDir = 0 - case ndir: - w.eNonDir = 0 - case both: - w.eDir, w.eNonDir = 0, 0 - } - if err := t.t.Unwatch(w); err != nil { - return err - } - if w.eNonDir|w.eDir != 0 { - mod := dir - if w.eNonDir != 0 { - mod = ndir - } - if err := t.singlewatch(p, w.eNonDir|w.eDir, mod, - w.fi); err != nil && err != errAlreadyWatched { - return err - } - } else { - t.t.Del(w) - } - return nil -} - -func (t *trg) monitor() { - var ( - n interface{} - err error - ) - for { - switch n, err = t.t.Wait(); { - case err == syscall.EINTR: - case t.t.IsStop(n, err): - t.s <- struct{}{} - return - case err != nil: - dbgprintf("trg: failed to read events: %q\n", err) - default: - t.send(t.process(n)) - } - } -} - -// process event returned by native call. -func (t *trg) process(n interface{}) (evn []event) { - t.Lock() - w, ge, err := t.t.Watched(n) - if err != nil { - t.Unlock() - dbgprintf("trg: %v event lookup failed: %q", Event(ge), err) - return - } - - e := decode(ge, w.eDir|w.eNonDir) - if ge&int64(not2nat[Remove]|not2nat[Rename]) == 0 { - switch fi, err := os.Stat(w.p); { - case err != nil: - default: - if err = t.t.Watch(fi, w, encode(w.eDir|w.eNonDir, fi.IsDir())); err != nil { - dbgprintf("trg: %q is no longer watched: %q", w.p, err) - t.t.Del(w) - } - } - } - if e == Event(0) && (!w.fi.IsDir() || (ge&int64(not2nat[Write])) == 0) { - t.Unlock() - return - } - - if w.fi.IsDir() { - evn = append(evn, t.dir(w, n, e, Event(ge))...) - } else { - evn = append(evn, t.file(w, n, e)...) - } - if Event(ge)&(not2nat[Remove]|not2nat[Rename]) != 0 { - t.t.Del(w) - } - t.Unlock() - return -} diff --git a/vendor/github.com/rjeczalik/notify/watchpoint.go b/vendor/github.com/rjeczalik/notify/watchpoint.go deleted file mode 100644 index 5afc914f49..0000000000 --- a/vendor/github.com/rjeczalik/notify/watchpoint.go +++ /dev/null @@ -1,103 +0,0 @@ -// Copyright (c) 2014-2015 The Notify Authors. All rights reserved. -// Use of this source code is governed by the MIT license that can be -// found in the LICENSE file. - -package notify - -// EventDiff describes a change to an event set - EventDiff[0] is an old state, -// while EventDiff[1] is a new state. If event set has not changed (old == new), -// functions typically return the None value. -type eventDiff [2]Event - -func (diff eventDiff) Event() Event { - return diff[1] &^ diff[0] -} - -// Watchpoint -// -// The nil key holds total event set - logical sum for all registered events. -// It speeds up computing EventDiff for Add method. -// -// The rec key holds an event set for a watchpoints created by RecursiveWatch -// for a Watcher implementation which is not natively recursive. -type watchpoint map[chan<- EventInfo]Event - -// None is an empty event diff, think null object. -var none eventDiff - -// rec is just a placeholder -var rec = func() (ch chan<- EventInfo) { - ch = make(chan<- EventInfo) - close(ch) - return -}() - -func (wp watchpoint) dryAdd(ch chan<- EventInfo, e Event) eventDiff { - if e &^= internal; wp[ch]&e == e { - return none - } - total := wp[ch] &^ internal - return eventDiff{total, total | e} -} - -// Add assumes neither c nor e are nil or zero values. -func (wp watchpoint) Add(c chan<- EventInfo, e Event) (diff eventDiff) { - wp[c] |= e - diff[0] = wp[nil] - diff[1] = diff[0] | e - wp[nil] = diff[1] &^ omit - // Strip diff from internal events. - diff[0] &^= internal - diff[1] &^= internal - if diff[0] == diff[1] { - return none - } - return -} - -func (wp watchpoint) Del(c chan<- EventInfo, e Event) (diff eventDiff) { - wp[c] &^= e - if wp[c] == 0 { - delete(wp, c) - } - diff[0] = wp[nil] - delete(wp, nil) - if len(wp) != 0 { - // Recalculate total event set. - for _, e := range wp { - diff[1] |= e - } - wp[nil] = diff[1] &^ omit - } - // Strip diff from internal events. - diff[0] &^= internal - diff[1] &^= internal - if diff[0] == diff[1] { - return none - } - return -} - -func (wp watchpoint) Dispatch(ei EventInfo, extra Event) { - e := eventmask(ei, extra) - if !matches(wp[nil], e) { - return - } - for ch, eset := range wp { - if ch != nil && matches(eset, e) { - select { - case ch <- ei: - default: // Drop event if receiver is too slow - dbgprintf("dropped %s on %q: receiver too slow", ei.Event(), ei.Path()) - } - } - } -} - -func (wp watchpoint) Total() Event { - return wp[nil] &^ internal -} - -func (wp watchpoint) IsRecursive() bool { - return wp[nil]&recursive != 0 -} diff --git a/vendor/github.com/rjeczalik/notify/watchpoint_other.go b/vendor/github.com/rjeczalik/notify/watchpoint_other.go deleted file mode 100644 index d4269994e1..0000000000 --- a/vendor/github.com/rjeczalik/notify/watchpoint_other.go +++ /dev/null @@ -1,24 +0,0 @@ -// Copyright (c) 2014-2015 The Notify Authors. All rights reserved. -// Use of this source code is governed by the MIT license that can be -// found in the LICENSE file. - -//go:build !windows -// +build !windows - -package notify - -// eventmask uses ei to create a new event which contains internal flags used by -// notify package logic. -func eventmask(ei EventInfo, extra Event) Event { - return ei.Event() | extra -} - -// matches reports a match only when: -// -// - for user events, when event is present in the given set -// - for internal events, when additionally both event and set have omit bit set -// -// Internal events must not be sent to user channels and vice versa. -func matches(set, event Event) bool { - return (set&omit)^(event&omit) == 0 && set&event == event -} diff --git a/vendor/github.com/rjeczalik/notify/watchpoint_readdcw.go b/vendor/github.com/rjeczalik/notify/watchpoint_readdcw.go deleted file mode 100644 index 49a9b9c87b..0000000000 --- a/vendor/github.com/rjeczalik/notify/watchpoint_readdcw.go +++ /dev/null @@ -1,39 +0,0 @@ -// Copyright (c) 2014-2015 The Notify Authors. All rights reserved. -// Use of this source code is governed by the MIT license that can be -// found in the LICENSE file. - -//go:build windows -// +build windows - -package notify - -// eventmask uses ei to create a new event which contains internal flags used by -// notify package logic. If one of FileAction* masks is detected, this function -// adds corresponding FileNotifyChange* values. This allows non registered -// FileAction* events to be passed on. -func eventmask(ei EventInfo, extra Event) (e Event) { - if e = ei.Event() | extra; e&fileActionAll != 0 { - if ev, ok := ei.(*event); ok { - switch ev.ftype { - case fTypeFile: - e |= FileNotifyChangeFileName - case fTypeDirectory: - e |= FileNotifyChangeDirName - case fTypeUnknown: - e |= fileNotifyChangeModified - } - return e &^ fileActionAll - } - } - return -} - -// matches reports a match only when: -// -// - for user events, when event is present in the given set -// - for internal events, when additionally both event and set have omit bit set -// -// Internal events must not be sent to user channels and vice versa. -func matches(set, event Event) bool { - return (set&omit)^(event&omit) == 0 && (set&event == event || set&fileNotifyChangeModified&event != 0) -} diff --git a/vendor/modules.txt b/vendor/modules.txt index db3f81a3d7..c91edc6320 100644 --- a/vendor/modules.txt +++ b/vendor/modules.txt @@ -500,6 +500,9 @@ github.com/fjl/memsize/memsizeui # github.com/fogleman/ease v0.0.0-20170301025033-8da417bf1776 ## explicit github.com/fogleman/ease +# github.com/fsnotify/fsnotify v1.6.0 +## explicit; go 1.16 +github.com/fsnotify/fsnotify # github.com/garslo/gogen v0.0.0-20170306192744-1d203ffc1f61 ## explicit github.com/garslo/gogen @@ -888,9 +891,6 @@ github.com/remyoudompheng/bigfft # github.com/rivo/uniseg v0.4.4 ## explicit; go 1.18 github.com/rivo/uniseg -# github.com/rjeczalik/notify v0.9.3 -## explicit; go 1.11 -github.com/rjeczalik/notify # github.com/rogpeppe/go-internal v1.11.0 ## explicit; go 1.19 github.com/rogpeppe/go-internal/fmtsort