mirror of
				https://github.com/superseriousbusiness/gotosocial.git
				synced 2025-11-04 08:22:25 -06:00 
			
		
		
		
	[chore]: Bump github.com/tdewolff/minify/v2 from 2.21.2 to 2.21.3 (#3727)
Bumps [github.com/tdewolff/minify/v2](https://github.com/tdewolff/minify) from 2.21.2 to 2.21.3. - [Release notes](https://github.com/tdewolff/minify/releases) - [Commits](https://github.com/tdewolff/minify/compare/v2.21.2...v2.21.3) --- updated-dependencies: - dependency-name: github.com/tdewolff/minify/v2 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
This commit is contained in:
		
					parent
					
						
							
								c086d4048c
							
						
					
				
			
			
				commit
				
					
						8b74cad422
					
				
			
		
					 36 changed files with 1891 additions and 1625 deletions
				
			
		
							
								
								
									
										7
									
								
								vendor/github.com/fsnotify/fsnotify/.cirrus.yml
									
										
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										7
									
								
								vendor/github.com/fsnotify/fsnotify/.cirrus.yml
									
										
									
										generated
									
									
										vendored
									
									
								
							| 
						 | 
				
			
			@ -1,7 +1,7 @@
 | 
			
		|||
freebsd_task:
 | 
			
		||||
  name: 'FreeBSD'
 | 
			
		||||
  freebsd_instance:
 | 
			
		||||
    image_family: freebsd-13-2
 | 
			
		||||
    image_family: freebsd-14-1
 | 
			
		||||
  install_script:
 | 
			
		||||
    - pkg update -f
 | 
			
		||||
    - pkg install -y go
 | 
			
		||||
| 
						 | 
				
			
			@ -9,5 +9,6 @@ freebsd_task:
 | 
			
		|||
      # run tests as user "cirrus" instead of root
 | 
			
		||||
    - pw useradd cirrus -m
 | 
			
		||||
    - chown -R cirrus:cirrus .
 | 
			
		||||
    - FSNOTIFY_BUFFER=4096 sudo --preserve-env=FSNOTIFY_BUFFER -u cirrus go test -parallel 1 -race ./...
 | 
			
		||||
    -                      sudo --preserve-env=FSNOTIFY_BUFFER -u cirrus go test -parallel 1 -race ./...
 | 
			
		||||
    - FSNOTIFY_BUFFER=4096 sudo --preserve-env=FSNOTIFY_BUFFER -u cirrus go test -parallel 1 -race    ./...
 | 
			
		||||
    -                      sudo --preserve-env=FSNOTIFY_BUFFER -u cirrus go test -parallel 1 -race    ./...
 | 
			
		||||
    - FSNOTIFY_DEBUG=1     sudo --preserve-env=FSNOTIFY_BUFFER -u cirrus go test -parallel 1 -race -v ./...
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										12
									
								
								vendor/github.com/fsnotify/fsnotify/.editorconfig
									
										
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										12
									
								
								vendor/github.com/fsnotify/fsnotify/.editorconfig
									
										
									
										generated
									
									
										vendored
									
									
								
							| 
						 | 
				
			
			@ -1,12 +0,0 @@
 | 
			
		|||
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
 | 
			
		||||
							
								
								
									
										1
									
								
								vendor/github.com/fsnotify/fsnotify/.gitattributes
									
										
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										1
									
								
								vendor/github.com/fsnotify/fsnotify/.gitattributes
									
										
									
										generated
									
									
										vendored
									
									
								
							| 
						 | 
				
			
			@ -1 +0,0 @@
 | 
			
		|||
go.sum linguist-generated
 | 
			
		||||
							
								
								
									
										3
									
								
								vendor/github.com/fsnotify/fsnotify/.gitignore
									
										
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										3
									
								
								vendor/github.com/fsnotify/fsnotify/.gitignore
									
										
									
										generated
									
									
										vendored
									
									
								
							| 
						 | 
				
			
			@ -5,3 +5,6 @@
 | 
			
		|||
# Output of go build ./cmd/fsnotify
 | 
			
		||||
/fsnotify
 | 
			
		||||
/fsnotify.exe
 | 
			
		||||
 | 
			
		||||
/test/kqueue
 | 
			
		||||
/test/a.out
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										34
									
								
								vendor/github.com/fsnotify/fsnotify/CHANGELOG.md
									
										
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										34
									
								
								vendor/github.com/fsnotify/fsnotify/CHANGELOG.md
									
										
									
										generated
									
									
										vendored
									
									
								
							| 
						 | 
				
			
			@ -1,8 +1,36 @@
 | 
			
		|||
# Changelog
 | 
			
		||||
 | 
			
		||||
Unreleased
 | 
			
		||||
----------
 | 
			
		||||
Nothing yet.
 | 
			
		||||
1.8.0 2023-10-31
 | 
			
		||||
----------------
 | 
			
		||||
 | 
			
		||||
### Additions
 | 
			
		||||
 | 
			
		||||
- all: add `FSNOTIFY_DEBUG` to print debug logs to stderr ([#619])
 | 
			
		||||
 | 
			
		||||
### Changes and fixes
 | 
			
		||||
 | 
			
		||||
- windows: fix behaviour of `WatchList()` to be consistent with other platforms ([#610])
 | 
			
		||||
 | 
			
		||||
- kqueue: ignore events with Ident=0 ([#590])
 | 
			
		||||
 | 
			
		||||
- kqueue: set O_CLOEXEC to prevent passing file descriptors to children ([#617])
 | 
			
		||||
 | 
			
		||||
- kqueue: emit events as "/path/dir/file" instead of "path/link/file" when watching a symlink ([#625])
 | 
			
		||||
 | 
			
		||||
- inotify: don't send event for IN_DELETE_SELF when also watching the parent ([#620])
 | 
			
		||||
 | 
			
		||||
- inotify: fix panic when calling Remove() in a goroutine ([#650])
 | 
			
		||||
 | 
			
		||||
- fen: allow watching subdirectories of watched directories ([#621])
 | 
			
		||||
 | 
			
		||||
[#590]: https://github.com/fsnotify/fsnotify/pull/590
 | 
			
		||||
[#610]: https://github.com/fsnotify/fsnotify/pull/610
 | 
			
		||||
[#617]: https://github.com/fsnotify/fsnotify/pull/617
 | 
			
		||||
[#619]: https://github.com/fsnotify/fsnotify/pull/619
 | 
			
		||||
[#620]: https://github.com/fsnotify/fsnotify/pull/620
 | 
			
		||||
[#621]: https://github.com/fsnotify/fsnotify/pull/621
 | 
			
		||||
[#625]: https://github.com/fsnotify/fsnotify/pull/625
 | 
			
		||||
[#650]: https://github.com/fsnotify/fsnotify/pull/650
 | 
			
		||||
 | 
			
		||||
1.7.0 - 2023-10-22
 | 
			
		||||
------------------
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										120
									
								
								vendor/github.com/fsnotify/fsnotify/CONTRIBUTING.md
									
										
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										120
									
								
								vendor/github.com/fsnotify/fsnotify/CONTRIBUTING.md
									
										
									
										generated
									
									
										vendored
									
									
								
							| 
						 | 
				
			
			@ -1,7 +1,7 @@
 | 
			
		|||
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
 | 
			
		||||
- To avoid "wasted" work, please discuss changes on the issue tracker first. You
 | 
			
		||||
  can just send PRs, but they may end up being rejected for one reason or the
 | 
			
		||||
  other.
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -20,6 +20,124 @@ platforms. Testing different platforms locally can be done with something like
 | 
			
		|||
 | 
			
		||||
Use the `-short` flag to make the "stress test" run faster.
 | 
			
		||||
 | 
			
		||||
Writing new tests
 | 
			
		||||
-----------------
 | 
			
		||||
Scripts in the testdata directory allow creating test cases in a "shell-like"
 | 
			
		||||
syntax. The basic format is:
 | 
			
		||||
 | 
			
		||||
    script
 | 
			
		||||
 | 
			
		||||
    Output:
 | 
			
		||||
    desired output
 | 
			
		||||
 | 
			
		||||
For example:
 | 
			
		||||
 | 
			
		||||
    # Create a new empty file with some data.
 | 
			
		||||
    watch /
 | 
			
		||||
    echo data >/file
 | 
			
		||||
 | 
			
		||||
    Output:
 | 
			
		||||
        create  /file
 | 
			
		||||
        write   /file
 | 
			
		||||
 | 
			
		||||
Just create a new file to add a new test; select which tests to run with
 | 
			
		||||
`-run TestScript/[path]`.
 | 
			
		||||
 | 
			
		||||
script
 | 
			
		||||
------
 | 
			
		||||
The script is a "shell-like" script:
 | 
			
		||||
 | 
			
		||||
    cmd arg arg
 | 
			
		||||
 | 
			
		||||
Comments are supported with `#`:
 | 
			
		||||
 | 
			
		||||
    # Comment
 | 
			
		||||
    cmd arg arg  # Comment
 | 
			
		||||
 | 
			
		||||
All operations are done in a temp directory; a path like "/foo" is rewritten to
 | 
			
		||||
"/tmp/TestFoo/foo".
 | 
			
		||||
 | 
			
		||||
Arguments can be quoted with `"` or `'`; there are no escapes and they're
 | 
			
		||||
functionally identical right now, but this may change in the future, so best to
 | 
			
		||||
assume shell-like rules.
 | 
			
		||||
 | 
			
		||||
    touch "/file with spaces"
 | 
			
		||||
 | 
			
		||||
End-of-line escapes with `\` are not supported.
 | 
			
		||||
 | 
			
		||||
### Supported commands
 | 
			
		||||
 | 
			
		||||
    watch path [ops]    # Watch the path, reporting events for it. Nothing is
 | 
			
		||||
                        # watched by default. Optionally a list of ops can be
 | 
			
		||||
                        # given, as with AddWith(path, WithOps(...)).
 | 
			
		||||
    unwatch path        # Stop watching the path.
 | 
			
		||||
    watchlist n         # Assert watchlist length.
 | 
			
		||||
 | 
			
		||||
    stop                # Stop running the script; for debugging.
 | 
			
		||||
    debug [yes/no]      # Enable/disable FSNOTIFY_DEBUG (tests are run in
 | 
			
		||||
                          parallel by default, so -parallel=1 is probably a good
 | 
			
		||||
                          idea).
 | 
			
		||||
 | 
			
		||||
    touch path
 | 
			
		||||
    mkdir [-p] dir
 | 
			
		||||
    ln -s target link   # Only ln -s supported.
 | 
			
		||||
    mkfifo path
 | 
			
		||||
    mknod dev path
 | 
			
		||||
    mv src dst
 | 
			
		||||
    rm [-r] path
 | 
			
		||||
    chmod mode path     # Octal only
 | 
			
		||||
    sleep time-in-ms
 | 
			
		||||
 | 
			
		||||
    cat path            # Read path (does nothing with the data; just reads it).
 | 
			
		||||
    echo str >>path     # Append "str" to "path".
 | 
			
		||||
    echo str >path      # Truncate "path" and write "str".
 | 
			
		||||
 | 
			
		||||
    require reason      # Skip the test if "reason" is true; "skip" and
 | 
			
		||||
    skip reason         # "require" behave identical; it supports both for
 | 
			
		||||
                        # readability. Possible reasons are:
 | 
			
		||||
                        #
 | 
			
		||||
                        #   always    Always skip this test.
 | 
			
		||||
                        #   symlink   Symlinks are supported (requires admin
 | 
			
		||||
                        #             permissions on Windows).
 | 
			
		||||
                        #   mkfifo    Platform doesn't support FIFO named sockets.
 | 
			
		||||
                        #   mknod     Platform doesn't support device nodes.
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
output
 | 
			
		||||
------
 | 
			
		||||
After `Output:` the desired output is given; this is indented by convention, but
 | 
			
		||||
that's not required.
 | 
			
		||||
 | 
			
		||||
The format of that is:
 | 
			
		||||
 | 
			
		||||
    # Comment
 | 
			
		||||
    event  path  # Comment
 | 
			
		||||
 | 
			
		||||
    system:
 | 
			
		||||
        event  path
 | 
			
		||||
    system2:
 | 
			
		||||
        event  path
 | 
			
		||||
 | 
			
		||||
Every event is one line, and any whitespace between the event and path are
 | 
			
		||||
ignored. The path can optionally be surrounded in ". Anything after a "#" is
 | 
			
		||||
ignored.
 | 
			
		||||
 | 
			
		||||
Platform-specific tests can be added after GOOS; for example:
 | 
			
		||||
 | 
			
		||||
    watch /
 | 
			
		||||
    touch /file
 | 
			
		||||
 | 
			
		||||
    Output:
 | 
			
		||||
        # Tested if nothing else matches
 | 
			
		||||
        create    /file
 | 
			
		||||
 | 
			
		||||
        # Windows-specific test.
 | 
			
		||||
        windows:
 | 
			
		||||
            write  /file
 | 
			
		||||
 | 
			
		||||
You can specify multiple platforms with a comma (e.g. "windows, linux:").
 | 
			
		||||
"kqueue" is a shortcut for all kqueue systems (BSD, macOS).
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
[goon]: https://github.com/arp242/goon
 | 
			
		||||
[Vagrant]: https://www.vagrantup.com/
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										324
									
								
								vendor/github.com/fsnotify/fsnotify/backend_fen.go
									
										
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										324
									
								
								vendor/github.com/fsnotify/fsnotify/backend_fen.go
									
										
									
										generated
									
									
										vendored
									
									
								
							| 
						 | 
				
			
			@ -1,8 +1,8 @@
 | 
			
		|||
//go:build solaris
 | 
			
		||||
// +build solaris
 | 
			
		||||
 | 
			
		||||
// Note: the documentation on the Watcher type and methods is generated from
 | 
			
		||||
// mkdoc.zsh
 | 
			
		||||
// FEN backend for illumos (supported) and Solaris (untested, but should work).
 | 
			
		||||
//
 | 
			
		||||
// See port_create(3c) etc. for docs. https://www.illumos.org/man/3C/port_create
 | 
			
		||||
 | 
			
		||||
package fsnotify
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -12,150 +12,33 @@ import (
 | 
			
		|||
	"os"
 | 
			
		||||
	"path/filepath"
 | 
			
		||||
	"sync"
 | 
			
		||||
	"time"
 | 
			
		||||
 | 
			
		||||
	"github.com/fsnotify/fsnotify/internal"
 | 
			
		||||
	"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.
 | 
			
		||||
//
 | 
			
		||||
// # Windows notes
 | 
			
		||||
//
 | 
			
		||||
// Paths can be added as "C:\path\to\dir", but forward slashes
 | 
			
		||||
// ("C:/path/to/dir") will also work.
 | 
			
		||||
//
 | 
			
		||||
// When a watched directory is removed it will always send an event for the
 | 
			
		||||
// directory itself, but may not send events for all files in that directory.
 | 
			
		||||
// Sometimes it will send events for all times, sometimes it will send no
 | 
			
		||||
// events, and often only for some files.
 | 
			
		||||
//
 | 
			
		||||
// The default ReadDirectoryChangesW() buffer size is 64K, which is the largest
 | 
			
		||||
// value that is guaranteed to work with SMB filesystems. If you have many
 | 
			
		||||
// events in quick succession this may not be enough, and you will have to use
 | 
			
		||||
// [WithBufferSize] to increase the value.
 | 
			
		||||
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, and you may
 | 
			
		||||
	//                      want to wait until you've stopped receiving them
 | 
			
		||||
	//                      (see the dedup example in cmd/fsnotify).
 | 
			
		||||
	//
 | 
			
		||||
	//                      Some systems may send Write event for directories
 | 
			
		||||
	//                      when the directory content changes.
 | 
			
		||||
	//
 | 
			
		||||
	//   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
 | 
			
		||||
	//                      when a file is truncated. On Windows it's never
 | 
			
		||||
	//                      sent.
 | 
			
		||||
type fen struct {
 | 
			
		||||
	Events chan Event
 | 
			
		||||
 | 
			
		||||
	// Errors sends any errors.
 | 
			
		||||
	//
 | 
			
		||||
	// ErrEventOverflow is used to indicate there are too many events:
 | 
			
		||||
	//
 | 
			
		||||
	//  - inotify:      There are too many queued events (fs.inotify.max_queued_events sysctl)
 | 
			
		||||
	//  - windows:      The buffer size is too small; WithBufferSize() can be used to increase it.
 | 
			
		||||
	//  - kqueue, fen:  Not used.
 | 
			
		||||
	Errors chan error
 | 
			
		||||
 | 
			
		||||
	mu      sync.Mutex
 | 
			
		||||
	port    *unix.EventPort
 | 
			
		||||
	done    chan struct{}       // Channel for sending a "quit message" to the reader goroutine
 | 
			
		||||
	dirs    map[string]struct{} // Explicitly watched directories
 | 
			
		||||
	watches map[string]struct{} // Explicitly watched non-directories
 | 
			
		||||
	done    chan struct{} // Channel for sending a "quit message" to the reader goroutine
 | 
			
		||||
	dirs    map[string]Op // Explicitly watched directories
 | 
			
		||||
	watches map[string]Op // Explicitly watched non-directories
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// NewWatcher creates a new Watcher.
 | 
			
		||||
func NewWatcher() (*Watcher, error) {
 | 
			
		||||
	return NewBufferedWatcher(0)
 | 
			
		||||
func newBackend(ev chan Event, errs chan error) (backend, error) {
 | 
			
		||||
	return newBufferedBackend(0, ev, errs)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// NewBufferedWatcher creates a new Watcher with a buffered Watcher.Events
 | 
			
		||||
// channel.
 | 
			
		||||
//
 | 
			
		||||
// The main use case for this is situations with a very large number of events
 | 
			
		||||
// where the kernel buffer size can't be increased (e.g. due to lack of
 | 
			
		||||
// permissions). An unbuffered Watcher will perform better for almost all use
 | 
			
		||||
// cases, and whenever possible you will be better off increasing the kernel
 | 
			
		||||
// buffers instead of adding a large userspace buffer.
 | 
			
		||||
func NewBufferedWatcher(sz uint) (*Watcher, error) {
 | 
			
		||||
	w := &Watcher{
 | 
			
		||||
		Events:  make(chan Event, sz),
 | 
			
		||||
		Errors:  make(chan error),
 | 
			
		||||
		dirs:    make(map[string]struct{}),
 | 
			
		||||
		watches: make(map[string]struct{}),
 | 
			
		||||
func newBufferedBackend(sz uint, ev chan Event, errs chan error) (backend, error) {
 | 
			
		||||
	w := &fen{
 | 
			
		||||
		Events:  ev,
 | 
			
		||||
		Errors:  errs,
 | 
			
		||||
		dirs:    make(map[string]Op),
 | 
			
		||||
		watches: make(map[string]Op),
 | 
			
		||||
		done:    make(chan struct{}),
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -171,27 +54,30 @@ func NewBufferedWatcher(sz uint) (*Watcher, error) {
 | 
			
		|||
 | 
			
		||||
// sendEvent attempts to send an event to the user, returning true if the event
 | 
			
		||||
// was put in the channel successfully and false if the watcher has been closed.
 | 
			
		||||
func (w *Watcher) sendEvent(name string, op Op) (sent bool) {
 | 
			
		||||
func (w *fen) sendEvent(name string, op Op) (sent bool) {
 | 
			
		||||
	select {
 | 
			
		||||
	case w.Events <- Event{Name: name, Op: op}:
 | 
			
		||||
		return true
 | 
			
		||||
	case <-w.done:
 | 
			
		||||
		return false
 | 
			
		||||
	case w.Events <- Event{Name: name, Op: op}:
 | 
			
		||||
		return true
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// sendError attempts to send an error to the user, returning true if the error
 | 
			
		||||
// was put in the channel successfully and false if the watcher has been closed.
 | 
			
		||||
func (w *Watcher) sendError(err error) (sent bool) {
 | 
			
		||||
	select {
 | 
			
		||||
	case w.Errors <- err:
 | 
			
		||||
func (w *fen) sendError(err error) (sent bool) {
 | 
			
		||||
	if err == nil {
 | 
			
		||||
		return true
 | 
			
		||||
	}
 | 
			
		||||
	select {
 | 
			
		||||
	case <-w.done:
 | 
			
		||||
		return false
 | 
			
		||||
	case w.Errors <- err:
 | 
			
		||||
		return true
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (w *Watcher) isClosed() bool {
 | 
			
		||||
func (w *fen) isClosed() bool {
 | 
			
		||||
	select {
 | 
			
		||||
	case <-w.done:
 | 
			
		||||
		return true
 | 
			
		||||
| 
						 | 
				
			
			@ -200,8 +86,7 @@ func (w *Watcher) isClosed() bool {
 | 
			
		|||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Close removes all watches and closes the Events channel.
 | 
			
		||||
func (w *Watcher) Close() error {
 | 
			
		||||
func (w *fen) Close() error {
 | 
			
		||||
	// Take the lock used by associateFile to prevent lingering events from
 | 
			
		||||
	// being processed after the close
 | 
			
		||||
	w.mu.Lock()
 | 
			
		||||
| 
						 | 
				
			
			@ -213,60 +98,21 @@ func (w *Watcher) Close() error {
 | 
			
		|||
	return w.port.Close()
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Add starts monitoring the path for changes.
 | 
			
		||||
//
 | 
			
		||||
// A path can only be watched once; watching it more than once is a no-op and will
 | 
			
		||||
// not return an error. Paths that do not yet exist on the filesystem cannot be
 | 
			
		||||
// watched.
 | 
			
		||||
//
 | 
			
		||||
// A watch will be automatically removed if the watched path is deleted or
 | 
			
		||||
// renamed. The exception is the Windows backend, which doesn't remove the
 | 
			
		||||
// watcher on renames.
 | 
			
		||||
//
 | 
			
		||||
// Notifications on network filesystems (NFS, SMB, FUSE, etc.) or special
 | 
			
		||||
// filesystems (/proc, /sys, etc.) generally don't work.
 | 
			
		||||
//
 | 
			
		||||
// Returns [ErrClosed] if [Watcher.Close] was called.
 | 
			
		||||
//
 | 
			
		||||
// See [Watcher.AddWith] for a version that allows adding options.
 | 
			
		||||
//
 | 
			
		||||
// # 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 programs (especially editors) update files atomically: it
 | 
			
		||||
// will write to a temporary file which is then moved to to destination,
 | 
			
		||||
// overwriting the original (or some variant thereof). The watcher on the
 | 
			
		||||
// original file is now lost, as that no longer exists.
 | 
			
		||||
//
 | 
			
		||||
// The upshot of this is that a power failure or crash won't leave a
 | 
			
		||||
// half-written file.
 | 
			
		||||
//
 | 
			
		||||
// 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 w.AddWith(name) }
 | 
			
		||||
func (w *fen) Add(name string) error { return w.AddWith(name) }
 | 
			
		||||
 | 
			
		||||
// AddWith is like [Watcher.Add], but allows adding options. When using Add()
 | 
			
		||||
// the defaults described below are used.
 | 
			
		||||
//
 | 
			
		||||
// Possible options are:
 | 
			
		||||
//
 | 
			
		||||
//   - [WithBufferSize] sets the buffer size for the Windows backend; no-op on
 | 
			
		||||
//     other platforms. The default is 64K (65536 bytes).
 | 
			
		||||
func (w *Watcher) AddWith(name string, opts ...addOpt) error {
 | 
			
		||||
func (w *fen) AddWith(name string, opts ...addOpt) error {
 | 
			
		||||
	if w.isClosed() {
 | 
			
		||||
		return ErrClosed
 | 
			
		||||
	}
 | 
			
		||||
	if w.port.PathIsWatched(name) {
 | 
			
		||||
		return nil
 | 
			
		||||
	if debug {
 | 
			
		||||
		fmt.Fprintf(os.Stderr, "FSNOTIFY_DEBUG: %s  AddWith(%q)\n",
 | 
			
		||||
			time.Now().Format("15:04:05.000000000"), name)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	_ = getOptions(opts...)
 | 
			
		||||
	with := getOptions(opts...)
 | 
			
		||||
	if !w.xSupports(with.op) {
 | 
			
		||||
		return fmt.Errorf("%w: %s", xErrUnsupported, with.op)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// Currently we resolve symlinks that were explicitly requested to be
 | 
			
		||||
	// watched. Otherwise we would use LStat here.
 | 
			
		||||
| 
						 | 
				
			
			@ -283,7 +129,7 @@ func (w *Watcher) AddWith(name string, opts ...addOpt) error {
 | 
			
		|||
		}
 | 
			
		||||
 | 
			
		||||
		w.mu.Lock()
 | 
			
		||||
		w.dirs[name] = struct{}{}
 | 
			
		||||
		w.dirs[name] = with.op
 | 
			
		||||
		w.mu.Unlock()
 | 
			
		||||
		return nil
 | 
			
		||||
	}
 | 
			
		||||
| 
						 | 
				
			
			@ -294,26 +140,22 @@ func (w *Watcher) AddWith(name string, opts ...addOpt) error {
 | 
			
		|||
	}
 | 
			
		||||
 | 
			
		||||
	w.mu.Lock()
 | 
			
		||||
	w.watches[name] = struct{}{}
 | 
			
		||||
	w.watches[name] = with.op
 | 
			
		||||
	w.mu.Unlock()
 | 
			
		||||
	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].
 | 
			
		||||
//
 | 
			
		||||
// Returns nil if [Watcher.Close] was called.
 | 
			
		||||
func (w *Watcher) Remove(name string) error {
 | 
			
		||||
func (w *fen) Remove(name string) error {
 | 
			
		||||
	if w.isClosed() {
 | 
			
		||||
		return nil
 | 
			
		||||
	}
 | 
			
		||||
	if !w.port.PathIsWatched(name) {
 | 
			
		||||
		return fmt.Errorf("%w: %s", ErrNonExistentWatch, name)
 | 
			
		||||
	}
 | 
			
		||||
	if debug {
 | 
			
		||||
		fmt.Fprintf(os.Stderr, "FSNOTIFY_DEBUG: %s  Remove(%q)\n",
 | 
			
		||||
			time.Now().Format("15:04:05.000000000"), name)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// The user has expressed an intent. Immediately remove this name from
 | 
			
		||||
	// whichever watch list it might be in. If it's not in there the delete
 | 
			
		||||
| 
						 | 
				
			
			@ -346,7 +188,7 @@ func (w *Watcher) Remove(name string) error {
 | 
			
		|||
}
 | 
			
		||||
 | 
			
		||||
// readEvents contains the main loop that runs in a goroutine watching for events.
 | 
			
		||||
func (w *Watcher) readEvents() {
 | 
			
		||||
func (w *fen) readEvents() {
 | 
			
		||||
	// If this function returns, the watcher has been closed and we can close
 | 
			
		||||
	// these channels
 | 
			
		||||
	defer func() {
 | 
			
		||||
| 
						 | 
				
			
			@ -382,17 +224,19 @@ func (w *Watcher) readEvents() {
 | 
			
		|||
				continue
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			if debug {
 | 
			
		||||
				internal.Debug(pevent.Path, pevent.Events)
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			err = w.handleEvent(&pevent)
 | 
			
		||||
			if err != nil {
 | 
			
		||||
				if !w.sendError(err) {
 | 
			
		||||
					return
 | 
			
		||||
				}
 | 
			
		||||
			if !w.sendError(err) {
 | 
			
		||||
				return
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (w *Watcher) handleDirectory(path string, stat os.FileInfo, follow bool, handler func(string, os.FileInfo, bool) error) error {
 | 
			
		||||
func (w *fen) handleDirectory(path string, stat os.FileInfo, follow bool, handler func(string, os.FileInfo, bool) error) error {
 | 
			
		||||
	files, err := os.ReadDir(path)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return err
 | 
			
		||||
| 
						 | 
				
			
			@ -418,7 +262,7 @@ func (w *Watcher) handleDirectory(path string, stat os.FileInfo, follow bool, ha
 | 
			
		|||
// bitmap matches more than one event type (e.g. the file was both modified and
 | 
			
		||||
// had the attributes changed between when the association was created and the
 | 
			
		||||
// when event was returned)
 | 
			
		||||
func (w *Watcher) handleEvent(event *unix.PortEvent) error {
 | 
			
		||||
func (w *fen) handleEvent(event *unix.PortEvent) error {
 | 
			
		||||
	var (
 | 
			
		||||
		events     = event.Events
 | 
			
		||||
		path       = event.Path
 | 
			
		||||
| 
						 | 
				
			
			@ -510,15 +354,9 @@ func (w *Watcher) handleEvent(event *unix.PortEvent) error {
 | 
			
		|||
	}
 | 
			
		||||
 | 
			
		||||
	if events&unix.FILE_MODIFIED != 0 {
 | 
			
		||||
		if fmode.IsDir() {
 | 
			
		||||
			if watchedDir {
 | 
			
		||||
				if err := w.updateDirectory(path); err != nil {
 | 
			
		||||
					return err
 | 
			
		||||
				}
 | 
			
		||||
			} else {
 | 
			
		||||
				if !w.sendEvent(path, Write) {
 | 
			
		||||
					return nil
 | 
			
		||||
				}
 | 
			
		||||
		if fmode.IsDir() && watchedDir {
 | 
			
		||||
			if err := w.updateDirectory(path); err != nil {
 | 
			
		||||
				return err
 | 
			
		||||
			}
 | 
			
		||||
		} else {
 | 
			
		||||
			if !w.sendEvent(path, Write) {
 | 
			
		||||
| 
						 | 
				
			
			@ -543,7 +381,7 @@ func (w *Watcher) handleEvent(event *unix.PortEvent) error {
 | 
			
		|||
	return nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (w *Watcher) updateDirectory(path string) error {
 | 
			
		||||
func (w *fen) updateDirectory(path string) error {
 | 
			
		||||
	// The directory was modified, so we must find unwatched entities and watch
 | 
			
		||||
	// them. If something was removed from the directory, nothing will happen,
 | 
			
		||||
	// as everything else should still be watched.
 | 
			
		||||
| 
						 | 
				
			
			@ -563,10 +401,8 @@ func (w *Watcher) updateDirectory(path string) error {
 | 
			
		|||
			return err
 | 
			
		||||
		}
 | 
			
		||||
		err = w.associateFile(path, finfo, false)
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			if !w.sendError(err) {
 | 
			
		||||
				return nil
 | 
			
		||||
			}
 | 
			
		||||
		if !w.sendError(err) {
 | 
			
		||||
			return nil
 | 
			
		||||
		}
 | 
			
		||||
		if !w.sendEvent(path, Create) {
 | 
			
		||||
			return nil
 | 
			
		||||
| 
						 | 
				
			
			@ -575,7 +411,7 @@ func (w *Watcher) updateDirectory(path string) error {
 | 
			
		|||
	return nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (w *Watcher) associateFile(path string, stat os.FileInfo, follow bool) error {
 | 
			
		||||
func (w *fen) associateFile(path string, stat os.FileInfo, follow bool) error {
 | 
			
		||||
	if w.isClosed() {
 | 
			
		||||
		return ErrClosed
 | 
			
		||||
	}
 | 
			
		||||
| 
						 | 
				
			
			@ -593,34 +429,34 @@ func (w *Watcher) associateFile(path string, stat os.FileInfo, follow bool) erro
 | 
			
		|||
		// cleared up that discrepancy. The most likely cause is that the event
 | 
			
		||||
		// has fired but we haven't processed it yet.
 | 
			
		||||
		err := w.port.DissociatePath(path)
 | 
			
		||||
		if err != nil && err != unix.ENOENT {
 | 
			
		||||
		if err != nil && !errors.Is(err, unix.ENOENT) {
 | 
			
		||||
			return err
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	// FILE_NOFOLLOW means we watch symlinks themselves rather than their
 | 
			
		||||
	// targets.
 | 
			
		||||
	events := unix.FILE_MODIFIED | unix.FILE_ATTRIB | unix.FILE_NOFOLLOW
 | 
			
		||||
	if follow {
 | 
			
		||||
		// We *DO* follow symlinks for explicitly watched entries.
 | 
			
		||||
		events = unix.FILE_MODIFIED | unix.FILE_ATTRIB
 | 
			
		||||
 | 
			
		||||
	var events int
 | 
			
		||||
	if !follow {
 | 
			
		||||
		// Watch symlinks themselves rather than their targets unless this entry
 | 
			
		||||
		// is explicitly watched.
 | 
			
		||||
		events |= unix.FILE_NOFOLLOW
 | 
			
		||||
	}
 | 
			
		||||
	return w.port.AssociatePath(path, stat,
 | 
			
		||||
		events,
 | 
			
		||||
		stat.Mode())
 | 
			
		||||
	if true { // TODO: implement withOps()
 | 
			
		||||
		events |= unix.FILE_MODIFIED
 | 
			
		||||
	}
 | 
			
		||||
	if true {
 | 
			
		||||
		events |= unix.FILE_ATTRIB
 | 
			
		||||
	}
 | 
			
		||||
	return w.port.AssociatePath(path, stat, events, stat.Mode())
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (w *Watcher) dissociateFile(path string, stat os.FileInfo, unused bool) error {
 | 
			
		||||
func (w *fen) dissociateFile(path string, stat os.FileInfo, unused bool) error {
 | 
			
		||||
	if !w.port.PathIsWatched(path) {
 | 
			
		||||
		return nil
 | 
			
		||||
	}
 | 
			
		||||
	return w.port.DissociatePath(path)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// WatchList returns all paths explicitly added with [Watcher.Add] (and are not
 | 
			
		||||
// yet removed).
 | 
			
		||||
//
 | 
			
		||||
// Returns nil if [Watcher.Close] was called.
 | 
			
		||||
func (w *Watcher) WatchList() []string {
 | 
			
		||||
func (w *fen) WatchList() []string {
 | 
			
		||||
	if w.isClosed() {
 | 
			
		||||
		return nil
 | 
			
		||||
	}
 | 
			
		||||
| 
						 | 
				
			
			@ -638,3 +474,11 @@ func (w *Watcher) WatchList() []string {
 | 
			
		|||
 | 
			
		||||
	return entries
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (w *fen) xSupports(op Op) bool {
 | 
			
		||||
	if op.Has(xUnportableOpen) || op.Has(xUnportableRead) ||
 | 
			
		||||
		op.Has(xUnportableCloseWrite) || op.Has(xUnportableCloseRead) {
 | 
			
		||||
		return false
 | 
			
		||||
	}
 | 
			
		||||
	return true
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										594
									
								
								vendor/github.com/fsnotify/fsnotify/backend_inotify.go
									
										
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										594
									
								
								vendor/github.com/fsnotify/fsnotify/backend_inotify.go
									
										
									
										generated
									
									
										vendored
									
									
								
							| 
						 | 
				
			
			@ -1,8 +1,4 @@
 | 
			
		|||
//go:build linux && !appengine
 | 
			
		||||
// +build linux,!appengine
 | 
			
		||||
 | 
			
		||||
// Note: the documentation on the Watcher type and methods is generated from
 | 
			
		||||
// mkdoc.zsh
 | 
			
		||||
 | 
			
		||||
package fsnotify
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -10,127 +6,20 @@ import (
 | 
			
		|||
	"errors"
 | 
			
		||||
	"fmt"
 | 
			
		||||
	"io"
 | 
			
		||||
	"io/fs"
 | 
			
		||||
	"os"
 | 
			
		||||
	"path/filepath"
 | 
			
		||||
	"strings"
 | 
			
		||||
	"sync"
 | 
			
		||||
	"time"
 | 
			
		||||
	"unsafe"
 | 
			
		||||
 | 
			
		||||
	"github.com/fsnotify/fsnotify/internal"
 | 
			
		||||
	"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.
 | 
			
		||||
//
 | 
			
		||||
// # Windows notes
 | 
			
		||||
//
 | 
			
		||||
// Paths can be added as "C:\path\to\dir", but forward slashes
 | 
			
		||||
// ("C:/path/to/dir") will also work.
 | 
			
		||||
//
 | 
			
		||||
// When a watched directory is removed it will always send an event for the
 | 
			
		||||
// directory itself, but may not send events for all files in that directory.
 | 
			
		||||
// Sometimes it will send events for all times, sometimes it will send no
 | 
			
		||||
// events, and often only for some files.
 | 
			
		||||
//
 | 
			
		||||
// The default ReadDirectoryChangesW() buffer size is 64K, which is the largest
 | 
			
		||||
// value that is guaranteed to work with SMB filesystems. If you have many
 | 
			
		||||
// events in quick succession this may not be enough, and you will have to use
 | 
			
		||||
// [WithBufferSize] to increase the value.
 | 
			
		||||
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, and you may
 | 
			
		||||
	//                      want to wait until you've stopped receiving them
 | 
			
		||||
	//                      (see the dedup example in cmd/fsnotify).
 | 
			
		||||
	//
 | 
			
		||||
	//                      Some systems may send Write event for directories
 | 
			
		||||
	//                      when the directory content changes.
 | 
			
		||||
	//
 | 
			
		||||
	//   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
 | 
			
		||||
	//                      when a file is truncated. On Windows it's never
 | 
			
		||||
	//                      sent.
 | 
			
		||||
type inotify struct {
 | 
			
		||||
	Events chan Event
 | 
			
		||||
 | 
			
		||||
	// Errors sends any errors.
 | 
			
		||||
	//
 | 
			
		||||
	// ErrEventOverflow is used to indicate there are too many events:
 | 
			
		||||
	//
 | 
			
		||||
	//  - inotify:      There are too many queued events (fs.inotify.max_queued_events sysctl)
 | 
			
		||||
	//  - windows:      The buffer size is too small; WithBufferSize() can be used to increase it.
 | 
			
		||||
	//  - kqueue, fen:  Not used.
 | 
			
		||||
	Errors chan error
 | 
			
		||||
 | 
			
		||||
	// Store fd here as os.File.Read() will no longer return on close after
 | 
			
		||||
| 
						 | 
				
			
			@ -139,8 +28,26 @@ type Watcher struct {
 | 
			
		|||
	inotifyFile *os.File
 | 
			
		||||
	watches     *watches
 | 
			
		||||
	done        chan struct{} // Channel for sending a "quit message" to the reader goroutine
 | 
			
		||||
	closeMu     sync.Mutex
 | 
			
		||||
	doneMu      sync.Mutex
 | 
			
		||||
	doneResp    chan struct{} // Channel to respond to Close
 | 
			
		||||
 | 
			
		||||
	// Store rename cookies in an array, with the index wrapping to 0. Almost
 | 
			
		||||
	// all of the time what we get is a MOVED_FROM to set the cookie and the
 | 
			
		||||
	// next event inotify sends will be MOVED_TO to read it. However, this is
 | 
			
		||||
	// not guaranteed – as described in inotify(7) – and we may get other events
 | 
			
		||||
	// between the two MOVED_* events (including other MOVED_* ones).
 | 
			
		||||
	//
 | 
			
		||||
	// A second issue is that moving a file outside the watched directory will
 | 
			
		||||
	// trigger a MOVED_FROM to set the cookie, but we never see the MOVED_TO to
 | 
			
		||||
	// read and delete it. So just storing it in a map would slowly leak memory.
 | 
			
		||||
	//
 | 
			
		||||
	// Doing it like this gives us a simple fast LRU-cache that won't allocate.
 | 
			
		||||
	// Ten items should be more than enough for our purpose, and a loop over
 | 
			
		||||
	// such a short array is faster than a map access anyway (not that it hugely
 | 
			
		||||
	// matters since we're talking about hundreds of ns at the most, but still).
 | 
			
		||||
	cookies     [10]koekje
 | 
			
		||||
	cookieIndex uint8
 | 
			
		||||
	cookiesMu   sync.Mutex
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type (
 | 
			
		||||
| 
						 | 
				
			
			@ -150,9 +57,14 @@ type (
 | 
			
		|||
		path map[string]uint32 // pathname → wd
 | 
			
		||||
	}
 | 
			
		||||
	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)
 | 
			
		||||
		path  string // Watch path.
 | 
			
		||||
		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)
 | 
			
		||||
		path    string // Watch path.
 | 
			
		||||
		recurse bool   // Recursion with ./...?
 | 
			
		||||
	}
 | 
			
		||||
	koekje struct {
 | 
			
		||||
		cookie uint32
 | 
			
		||||
		path   string
 | 
			
		||||
	}
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -179,23 +91,45 @@ func (w *watches) add(ww *watch) {
 | 
			
		|||
func (w *watches) remove(wd uint32) {
 | 
			
		||||
	w.mu.Lock()
 | 
			
		||||
	defer w.mu.Unlock()
 | 
			
		||||
	delete(w.path, w.wd[wd].path)
 | 
			
		||||
	watch := w.wd[wd] // Could have had Remove() called. See #616.
 | 
			
		||||
	if watch == nil {
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
	delete(w.path, watch.path)
 | 
			
		||||
	delete(w.wd, wd)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (w *watches) removePath(path string) (uint32, bool) {
 | 
			
		||||
func (w *watches) removePath(path string) ([]uint32, error) {
 | 
			
		||||
	w.mu.Lock()
 | 
			
		||||
	defer w.mu.Unlock()
 | 
			
		||||
 | 
			
		||||
	path, recurse := recursivePath(path)
 | 
			
		||||
	wd, ok := w.path[path]
 | 
			
		||||
	if !ok {
 | 
			
		||||
		return 0, false
 | 
			
		||||
		return nil, fmt.Errorf("%w: %s", ErrNonExistentWatch, path)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	watch := w.wd[wd]
 | 
			
		||||
	if recurse && !watch.recurse {
 | 
			
		||||
		return nil, fmt.Errorf("can't use /... with non-recursive watch %q", path)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	delete(w.path, path)
 | 
			
		||||
	delete(w.wd, wd)
 | 
			
		||||
	if !watch.recurse {
 | 
			
		||||
		return []uint32{wd}, nil
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return wd, true
 | 
			
		||||
	wds := make([]uint32, 0, 8)
 | 
			
		||||
	wds = append(wds, wd)
 | 
			
		||||
	for p, rwd := range w.path {
 | 
			
		||||
		if filepath.HasPrefix(p, path) {
 | 
			
		||||
			delete(w.path, p)
 | 
			
		||||
			delete(w.wd, rwd)
 | 
			
		||||
			wds = append(wds, rwd)
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	return wds, nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (w *watches) byPath(path string) *watch {
 | 
			
		||||
| 
						 | 
				
			
			@ -236,20 +170,11 @@ func (w *watches) updatePath(path string, f func(*watch) (*watch, error)) error
 | 
			
		|||
	return nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// NewWatcher creates a new Watcher.
 | 
			
		||||
func NewWatcher() (*Watcher, error) {
 | 
			
		||||
	return NewBufferedWatcher(0)
 | 
			
		||||
func newBackend(ev chan Event, errs chan error) (backend, error) {
 | 
			
		||||
	return newBufferedBackend(0, ev, errs)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// NewBufferedWatcher creates a new Watcher with a buffered Watcher.Events
 | 
			
		||||
// channel.
 | 
			
		||||
//
 | 
			
		||||
// The main use case for this is situations with a very large number of events
 | 
			
		||||
// where the kernel buffer size can't be increased (e.g. due to lack of
 | 
			
		||||
// permissions). An unbuffered Watcher will perform better for almost all use
 | 
			
		||||
// cases, and whenever possible you will be better off increasing the kernel
 | 
			
		||||
// buffers instead of adding a large userspace buffer.
 | 
			
		||||
func NewBufferedWatcher(sz uint) (*Watcher, error) {
 | 
			
		||||
func newBufferedBackend(sz uint, ev chan Event, errs chan error) (backend, error) {
 | 
			
		||||
	// Need to set nonblocking mode for SetDeadline to work, otherwise blocking
 | 
			
		||||
	// I/O operations won't terminate on close.
 | 
			
		||||
	fd, errno := unix.InotifyInit1(unix.IN_CLOEXEC | unix.IN_NONBLOCK)
 | 
			
		||||
| 
						 | 
				
			
			@ -257,12 +182,12 @@ func NewBufferedWatcher(sz uint) (*Watcher, error) {
 | 
			
		|||
		return nil, errno
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	w := &Watcher{
 | 
			
		||||
	w := &inotify{
 | 
			
		||||
		Events:      ev,
 | 
			
		||||
		Errors:      errs,
 | 
			
		||||
		fd:          fd,
 | 
			
		||||
		inotifyFile: os.NewFile(uintptr(fd), ""),
 | 
			
		||||
		watches:     newWatches(),
 | 
			
		||||
		Events:      make(chan Event, sz),
 | 
			
		||||
		Errors:      make(chan error),
 | 
			
		||||
		done:        make(chan struct{}),
 | 
			
		||||
		doneResp:    make(chan struct{}),
 | 
			
		||||
	}
 | 
			
		||||
| 
						 | 
				
			
			@ -272,26 +197,29 @@ func NewBufferedWatcher(sz uint) (*Watcher, error) {
 | 
			
		|||
}
 | 
			
		||||
 | 
			
		||||
// Returns true if the event was sent, or false if watcher is closed.
 | 
			
		||||
func (w *Watcher) sendEvent(e Event) bool {
 | 
			
		||||
func (w *inotify) sendEvent(e Event) bool {
 | 
			
		||||
	select {
 | 
			
		||||
	case w.Events <- e:
 | 
			
		||||
		return true
 | 
			
		||||
	case <-w.done:
 | 
			
		||||
		return false
 | 
			
		||||
	case w.Events <- e:
 | 
			
		||||
		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:
 | 
			
		||||
func (w *inotify) sendError(err error) bool {
 | 
			
		||||
	if err == nil {
 | 
			
		||||
		return true
 | 
			
		||||
	}
 | 
			
		||||
	select {
 | 
			
		||||
	case <-w.done:
 | 
			
		||||
		return false
 | 
			
		||||
	case w.Errors <- err:
 | 
			
		||||
		return true
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (w *Watcher) isClosed() bool {
 | 
			
		||||
func (w *inotify) isClosed() bool {
 | 
			
		||||
	select {
 | 
			
		||||
	case <-w.done:
 | 
			
		||||
		return true
 | 
			
		||||
| 
						 | 
				
			
			@ -300,15 +228,14 @@ func (w *Watcher) isClosed() bool {
 | 
			
		|||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Close removes all watches and closes the Events channel.
 | 
			
		||||
func (w *Watcher) Close() error {
 | 
			
		||||
	w.closeMu.Lock()
 | 
			
		||||
func (w *inotify) Close() error {
 | 
			
		||||
	w.doneMu.Lock()
 | 
			
		||||
	if w.isClosed() {
 | 
			
		||||
		w.closeMu.Unlock()
 | 
			
		||||
		w.doneMu.Unlock()
 | 
			
		||||
		return nil
 | 
			
		||||
	}
 | 
			
		||||
	close(w.done)
 | 
			
		||||
	w.closeMu.Unlock()
 | 
			
		||||
	w.doneMu.Unlock()
 | 
			
		||||
 | 
			
		||||
	// Causes any blocking reads to return with an error, provided the file
 | 
			
		||||
	// still supports deadline operations.
 | 
			
		||||
| 
						 | 
				
			
			@ -323,78 +250,104 @@ func (w *Watcher) Close() error {
 | 
			
		|||
	return nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Add starts monitoring the path for changes.
 | 
			
		||||
//
 | 
			
		||||
// A path can only be watched once; watching it more than once is a no-op and will
 | 
			
		||||
// not return an error. Paths that do not yet exist on the filesystem cannot be
 | 
			
		||||
// watched.
 | 
			
		||||
//
 | 
			
		||||
// A watch will be automatically removed if the watched path is deleted or
 | 
			
		||||
// renamed. The exception is the Windows backend, which doesn't remove the
 | 
			
		||||
// watcher on renames.
 | 
			
		||||
//
 | 
			
		||||
// Notifications on network filesystems (NFS, SMB, FUSE, etc.) or special
 | 
			
		||||
// filesystems (/proc, /sys, etc.) generally don't work.
 | 
			
		||||
//
 | 
			
		||||
// Returns [ErrClosed] if [Watcher.Close] was called.
 | 
			
		||||
//
 | 
			
		||||
// See [Watcher.AddWith] for a version that allows adding options.
 | 
			
		||||
//
 | 
			
		||||
// # 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 programs (especially editors) update files atomically: it
 | 
			
		||||
// will write to a temporary file which is then moved to to destination,
 | 
			
		||||
// overwriting the original (or some variant thereof). The watcher on the
 | 
			
		||||
// original file is now lost, as that no longer exists.
 | 
			
		||||
//
 | 
			
		||||
// The upshot of this is that a power failure or crash won't leave a
 | 
			
		||||
// half-written file.
 | 
			
		||||
//
 | 
			
		||||
// 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 w.AddWith(name) }
 | 
			
		||||
func (w *inotify) Add(name string) error { return w.AddWith(name) }
 | 
			
		||||
 | 
			
		||||
// AddWith is like [Watcher.Add], but allows adding options. When using Add()
 | 
			
		||||
// the defaults described below are used.
 | 
			
		||||
//
 | 
			
		||||
// Possible options are:
 | 
			
		||||
//
 | 
			
		||||
//   - [WithBufferSize] sets the buffer size for the Windows backend; no-op on
 | 
			
		||||
//     other platforms. The default is 64K (65536 bytes).
 | 
			
		||||
func (w *Watcher) AddWith(name string, opts ...addOpt) error {
 | 
			
		||||
func (w *inotify) AddWith(path string, opts ...addOpt) error {
 | 
			
		||||
	if w.isClosed() {
 | 
			
		||||
		return ErrClosed
 | 
			
		||||
	}
 | 
			
		||||
	if debug {
 | 
			
		||||
		fmt.Fprintf(os.Stderr, "FSNOTIFY_DEBUG: %s  AddWith(%q)\n",
 | 
			
		||||
			time.Now().Format("15:04:05.000000000"), path)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	name = filepath.Clean(name)
 | 
			
		||||
	_ = getOptions(opts...)
 | 
			
		||||
	with := getOptions(opts...)
 | 
			
		||||
	if !w.xSupports(with.op) {
 | 
			
		||||
		return fmt.Errorf("%w: %s", xErrUnsupported, with.op)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	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
 | 
			
		||||
	path, recurse := recursivePath(path)
 | 
			
		||||
	if recurse {
 | 
			
		||||
		return filepath.WalkDir(path, func(root string, d fs.DirEntry, err error) error {
 | 
			
		||||
			if err != nil {
 | 
			
		||||
				return err
 | 
			
		||||
			}
 | 
			
		||||
			if !d.IsDir() {
 | 
			
		||||
				if root == path {
 | 
			
		||||
					return fmt.Errorf("fsnotify: not a directory: %q", path)
 | 
			
		||||
				}
 | 
			
		||||
				return nil
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
	return w.watches.updatePath(name, func(existing *watch) (*watch, error) {
 | 
			
		||||
			// Send a Create event when adding new directory from a recursive
 | 
			
		||||
			// watch; this is for "mkdir -p one/two/three". Usually all those
 | 
			
		||||
			// directories will be created before we can set up watchers on the
 | 
			
		||||
			// subdirectories, so only "one" would be sent as a Create event and
 | 
			
		||||
			// not "one/two" and "one/two/three" (inotifywait -r has the same
 | 
			
		||||
			// problem).
 | 
			
		||||
			if with.sendCreate && root != path {
 | 
			
		||||
				w.sendEvent(Event{Name: root, Op: Create})
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			return w.add(root, with, true)
 | 
			
		||||
		})
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return w.add(path, with, false)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (w *inotify) add(path string, with withOpts, recurse bool) error {
 | 
			
		||||
	var flags uint32
 | 
			
		||||
	if with.noFollow {
 | 
			
		||||
		flags |= unix.IN_DONT_FOLLOW
 | 
			
		||||
	}
 | 
			
		||||
	if with.op.Has(Create) {
 | 
			
		||||
		flags |= unix.IN_CREATE
 | 
			
		||||
	}
 | 
			
		||||
	if with.op.Has(Write) {
 | 
			
		||||
		flags |= unix.IN_MODIFY
 | 
			
		||||
	}
 | 
			
		||||
	if with.op.Has(Remove) {
 | 
			
		||||
		flags |= unix.IN_DELETE | unix.IN_DELETE_SELF
 | 
			
		||||
	}
 | 
			
		||||
	if with.op.Has(Rename) {
 | 
			
		||||
		flags |= unix.IN_MOVED_TO | unix.IN_MOVED_FROM | unix.IN_MOVE_SELF
 | 
			
		||||
	}
 | 
			
		||||
	if with.op.Has(Chmod) {
 | 
			
		||||
		flags |= unix.IN_ATTRIB
 | 
			
		||||
	}
 | 
			
		||||
	if with.op.Has(xUnportableOpen) {
 | 
			
		||||
		flags |= unix.IN_OPEN
 | 
			
		||||
	}
 | 
			
		||||
	if with.op.Has(xUnportableRead) {
 | 
			
		||||
		flags |= unix.IN_ACCESS
 | 
			
		||||
	}
 | 
			
		||||
	if with.op.Has(xUnportableCloseWrite) {
 | 
			
		||||
		flags |= unix.IN_CLOSE_WRITE
 | 
			
		||||
	}
 | 
			
		||||
	if with.op.Has(xUnportableCloseRead) {
 | 
			
		||||
		flags |= unix.IN_CLOSE_NOWRITE
 | 
			
		||||
	}
 | 
			
		||||
	return w.register(path, flags, recurse)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (w *inotify) register(path string, flags uint32, recurse bool) error {
 | 
			
		||||
	return w.watches.updatePath(path, func(existing *watch) (*watch, error) {
 | 
			
		||||
		if existing != nil {
 | 
			
		||||
			flags |= existing.flags | unix.IN_MASK_ADD
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		wd, err := unix.InotifyAddWatch(w.fd, name, flags)
 | 
			
		||||
		wd, err := unix.InotifyAddWatch(w.fd, path, flags)
 | 
			
		||||
		if wd == -1 {
 | 
			
		||||
			return nil, err
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		if existing == nil {
 | 
			
		||||
			return &watch{
 | 
			
		||||
				wd:    uint32(wd),
 | 
			
		||||
				path:  name,
 | 
			
		||||
				flags: flags,
 | 
			
		||||
				wd:      uint32(wd),
 | 
			
		||||
				path:    path,
 | 
			
		||||
				flags:   flags,
 | 
			
		||||
				recurse: recurse,
 | 
			
		||||
			}, nil
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -404,49 +357,44 @@ func (w *Watcher) AddWith(name string, opts ...addOpt) error {
 | 
			
		|||
	})
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// 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].
 | 
			
		||||
//
 | 
			
		||||
// Returns nil if [Watcher.Close] was called.
 | 
			
		||||
func (w *Watcher) Remove(name string) error {
 | 
			
		||||
func (w *inotify) Remove(name string) error {
 | 
			
		||||
	if w.isClosed() {
 | 
			
		||||
		return nil
 | 
			
		||||
	}
 | 
			
		||||
	if debug {
 | 
			
		||||
		fmt.Fprintf(os.Stderr, "FSNOTIFY_DEBUG: %s  Remove(%q)\n",
 | 
			
		||||
			time.Now().Format("15:04:05.000000000"), name)
 | 
			
		||||
	}
 | 
			
		||||
	return w.remove(filepath.Clean(name))
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (w *Watcher) remove(name string) error {
 | 
			
		||||
	wd, ok := w.watches.removePath(name)
 | 
			
		||||
	if !ok {
 | 
			
		||||
		return fmt.Errorf("%w: %s", ErrNonExistentWatch, name)
 | 
			
		||||
func (w *inotify) remove(name string) error {
 | 
			
		||||
	wds, err := w.watches.removePath(name)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	success, errno := unix.InotifyRmWatch(w.fd, 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
 | 
			
		||||
	for _, wd := range wds {
 | 
			
		||||
		_, err := unix.InotifyRmWatch(w.fd, wd)
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			// 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 err
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	return nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// WatchList returns all paths explicitly added with [Watcher.Add] (and are not
 | 
			
		||||
// yet removed).
 | 
			
		||||
//
 | 
			
		||||
// Returns nil if [Watcher.Close] was called.
 | 
			
		||||
func (w *Watcher) WatchList() []string {
 | 
			
		||||
func (w *inotify) WatchList() []string {
 | 
			
		||||
	if w.isClosed() {
 | 
			
		||||
		return nil
 | 
			
		||||
	}
 | 
			
		||||
| 
						 | 
				
			
			@ -463,7 +411,7 @@ func (w *Watcher) WatchList() []string {
 | 
			
		|||
 | 
			
		||||
// 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() {
 | 
			
		||||
func (w *inotify) readEvents() {
 | 
			
		||||
	defer func() {
 | 
			
		||||
		close(w.doneResp)
 | 
			
		||||
		close(w.Errors)
 | 
			
		||||
| 
						 | 
				
			
			@ -506,15 +454,17 @@ func (w *Watcher) readEvents() {
 | 
			
		|||
			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...
 | 
			
		||||
		var offset uint32
 | 
			
		||||
		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)
 | 
			
		||||
				// Move to the next event in the buffer
 | 
			
		||||
				next = func() { offset += unix.SizeofInotifyEvent + nameLen }
 | 
			
		||||
			)
 | 
			
		||||
 | 
			
		||||
			if mask&unix.IN_Q_OVERFLOW != 0 {
 | 
			
		||||
| 
						 | 
				
			
			@ -523,21 +473,53 @@ func (w *Watcher) readEvents() {
 | 
			
		|||
				}
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			// 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.
 | 
			
		||||
			/// 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.
 | 
			
		||||
			watch := w.watches.byWd(uint32(raw.Wd))
 | 
			
		||||
			/// Can be nil if Remove() was called in another goroutine for this
 | 
			
		||||
			/// path inbetween reading the events from the kernel and reading
 | 
			
		||||
			/// the internal state. Not much we can do about it, so just skip.
 | 
			
		||||
			/// See #616.
 | 
			
		||||
			if watch == nil {
 | 
			
		||||
				next()
 | 
			
		||||
				continue
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			name := watch.path
 | 
			
		||||
			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")
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			if debug {
 | 
			
		||||
				internal.Debug(name, raw.Mask, raw.Cookie)
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			if mask&unix.IN_IGNORED != 0 { //&& event.Op != 0
 | 
			
		||||
				next()
 | 
			
		||||
				continue
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			// inotify will automatically remove the watch on deletes; just need
 | 
			
		||||
			// to clean our state here.
 | 
			
		||||
			if watch != nil && mask&unix.IN_DELETE_SELF == unix.IN_DELETE_SELF {
 | 
			
		||||
			if mask&unix.IN_DELETE_SELF == unix.IN_DELETE_SELF {
 | 
			
		||||
				w.watches.remove(watch.wd)
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			// We can't really update the state when a watched path is moved;
 | 
			
		||||
			// only IN_MOVE_SELF is sent and not IN_MOVED_{FROM,TO}. So remove
 | 
			
		||||
			// the watch.
 | 
			
		||||
			if watch != nil && mask&unix.IN_MOVE_SELF == unix.IN_MOVE_SELF {
 | 
			
		||||
			if mask&unix.IN_MOVE_SELF == unix.IN_MOVE_SELF {
 | 
			
		||||
				if watch.recurse {
 | 
			
		||||
					next() // Do nothing
 | 
			
		||||
					continue
 | 
			
		||||
				}
 | 
			
		||||
 | 
			
		||||
				err := w.remove(watch.path)
 | 
			
		||||
				if err != nil && !errors.Is(err, ErrNonExistentWatch) {
 | 
			
		||||
					if !w.sendError(err) {
 | 
			
		||||
| 
						 | 
				
			
			@ -546,34 +528,69 @@ func (w *Watcher) readEvents() {
 | 
			
		|||
				}
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			var name string
 | 
			
		||||
			if watch != nil {
 | 
			
		||||
				name = watch.path
 | 
			
		||||
			}
 | 
			
		||||
			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
 | 
			
		||||
			/// Skip if we're watching both this path and the parent; the parent
 | 
			
		||||
			/// will already send a delete so no need to do it twice.
 | 
			
		||||
			if mask&unix.IN_DELETE_SELF != 0 {
 | 
			
		||||
				if _, ok := w.watches.path[filepath.Dir(watch.path)]; ok {
 | 
			
		||||
					next()
 | 
			
		||||
					continue
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			// Move to the next event in the buffer
 | 
			
		||||
			offset += unix.SizeofInotifyEvent + nameLen
 | 
			
		||||
			ev := w.newEvent(name, mask, raw.Cookie)
 | 
			
		||||
			// Need to update watch path for recurse.
 | 
			
		||||
			if watch.recurse {
 | 
			
		||||
				isDir := mask&unix.IN_ISDIR == unix.IN_ISDIR
 | 
			
		||||
				/// New directory created: set up watch on it.
 | 
			
		||||
				if isDir && ev.Has(Create) {
 | 
			
		||||
					err := w.register(ev.Name, watch.flags, true)
 | 
			
		||||
					if !w.sendError(err) {
 | 
			
		||||
						return
 | 
			
		||||
					}
 | 
			
		||||
 | 
			
		||||
					// This was a directory rename, so we need to update all
 | 
			
		||||
					// the children.
 | 
			
		||||
					//
 | 
			
		||||
					// TODO: this is of course pretty slow; we should use a
 | 
			
		||||
					// better data structure for storing all of this, e.g. store
 | 
			
		||||
					// children in the watch. I have some code for this in my
 | 
			
		||||
					// kqueue refactor we can use in the future. For now I'm
 | 
			
		||||
					// okay with this as it's not publicly available.
 | 
			
		||||
					// Correctness first, performance second.
 | 
			
		||||
					if ev.renamedFrom != "" {
 | 
			
		||||
						w.watches.mu.Lock()
 | 
			
		||||
						for k, ww := range w.watches.wd {
 | 
			
		||||
							if k == watch.wd || ww.path == ev.Name {
 | 
			
		||||
								continue
 | 
			
		||||
							}
 | 
			
		||||
							if strings.HasPrefix(ww.path, ev.renamedFrom) {
 | 
			
		||||
								ww.path = strings.Replace(ww.path, ev.renamedFrom, ev.Name, 1)
 | 
			
		||||
								w.watches.wd[k] = ww
 | 
			
		||||
							}
 | 
			
		||||
						}
 | 
			
		||||
						w.watches.mu.Unlock()
 | 
			
		||||
					}
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			/// Send the events that are not ignored on the events channel
 | 
			
		||||
			if !w.sendEvent(ev) {
 | 
			
		||||
				return
 | 
			
		||||
			}
 | 
			
		||||
			next()
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// newEvent returns an platform-independent Event based on an inotify mask.
 | 
			
		||||
func (w *Watcher) newEvent(name string, mask uint32) Event {
 | 
			
		||||
func (w *inotify) isRecursive(path string) bool {
 | 
			
		||||
	ww := w.watches.byPath(path)
 | 
			
		||||
	if ww == nil { // path could be a file, so also check the Dir.
 | 
			
		||||
		ww = w.watches.byPath(filepath.Dir(path))
 | 
			
		||||
	}
 | 
			
		||||
	return ww != nil && ww.recurse
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (w *inotify) newEvent(name string, mask, cookie 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
 | 
			
		||||
| 
						 | 
				
			
			@ -584,11 +601,58 @@ func (w *Watcher) newEvent(name string, mask uint32) Event {
 | 
			
		|||
	if mask&unix.IN_MODIFY == unix.IN_MODIFY {
 | 
			
		||||
		e.Op |= Write
 | 
			
		||||
	}
 | 
			
		||||
	if mask&unix.IN_OPEN == unix.IN_OPEN {
 | 
			
		||||
		e.Op |= xUnportableOpen
 | 
			
		||||
	}
 | 
			
		||||
	if mask&unix.IN_ACCESS == unix.IN_ACCESS {
 | 
			
		||||
		e.Op |= xUnportableRead
 | 
			
		||||
	}
 | 
			
		||||
	if mask&unix.IN_CLOSE_WRITE == unix.IN_CLOSE_WRITE {
 | 
			
		||||
		e.Op |= xUnportableCloseWrite
 | 
			
		||||
	}
 | 
			
		||||
	if mask&unix.IN_CLOSE_NOWRITE == unix.IN_CLOSE_NOWRITE {
 | 
			
		||||
		e.Op |= xUnportableCloseRead
 | 
			
		||||
	}
 | 
			
		||||
	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
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if cookie != 0 {
 | 
			
		||||
		if mask&unix.IN_MOVED_FROM == unix.IN_MOVED_FROM {
 | 
			
		||||
			w.cookiesMu.Lock()
 | 
			
		||||
			w.cookies[w.cookieIndex] = koekje{cookie: cookie, path: e.Name}
 | 
			
		||||
			w.cookieIndex++
 | 
			
		||||
			if w.cookieIndex > 9 {
 | 
			
		||||
				w.cookieIndex = 0
 | 
			
		||||
			}
 | 
			
		||||
			w.cookiesMu.Unlock()
 | 
			
		||||
		} else if mask&unix.IN_MOVED_TO == unix.IN_MOVED_TO {
 | 
			
		||||
			w.cookiesMu.Lock()
 | 
			
		||||
			var prev string
 | 
			
		||||
			for _, c := range w.cookies {
 | 
			
		||||
				if c.cookie == cookie {
 | 
			
		||||
					prev = c.path
 | 
			
		||||
					break
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
			w.cookiesMu.Unlock()
 | 
			
		||||
			e.renamedFrom = prev
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	return e
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (w *inotify) xSupports(op Op) bool {
 | 
			
		||||
	return true // Supports everything.
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (w *inotify) state() {
 | 
			
		||||
	w.watches.mu.Lock()
 | 
			
		||||
	defer w.watches.mu.Unlock()
 | 
			
		||||
	for wd, ww := range w.watches.wd {
 | 
			
		||||
		fmt.Fprintf(os.Stderr, "%4d: recurse=%t %q\n", wd, ww.recurse, ww.path)
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										747
									
								
								vendor/github.com/fsnotify/fsnotify/backend_kqueue.go
									
										
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										747
									
								
								vendor/github.com/fsnotify/fsnotify/backend_kqueue.go
									
										
									
										generated
									
									
										vendored
									
									
								
							
										
											
												File diff suppressed because it is too large
												Load diff
											
										
									
								
							
							
								
								
									
										204
									
								
								vendor/github.com/fsnotify/fsnotify/backend_other.go
									
										
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										204
									
								
								vendor/github.com/fsnotify/fsnotify/backend_other.go
									
										
									
										generated
									
									
										vendored
									
									
								
							| 
						 | 
				
			
			@ -1,205 +1,23 @@
 | 
			
		|||
//go:build appengine || (!darwin && !dragonfly && !freebsd && !openbsd && !linux && !netbsd && !solaris && !windows)
 | 
			
		||||
// +build appengine !darwin,!dragonfly,!freebsd,!openbsd,!linux,!netbsd,!solaris,!windows
 | 
			
		||||
 | 
			
		||||
// Note: the documentation on the Watcher type and methods is generated from
 | 
			
		||||
// mkdoc.zsh
 | 
			
		||||
 | 
			
		||||
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.
 | 
			
		||||
//
 | 
			
		||||
// # Windows notes
 | 
			
		||||
//
 | 
			
		||||
// Paths can be added as "C:\path\to\dir", but forward slashes
 | 
			
		||||
// ("C:/path/to/dir") will also work.
 | 
			
		||||
//
 | 
			
		||||
// When a watched directory is removed it will always send an event for the
 | 
			
		||||
// directory itself, but may not send events for all files in that directory.
 | 
			
		||||
// Sometimes it will send events for all times, sometimes it will send no
 | 
			
		||||
// events, and often only for some files.
 | 
			
		||||
//
 | 
			
		||||
// The default ReadDirectoryChangesW() buffer size is 64K, which is the largest
 | 
			
		||||
// value that is guaranteed to work with SMB filesystems. If you have many
 | 
			
		||||
// events in quick succession this may not be enough, and you will have to use
 | 
			
		||||
// [WithBufferSize] to increase the value.
 | 
			
		||||
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, and you may
 | 
			
		||||
	//                      want to wait until you've stopped receiving them
 | 
			
		||||
	//                      (see the dedup example in cmd/fsnotify).
 | 
			
		||||
	//
 | 
			
		||||
	//                      Some systems may send Write event for directories
 | 
			
		||||
	//                      when the directory content changes.
 | 
			
		||||
	//
 | 
			
		||||
	//   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
 | 
			
		||||
	//                      when a file is truncated. On Windows it's never
 | 
			
		||||
	//                      sent.
 | 
			
		||||
type other struct {
 | 
			
		||||
	Events chan Event
 | 
			
		||||
 | 
			
		||||
	// Errors sends any errors.
 | 
			
		||||
	//
 | 
			
		||||
	// ErrEventOverflow is used to indicate there are too many events:
 | 
			
		||||
	//
 | 
			
		||||
	//  - inotify:      There are too many queued events (fs.inotify.max_queued_events sysctl)
 | 
			
		||||
	//  - windows:      The buffer size is too small; WithBufferSize() can be used to increase it.
 | 
			
		||||
	//  - kqueue, fen:  Not used.
 | 
			
		||||
	Errors chan error
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// NewWatcher creates a new Watcher.
 | 
			
		||||
func NewWatcher() (*Watcher, error) {
 | 
			
		||||
func newBackend(ev chan Event, errs chan error) (backend, error) {
 | 
			
		||||
	return nil, errors.New("fsnotify not supported on the current platform")
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// NewBufferedWatcher creates a new Watcher with a buffered Watcher.Events
 | 
			
		||||
// channel.
 | 
			
		||||
//
 | 
			
		||||
// The main use case for this is situations with a very large number of events
 | 
			
		||||
// where the kernel buffer size can't be increased (e.g. due to lack of
 | 
			
		||||
// permissions). An unbuffered Watcher will perform better for almost all use
 | 
			
		||||
// cases, and whenever possible you will be better off increasing the kernel
 | 
			
		||||
// buffers instead of adding a large userspace buffer.
 | 
			
		||||
func NewBufferedWatcher(sz uint) (*Watcher, error) { return NewWatcher() }
 | 
			
		||||
 | 
			
		||||
// Close removes all watches and closes the Events channel.
 | 
			
		||||
func (w *Watcher) Close() error { return nil }
 | 
			
		||||
 | 
			
		||||
// WatchList returns all paths explicitly added with [Watcher.Add] (and are not
 | 
			
		||||
// yet removed).
 | 
			
		||||
//
 | 
			
		||||
// Returns nil if [Watcher.Close] was called.
 | 
			
		||||
func (w *Watcher) WatchList() []string { return nil }
 | 
			
		||||
 | 
			
		||||
// Add starts monitoring the path for changes.
 | 
			
		||||
//
 | 
			
		||||
// A path can only be watched once; watching it more than once is a no-op and will
 | 
			
		||||
// not return an error. Paths that do not yet exist on the filesystem cannot be
 | 
			
		||||
// watched.
 | 
			
		||||
//
 | 
			
		||||
// A watch will be automatically removed if the watched path is deleted or
 | 
			
		||||
// renamed. The exception is the Windows backend, which doesn't remove the
 | 
			
		||||
// watcher on renames.
 | 
			
		||||
//
 | 
			
		||||
// Notifications on network filesystems (NFS, SMB, FUSE, etc.) or special
 | 
			
		||||
// filesystems (/proc, /sys, etc.) generally don't work.
 | 
			
		||||
//
 | 
			
		||||
// Returns [ErrClosed] if [Watcher.Close] was called.
 | 
			
		||||
//
 | 
			
		||||
// See [Watcher.AddWith] for a version that allows adding options.
 | 
			
		||||
//
 | 
			
		||||
// # 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 programs (especially editors) update files atomically: it
 | 
			
		||||
// will write to a temporary file which is then moved to to destination,
 | 
			
		||||
// overwriting the original (or some variant thereof). The watcher on the
 | 
			
		||||
// original file is now lost, as that no longer exists.
 | 
			
		||||
//
 | 
			
		||||
// The upshot of this is that a power failure or crash won't leave a
 | 
			
		||||
// half-written file.
 | 
			
		||||
//
 | 
			
		||||
// 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 }
 | 
			
		||||
 | 
			
		||||
// AddWith is like [Watcher.Add], but allows adding options. When using Add()
 | 
			
		||||
// the defaults described below are used.
 | 
			
		||||
//
 | 
			
		||||
// Possible options are:
 | 
			
		||||
//
 | 
			
		||||
//   - [WithBufferSize] sets the buffer size for the Windows backend; no-op on
 | 
			
		||||
//     other platforms. The default is 64K (65536 bytes).
 | 
			
		||||
func (w *Watcher) AddWith(name string, opts ...addOpt) 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].
 | 
			
		||||
//
 | 
			
		||||
// Returns nil if [Watcher.Close] was called.
 | 
			
		||||
func (w *Watcher) Remove(name string) error { return nil }
 | 
			
		||||
func newBufferedBackend(sz uint, ev chan Event, errs chan error) (backend, error) {
 | 
			
		||||
	return newBackend(ev, errs)
 | 
			
		||||
}
 | 
			
		||||
func (w *other) Close() error                              { return nil }
 | 
			
		||||
func (w *other) WatchList() []string                       { return nil }
 | 
			
		||||
func (w *other) Add(name string) error                     { return nil }
 | 
			
		||||
func (w *other) AddWith(name string, opts ...addOpt) error { return nil }
 | 
			
		||||
func (w *other) Remove(name string) error                  { return nil }
 | 
			
		||||
func (w *other) xSupports(op Op) bool                      { return false }
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										305
									
								
								vendor/github.com/fsnotify/fsnotify/backend_windows.go
									
										
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										305
									
								
								vendor/github.com/fsnotify/fsnotify/backend_windows.go
									
										
									
										generated
									
									
										vendored
									
									
								
							| 
						 | 
				
			
			@ -1,12 +1,8 @@
 | 
			
		|||
//go:build windows
 | 
			
		||||
// +build windows
 | 
			
		||||
 | 
			
		||||
// Windows backend based on ReadDirectoryChangesW()
 | 
			
		||||
//
 | 
			
		||||
// https://learn.microsoft.com/en-us/windows/win32/api/winbase/nf-winbase-readdirectorychangesw
 | 
			
		||||
//
 | 
			
		||||
// Note: the documentation on the Watcher type and methods is generated from
 | 
			
		||||
// mkdoc.zsh
 | 
			
		||||
 | 
			
		||||
package fsnotify
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -19,123 +15,15 @@ import (
 | 
			
		|||
	"runtime"
 | 
			
		||||
	"strings"
 | 
			
		||||
	"sync"
 | 
			
		||||
	"time"
 | 
			
		||||
	"unsafe"
 | 
			
		||||
 | 
			
		||||
	"github.com/fsnotify/fsnotify/internal"
 | 
			
		||||
	"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.
 | 
			
		||||
//
 | 
			
		||||
// # Windows notes
 | 
			
		||||
//
 | 
			
		||||
// Paths can be added as "C:\path\to\dir", but forward slashes
 | 
			
		||||
// ("C:/path/to/dir") will also work.
 | 
			
		||||
//
 | 
			
		||||
// When a watched directory is removed it will always send an event for the
 | 
			
		||||
// directory itself, but may not send events for all files in that directory.
 | 
			
		||||
// Sometimes it will send events for all times, sometimes it will send no
 | 
			
		||||
// events, and often only for some files.
 | 
			
		||||
//
 | 
			
		||||
// The default ReadDirectoryChangesW() buffer size is 64K, which is the largest
 | 
			
		||||
// value that is guaranteed to work with SMB filesystems. If you have many
 | 
			
		||||
// events in quick succession this may not be enough, and you will have to use
 | 
			
		||||
// [WithBufferSize] to increase the value.
 | 
			
		||||
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, and you may
 | 
			
		||||
	//                      want to wait until you've stopped receiving them
 | 
			
		||||
	//                      (see the dedup example in cmd/fsnotify).
 | 
			
		||||
	//
 | 
			
		||||
	//                      Some systems may send Write event for directories
 | 
			
		||||
	//                      when the directory content changes.
 | 
			
		||||
	//
 | 
			
		||||
	//   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
 | 
			
		||||
	//                      when a file is truncated. On Windows it's never
 | 
			
		||||
	//                      sent.
 | 
			
		||||
type readDirChangesW struct {
 | 
			
		||||
	Events chan Event
 | 
			
		||||
 | 
			
		||||
	// Errors sends any errors.
 | 
			
		||||
	//
 | 
			
		||||
	// ErrEventOverflow is used to indicate there are too many events:
 | 
			
		||||
	//
 | 
			
		||||
	//  - inotify:      There are too many queued events (fs.inotify.max_queued_events sysctl)
 | 
			
		||||
	//  - windows:      The buffer size is too small; WithBufferSize() can be used to increase it.
 | 
			
		||||
	//  - kqueue, fen:  Not used.
 | 
			
		||||
	Errors chan error
 | 
			
		||||
 | 
			
		||||
	port  windows.Handle // Handle to completion port
 | 
			
		||||
| 
						 | 
				
			
			@ -147,48 +35,40 @@ type Watcher struct {
 | 
			
		|||
	closed  bool       // Set to true when Close() is first called
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// NewWatcher creates a new Watcher.
 | 
			
		||||
func NewWatcher() (*Watcher, error) {
 | 
			
		||||
	return NewBufferedWatcher(50)
 | 
			
		||||
func newBackend(ev chan Event, errs chan error) (backend, error) {
 | 
			
		||||
	return newBufferedBackend(50, ev, errs)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// NewBufferedWatcher creates a new Watcher with a buffered Watcher.Events
 | 
			
		||||
// channel.
 | 
			
		||||
//
 | 
			
		||||
// The main use case for this is situations with a very large number of events
 | 
			
		||||
// where the kernel buffer size can't be increased (e.g. due to lack of
 | 
			
		||||
// permissions). An unbuffered Watcher will perform better for almost all use
 | 
			
		||||
// cases, and whenever possible you will be better off increasing the kernel
 | 
			
		||||
// buffers instead of adding a large userspace buffer.
 | 
			
		||||
func NewBufferedWatcher(sz uint) (*Watcher, error) {
 | 
			
		||||
func newBufferedBackend(sz uint, ev chan Event, errs chan error) (backend, error) {
 | 
			
		||||
	port, err := windows.CreateIoCompletionPort(windows.InvalidHandle, 0, 0, 0)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return nil, os.NewSyscallError("CreateIoCompletionPort", err)
 | 
			
		||||
	}
 | 
			
		||||
	w := &Watcher{
 | 
			
		||||
	w := &readDirChangesW{
 | 
			
		||||
		Events:  ev,
 | 
			
		||||
		Errors:  errs,
 | 
			
		||||
		port:    port,
 | 
			
		||||
		watches: make(watchMap),
 | 
			
		||||
		input:   make(chan *input, 1),
 | 
			
		||||
		Events:  make(chan Event, sz),
 | 
			
		||||
		Errors:  make(chan error),
 | 
			
		||||
		quit:    make(chan chan<- error, 1),
 | 
			
		||||
	}
 | 
			
		||||
	go w.readEvents()
 | 
			
		||||
	return w, nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (w *Watcher) isClosed() bool {
 | 
			
		||||
func (w *readDirChangesW) isClosed() bool {
 | 
			
		||||
	w.mu.Lock()
 | 
			
		||||
	defer w.mu.Unlock()
 | 
			
		||||
	return w.closed
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (w *Watcher) sendEvent(name string, mask uint64) bool {
 | 
			
		||||
func (w *readDirChangesW) sendEvent(name, renamedFrom string, mask uint64) bool {
 | 
			
		||||
	if mask == 0 {
 | 
			
		||||
		return false
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	event := w.newEvent(name, uint32(mask))
 | 
			
		||||
	event.renamedFrom = renamedFrom
 | 
			
		||||
	select {
 | 
			
		||||
	case ch := <-w.quit:
 | 
			
		||||
		w.quit <- ch
 | 
			
		||||
| 
						 | 
				
			
			@ -198,17 +78,19 @@ func (w *Watcher) sendEvent(name string, mask uint64) bool {
 | 
			
		|||
}
 | 
			
		||||
 | 
			
		||||
// Returns true if the error was sent, or false if watcher is closed.
 | 
			
		||||
func (w *Watcher) sendError(err error) bool {
 | 
			
		||||
func (w *readDirChangesW) sendError(err error) bool {
 | 
			
		||||
	if err == nil {
 | 
			
		||||
		return true
 | 
			
		||||
	}
 | 
			
		||||
	select {
 | 
			
		||||
	case w.Errors <- err:
 | 
			
		||||
		return true
 | 
			
		||||
	case <-w.quit:
 | 
			
		||||
		return false
 | 
			
		||||
	}
 | 
			
		||||
	return false
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Close removes all watches and closes the Events channel.
 | 
			
		||||
func (w *Watcher) Close() error {
 | 
			
		||||
func (w *readDirChangesW) Close() error {
 | 
			
		||||
	if w.isClosed() {
 | 
			
		||||
		return nil
 | 
			
		||||
	}
 | 
			
		||||
| 
						 | 
				
			
			@ -226,57 +108,21 @@ func (w *Watcher) Close() error {
 | 
			
		|||
	return <-ch
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Add starts monitoring the path for changes.
 | 
			
		||||
//
 | 
			
		||||
// A path can only be watched once; watching it more than once is a no-op and will
 | 
			
		||||
// not return an error. Paths that do not yet exist on the filesystem cannot be
 | 
			
		||||
// watched.
 | 
			
		||||
//
 | 
			
		||||
// A watch will be automatically removed if the watched path is deleted or
 | 
			
		||||
// renamed. The exception is the Windows backend, which doesn't remove the
 | 
			
		||||
// watcher on renames.
 | 
			
		||||
//
 | 
			
		||||
// Notifications on network filesystems (NFS, SMB, FUSE, etc.) or special
 | 
			
		||||
// filesystems (/proc, /sys, etc.) generally don't work.
 | 
			
		||||
//
 | 
			
		||||
// Returns [ErrClosed] if [Watcher.Close] was called.
 | 
			
		||||
//
 | 
			
		||||
// See [Watcher.AddWith] for a version that allows adding options.
 | 
			
		||||
//
 | 
			
		||||
// # 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 programs (especially editors) update files atomically: it
 | 
			
		||||
// will write to a temporary file which is then moved to to destination,
 | 
			
		||||
// overwriting the original (or some variant thereof). The watcher on the
 | 
			
		||||
// original file is now lost, as that no longer exists.
 | 
			
		||||
//
 | 
			
		||||
// The upshot of this is that a power failure or crash won't leave a
 | 
			
		||||
// half-written file.
 | 
			
		||||
//
 | 
			
		||||
// 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 w.AddWith(name) }
 | 
			
		||||
func (w *readDirChangesW) Add(name string) error { return w.AddWith(name) }
 | 
			
		||||
 | 
			
		||||
// AddWith is like [Watcher.Add], but allows adding options. When using Add()
 | 
			
		||||
// the defaults described below are used.
 | 
			
		||||
//
 | 
			
		||||
// Possible options are:
 | 
			
		||||
//
 | 
			
		||||
//   - [WithBufferSize] sets the buffer size for the Windows backend; no-op on
 | 
			
		||||
//     other platforms. The default is 64K (65536 bytes).
 | 
			
		||||
func (w *Watcher) AddWith(name string, opts ...addOpt) error {
 | 
			
		||||
func (w *readDirChangesW) AddWith(name string, opts ...addOpt) error {
 | 
			
		||||
	if w.isClosed() {
 | 
			
		||||
		return ErrClosed
 | 
			
		||||
	}
 | 
			
		||||
	if debug {
 | 
			
		||||
		fmt.Fprintf(os.Stderr, "FSNOTIFY_DEBUG: %s  AddWith(%q)\n",
 | 
			
		||||
			time.Now().Format("15:04:05.000000000"), filepath.ToSlash(name))
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	with := getOptions(opts...)
 | 
			
		||||
	if !w.xSupports(with.op) {
 | 
			
		||||
		return fmt.Errorf("%w: %s", xErrUnsupported, with.op)
 | 
			
		||||
	}
 | 
			
		||||
	if with.bufsize < 4096 {
 | 
			
		||||
		return fmt.Errorf("fsnotify.WithBufferSize: buffer size cannot be smaller than 4096 bytes")
 | 
			
		||||
	}
 | 
			
		||||
| 
						 | 
				
			
			@ -295,18 +141,14 @@ func (w *Watcher) AddWith(name string, opts ...addOpt) error {
 | 
			
		|||
	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].
 | 
			
		||||
//
 | 
			
		||||
// Returns nil if [Watcher.Close] was called.
 | 
			
		||||
func (w *Watcher) Remove(name string) error {
 | 
			
		||||
func (w *readDirChangesW) Remove(name string) error {
 | 
			
		||||
	if w.isClosed() {
 | 
			
		||||
		return nil
 | 
			
		||||
	}
 | 
			
		||||
	if debug {
 | 
			
		||||
		fmt.Fprintf(os.Stderr, "FSNOTIFY_DEBUG: %s  Remove(%q)\n",
 | 
			
		||||
			time.Now().Format("15:04:05.000000000"), filepath.ToSlash(name))
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	in := &input{
 | 
			
		||||
		op:    opRemoveWatch,
 | 
			
		||||
| 
						 | 
				
			
			@ -320,11 +162,7 @@ func (w *Watcher) Remove(name string) error {
 | 
			
		|||
	return <-in.reply
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// WatchList returns all paths explicitly added with [Watcher.Add] (and are not
 | 
			
		||||
// yet removed).
 | 
			
		||||
//
 | 
			
		||||
// Returns nil if [Watcher.Close] was called.
 | 
			
		||||
func (w *Watcher) WatchList() []string {
 | 
			
		||||
func (w *readDirChangesW) WatchList() []string {
 | 
			
		||||
	if w.isClosed() {
 | 
			
		||||
		return nil
 | 
			
		||||
	}
 | 
			
		||||
| 
						 | 
				
			
			@ -335,7 +173,13 @@ func (w *Watcher) WatchList() []string {
 | 
			
		|||
	entries := make([]string, 0, len(w.watches))
 | 
			
		||||
	for _, entry := range w.watches {
 | 
			
		||||
		for _, watchEntry := range entry {
 | 
			
		||||
			entries = append(entries, watchEntry.path)
 | 
			
		||||
			for name := range watchEntry.names {
 | 
			
		||||
				entries = append(entries, filepath.Join(watchEntry.path, name))
 | 
			
		||||
			}
 | 
			
		||||
			// the directory itself is being watched
 | 
			
		||||
			if watchEntry.mask != 0 {
 | 
			
		||||
				entries = append(entries, watchEntry.path)
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -361,7 +205,7 @@ const (
 | 
			
		|||
	sysFSIGNORED    = 0x8000
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
func (w *Watcher) newEvent(name string, mask uint32) Event {
 | 
			
		||||
func (w *readDirChangesW) newEvent(name string, mask uint32) Event {
 | 
			
		||||
	e := Event{Name: name}
 | 
			
		||||
	if mask&sysFSCREATE == sysFSCREATE || mask&sysFSMOVEDTO == sysFSMOVEDTO {
 | 
			
		||||
		e.Op |= Create
 | 
			
		||||
| 
						 | 
				
			
			@ -417,7 +261,7 @@ type (
 | 
			
		|||
	watchMap map[uint32]indexMap
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
func (w *Watcher) wakeupReader() error {
 | 
			
		||||
func (w *readDirChangesW) wakeupReader() error {
 | 
			
		||||
	err := windows.PostQueuedCompletionStatus(w.port, 0, 0, nil)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return os.NewSyscallError("PostQueuedCompletionStatus", err)
 | 
			
		||||
| 
						 | 
				
			
			@ -425,7 +269,7 @@ func (w *Watcher) wakeupReader() error {
 | 
			
		|||
	return nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (w *Watcher) getDir(pathname string) (dir string, err error) {
 | 
			
		||||
func (w *readDirChangesW) getDir(pathname string) (dir string, err error) {
 | 
			
		||||
	attr, err := windows.GetFileAttributes(windows.StringToUTF16Ptr(pathname))
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return "", os.NewSyscallError("GetFileAttributes", err)
 | 
			
		||||
| 
						 | 
				
			
			@ -439,7 +283,7 @@ func (w *Watcher) getDir(pathname string) (dir string, err error) {
 | 
			
		|||
	return
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (w *Watcher) getIno(path string) (ino *inode, err error) {
 | 
			
		||||
func (w *readDirChangesW) 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,
 | 
			
		||||
| 
						 | 
				
			
			@ -482,9 +326,8 @@ func (m watchMap) set(ino *inode, watch *watch) {
 | 
			
		|||
}
 | 
			
		||||
 | 
			
		||||
// Must run within the I/O thread.
 | 
			
		||||
func (w *Watcher) addWatch(pathname string, flags uint64, bufsize int) error {
 | 
			
		||||
	//pathname, recurse := recursivePath(pathname)
 | 
			
		||||
	recurse := false
 | 
			
		||||
func (w *readDirChangesW) addWatch(pathname string, flags uint64, bufsize int) error {
 | 
			
		||||
	pathname, recurse := recursivePath(pathname)
 | 
			
		||||
 | 
			
		||||
	dir, err := w.getDir(pathname)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
| 
						 | 
				
			
			@ -538,7 +381,7 @@ func (w *Watcher) addWatch(pathname string, flags uint64, bufsize int) error {
 | 
			
		|||
}
 | 
			
		||||
 | 
			
		||||
// Must run within the I/O thread.
 | 
			
		||||
func (w *Watcher) remWatch(pathname string) error {
 | 
			
		||||
func (w *readDirChangesW) remWatch(pathname string) error {
 | 
			
		||||
	pathname, recurse := recursivePath(pathname)
 | 
			
		||||
 | 
			
		||||
	dir, err := w.getDir(pathname)
 | 
			
		||||
| 
						 | 
				
			
			@ -566,11 +409,11 @@ func (w *Watcher) remWatch(pathname string) error {
 | 
			
		|||
		return fmt.Errorf("%w: %s", ErrNonExistentWatch, pathname)
 | 
			
		||||
	}
 | 
			
		||||
	if pathname == dir {
 | 
			
		||||
		w.sendEvent(watch.path, watch.mask&sysFSIGNORED)
 | 
			
		||||
		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)
 | 
			
		||||
		w.sendEvent(filepath.Join(watch.path, name), "", watch.names[name]&sysFSIGNORED)
 | 
			
		||||
		delete(watch.names, name)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -578,23 +421,23 @@ func (w *Watcher) remWatch(pathname string) error {
 | 
			
		|||
}
 | 
			
		||||
 | 
			
		||||
// Must run within the I/O thread.
 | 
			
		||||
func (w *Watcher) deleteWatch(watch *watch) {
 | 
			
		||||
func (w *readDirChangesW) deleteWatch(watch *watch) {
 | 
			
		||||
	for name, mask := range watch.names {
 | 
			
		||||
		if mask&provisional == 0 {
 | 
			
		||||
			w.sendEvent(filepath.Join(watch.path, name), mask&sysFSIGNORED)
 | 
			
		||||
			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)
 | 
			
		||||
			w.sendEvent(watch.path, "", watch.mask&sysFSIGNORED)
 | 
			
		||||
		}
 | 
			
		||||
		watch.mask = 0
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Must run within the I/O thread.
 | 
			
		||||
func (w *Watcher) startRead(watch *watch) error {
 | 
			
		||||
func (w *readDirChangesW) startRead(watch *watch) error {
 | 
			
		||||
	err := windows.CancelIo(watch.ino.handle)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		w.sendError(os.NewSyscallError("CancelIo", err))
 | 
			
		||||
| 
						 | 
				
			
			@ -624,7 +467,7 @@ func (w *Watcher) startRead(watch *watch) error {
 | 
			
		|||
		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)
 | 
			
		||||
			w.sendEvent(watch.path, "", watch.mask&sysFSDELETESELF)
 | 
			
		||||
			err = nil
 | 
			
		||||
		}
 | 
			
		||||
		w.deleteWatch(watch)
 | 
			
		||||
| 
						 | 
				
			
			@ -637,7 +480,7 @@ func (w *Watcher) startRead(watch *watch) error {
 | 
			
		|||
// 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() {
 | 
			
		||||
func (w *readDirChangesW) readEvents() {
 | 
			
		||||
	var (
 | 
			
		||||
		n   uint32
 | 
			
		||||
		key uintptr
 | 
			
		||||
| 
						 | 
				
			
			@ -700,7 +543,7 @@ func (w *Watcher) readEvents() {
 | 
			
		|||
			}
 | 
			
		||||
		case windows.ERROR_ACCESS_DENIED:
 | 
			
		||||
			// Watched directory was probably removed
 | 
			
		||||
			w.sendEvent(watch.path, watch.mask&sysFSDELETESELF)
 | 
			
		||||
			w.sendEvent(watch.path, "", watch.mask&sysFSDELETESELF)
 | 
			
		||||
			w.deleteWatch(watch)
 | 
			
		||||
			w.startRead(watch)
 | 
			
		||||
			continue
 | 
			
		||||
| 
						 | 
				
			
			@ -733,6 +576,10 @@ func (w *Watcher) readEvents() {
 | 
			
		|||
			name := windows.UTF16ToString(buf)
 | 
			
		||||
			fullname := filepath.Join(watch.path, name)
 | 
			
		||||
 | 
			
		||||
			if debug {
 | 
			
		||||
				internal.Debug(fullname, raw.Action)
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			var mask uint64
 | 
			
		||||
			switch raw.Action {
 | 
			
		||||
			case windows.FILE_ACTION_REMOVED:
 | 
			
		||||
| 
						 | 
				
			
			@ -761,21 +608,22 @@ func (w *Watcher) readEvents() {
 | 
			
		|||
				}
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			sendNameEvent := func() {
 | 
			
		||||
				w.sendEvent(fullname, watch.names[name]&mask)
 | 
			
		||||
			}
 | 
			
		||||
			if raw.Action != windows.FILE_ACTION_RENAMED_NEW_NAME {
 | 
			
		||||
				sendNameEvent()
 | 
			
		||||
				w.sendEvent(fullname, "", watch.names[name]&mask)
 | 
			
		||||
			}
 | 
			
		||||
			if raw.Action == windows.FILE_ACTION_REMOVED {
 | 
			
		||||
				w.sendEvent(fullname, watch.names[name]&sysFSIGNORED)
 | 
			
		||||
				w.sendEvent(fullname, "", watch.names[name]&sysFSIGNORED)
 | 
			
		||||
				delete(watch.names, name)
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			w.sendEvent(fullname, watch.mask&w.toFSnotifyFlags(raw.Action))
 | 
			
		||||
			if watch.rename != "" && raw.Action == windows.FILE_ACTION_RENAMED_NEW_NAME {
 | 
			
		||||
				w.sendEvent(fullname, filepath.Join(watch.path, watch.rename), watch.mask&w.toFSnotifyFlags(raw.Action))
 | 
			
		||||
			} else {
 | 
			
		||||
				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()
 | 
			
		||||
				w.sendEvent(filepath.Join(watch.path, watch.rename), "", watch.names[name]&mask)
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			// Move to the next event in the buffer
 | 
			
		||||
| 
						 | 
				
			
			@ -787,8 +635,7 @@ func (w *Watcher) readEvents() {
 | 
			
		|||
			// Error!
 | 
			
		||||
			if offset >= n {
 | 
			
		||||
				//lint:ignore ST1005 Windows should be capitalized
 | 
			
		||||
				w.sendError(errors.New(
 | 
			
		||||
					"Windows system assumed buffer larger than it is, events have likely been missed"))
 | 
			
		||||
				w.sendError(errors.New("Windows system assumed buffer larger than it is, events have likely been missed"))
 | 
			
		||||
				break
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
| 
						 | 
				
			
			@ -799,7 +646,7 @@ func (w *Watcher) readEvents() {
 | 
			
		|||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (w *Watcher) toWindowsFlags(mask uint64) uint32 {
 | 
			
		||||
func (w *readDirChangesW) toWindowsFlags(mask uint64) uint32 {
 | 
			
		||||
	var m uint32
 | 
			
		||||
	if mask&sysFSMODIFY != 0 {
 | 
			
		||||
		m |= windows.FILE_NOTIFY_CHANGE_LAST_WRITE
 | 
			
		||||
| 
						 | 
				
			
			@ -810,7 +657,7 @@ func (w *Watcher) toWindowsFlags(mask uint64) uint32 {
 | 
			
		|||
	return m
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (w *Watcher) toFSnotifyFlags(action uint32) uint64 {
 | 
			
		||||
func (w *readDirChangesW) toFSnotifyFlags(action uint32) uint64 {
 | 
			
		||||
	switch action {
 | 
			
		||||
	case windows.FILE_ACTION_ADDED:
 | 
			
		||||
		return sysFSCREATE
 | 
			
		||||
| 
						 | 
				
			
			@ -825,3 +672,11 @@ func (w *Watcher) toFSnotifyFlags(action uint32) uint64 {
 | 
			
		|||
	}
 | 
			
		||||
	return 0
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (w *readDirChangesW) xSupports(op Op) bool {
 | 
			
		||||
	if op.Has(xUnportableOpen) || op.Has(xUnportableRead) ||
 | 
			
		||||
		op.Has(xUnportableCloseWrite) || op.Has(xUnportableCloseRead) {
 | 
			
		||||
		return false
 | 
			
		||||
	}
 | 
			
		||||
	return true
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										368
									
								
								vendor/github.com/fsnotify/fsnotify/fsnotify.go
									
										
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										368
									
								
								vendor/github.com/fsnotify/fsnotify/fsnotify.go
									
										
									
										generated
									
									
										vendored
									
									
								
							| 
						 | 
				
			
			@ -3,19 +3,146 @@
 | 
			
		|||
//
 | 
			
		||||
// Currently supported systems:
 | 
			
		||||
//
 | 
			
		||||
//	Linux 2.6.32+    via inotify
 | 
			
		||||
//	BSD, macOS       via kqueue
 | 
			
		||||
//	Windows          via ReadDirectoryChangesW
 | 
			
		||||
//	illumos          via FEN
 | 
			
		||||
//   - Linux      via inotify
 | 
			
		||||
//   - BSD, macOS via kqueue
 | 
			
		||||
//   - Windows    via ReadDirectoryChangesW
 | 
			
		||||
//   - illumos    via FEN
 | 
			
		||||
//
 | 
			
		||||
// # FSNOTIFY_DEBUG
 | 
			
		||||
//
 | 
			
		||||
// Set the FSNOTIFY_DEBUG environment variable to "1" to print debug messages to
 | 
			
		||||
// stderr. This can be useful to track down some problems, especially in cases
 | 
			
		||||
// where fsnotify is used as an indirect dependency.
 | 
			
		||||
//
 | 
			
		||||
// Every event will be printed as soon as there's something useful to print,
 | 
			
		||||
// with as little processing from fsnotify.
 | 
			
		||||
//
 | 
			
		||||
// Example output:
 | 
			
		||||
//
 | 
			
		||||
//	FSNOTIFY_DEBUG: 11:34:23.633087586   256:IN_CREATE            → "/tmp/file-1"
 | 
			
		||||
//	FSNOTIFY_DEBUG: 11:34:23.633202319     4:IN_ATTRIB            → "/tmp/file-1"
 | 
			
		||||
//	FSNOTIFY_DEBUG: 11:34:28.989728764   512:IN_DELETE            → "/tmp/file-1"
 | 
			
		||||
package fsnotify
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"errors"
 | 
			
		||||
	"fmt"
 | 
			
		||||
	"os"
 | 
			
		||||
	"path/filepath"
 | 
			
		||||
	"strings"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
// 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.
 | 
			
		||||
//
 | 
			
		||||
// # Windows notes
 | 
			
		||||
//
 | 
			
		||||
// Paths can be added as "C:\\path\\to\\dir", but forward slashes
 | 
			
		||||
// ("C:/path/to/dir") will also work.
 | 
			
		||||
//
 | 
			
		||||
// When a watched directory is removed it will always send an event for the
 | 
			
		||||
// directory itself, but may not send events for all files in that directory.
 | 
			
		||||
// Sometimes it will send events for all files, sometimes it will send no
 | 
			
		||||
// events, and often only for some files.
 | 
			
		||||
//
 | 
			
		||||
// The default ReadDirectoryChangesW() buffer size is 64K, which is the largest
 | 
			
		||||
// value that is guaranteed to work with SMB filesystems. If you have many
 | 
			
		||||
// events in quick succession this may not be enough, and you will have to use
 | 
			
		||||
// [WithBufferSize] to increase the value.
 | 
			
		||||
type Watcher struct {
 | 
			
		||||
	b backend
 | 
			
		||||
 | 
			
		||||
	// 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, and you may
 | 
			
		||||
	//                      want to wait until you've stopped receiving them
 | 
			
		||||
	//                      (see the dedup example in cmd/fsnotify).
 | 
			
		||||
	//
 | 
			
		||||
	//                      Some systems may send Write event for directories
 | 
			
		||||
	//                      when the directory content changes.
 | 
			
		||||
	//
 | 
			
		||||
	//   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
 | 
			
		||||
	//                      when a file is truncated. On Windows it's never
 | 
			
		||||
	//                      sent.
 | 
			
		||||
	Events chan Event
 | 
			
		||||
 | 
			
		||||
	// Errors sends any errors.
 | 
			
		||||
	Errors chan error
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Event represents a file system notification.
 | 
			
		||||
type Event struct {
 | 
			
		||||
	// Path to the file or directory.
 | 
			
		||||
| 
						 | 
				
			
			@ -30,6 +157,16 @@ type Event struct {
 | 
			
		|||
	// This is a bitmask and some systems may send multiple operations at once.
 | 
			
		||||
	// Use the Event.Has() method instead of comparing with ==.
 | 
			
		||||
	Op Op
 | 
			
		||||
 | 
			
		||||
	// Create events will have this set to the old path if it's a rename. This
 | 
			
		||||
	// only works when both the source and destination are watched. It's not
 | 
			
		||||
	// reliable when watching individual files, only directories.
 | 
			
		||||
	//
 | 
			
		||||
	// For example "mv /tmp/file /tmp/rename" will emit:
 | 
			
		||||
	//
 | 
			
		||||
	//   Event{Op: Rename, Name: "/tmp/file"}
 | 
			
		||||
	//   Event{Op: Create, Name: "/tmp/rename", RenamedFrom: "/tmp/file"}
 | 
			
		||||
	renamedFrom string
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Op describes a set of file operations.
 | 
			
		||||
| 
						 | 
				
			
			@ -50,7 +187,7 @@ const (
 | 
			
		|||
	// example "remove to trash" is often a rename).
 | 
			
		||||
	Remove
 | 
			
		||||
 | 
			
		||||
	// The path was renamed to something else; any watched on it will be
 | 
			
		||||
	// The path was renamed to something else; any watches on it will be
 | 
			
		||||
	// removed.
 | 
			
		||||
	Rename
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -60,15 +197,155 @@ const (
 | 
			
		|||
	// get triggered very frequently by some software. For example, Spotlight
 | 
			
		||||
	// indexing on macOS, anti-virus software, backup software, etc.
 | 
			
		||||
	Chmod
 | 
			
		||||
 | 
			
		||||
	// File descriptor was opened.
 | 
			
		||||
	//
 | 
			
		||||
	// Only works on Linux and FreeBSD.
 | 
			
		||||
	xUnportableOpen
 | 
			
		||||
 | 
			
		||||
	// File was read from.
 | 
			
		||||
	//
 | 
			
		||||
	// Only works on Linux and FreeBSD.
 | 
			
		||||
	xUnportableRead
 | 
			
		||||
 | 
			
		||||
	// File opened for writing was closed.
 | 
			
		||||
	//
 | 
			
		||||
	// Only works on Linux and FreeBSD.
 | 
			
		||||
	//
 | 
			
		||||
	// The advantage of using this over Write is that it's more reliable than
 | 
			
		||||
	// waiting for Write events to stop. It's also faster (if you're not
 | 
			
		||||
	// listening to Write events): copying a file of a few GB can easily
 | 
			
		||||
	// generate tens of thousands of Write events in a short span of time.
 | 
			
		||||
	xUnportableCloseWrite
 | 
			
		||||
 | 
			
		||||
	// File opened for reading was closed.
 | 
			
		||||
	//
 | 
			
		||||
	// Only works on Linux and FreeBSD.
 | 
			
		||||
	xUnportableCloseRead
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
// Common errors that can be reported.
 | 
			
		||||
var (
 | 
			
		||||
	// ErrNonExistentWatch is used when Remove() is called on a path that's not
 | 
			
		||||
	// added.
 | 
			
		||||
	ErrNonExistentWatch = errors.New("fsnotify: can't remove non-existent watch")
 | 
			
		||||
	ErrEventOverflow    = errors.New("fsnotify: queue or buffer overflow")
 | 
			
		||||
	ErrClosed           = errors.New("fsnotify: watcher already closed")
 | 
			
		||||
 | 
			
		||||
	// ErrClosed is used when trying to operate on a closed Watcher.
 | 
			
		||||
	ErrClosed = errors.New("fsnotify: watcher already closed")
 | 
			
		||||
 | 
			
		||||
	// ErrEventOverflow is reported from the Errors channel when there are too
 | 
			
		||||
	// many events:
 | 
			
		||||
	//
 | 
			
		||||
	//  - inotify:      inotify returns IN_Q_OVERFLOW – because there are too
 | 
			
		||||
	//                  many queued events (the fs.inotify.max_queued_events
 | 
			
		||||
	//                  sysctl can be used to increase this).
 | 
			
		||||
	//  - windows:      The buffer size is too small; WithBufferSize() can be used to increase it.
 | 
			
		||||
	//  - kqueue, fen:  Not used.
 | 
			
		||||
	ErrEventOverflow = errors.New("fsnotify: queue or buffer overflow")
 | 
			
		||||
 | 
			
		||||
	// ErrUnsupported is returned by AddWith() when WithOps() specified an
 | 
			
		||||
	// Unportable event that's not supported on this platform.
 | 
			
		||||
	xErrUnsupported = errors.New("fsnotify: not supported with this backend")
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
// NewWatcher creates a new Watcher.
 | 
			
		||||
func NewWatcher() (*Watcher, error) {
 | 
			
		||||
	ev, errs := make(chan Event), make(chan error)
 | 
			
		||||
	b, err := newBackend(ev, errs)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return nil, err
 | 
			
		||||
	}
 | 
			
		||||
	return &Watcher{b: b, Events: ev, Errors: errs}, nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// NewBufferedWatcher creates a new Watcher with a buffered Watcher.Events
 | 
			
		||||
// channel.
 | 
			
		||||
//
 | 
			
		||||
// The main use case for this is situations with a very large number of events
 | 
			
		||||
// where the kernel buffer size can't be increased (e.g. due to lack of
 | 
			
		||||
// permissions). An unbuffered Watcher will perform better for almost all use
 | 
			
		||||
// cases, and whenever possible you will be better off increasing the kernel
 | 
			
		||||
// buffers instead of adding a large userspace buffer.
 | 
			
		||||
func NewBufferedWatcher(sz uint) (*Watcher, error) {
 | 
			
		||||
	ev, errs := make(chan Event), make(chan error)
 | 
			
		||||
	b, err := newBufferedBackend(sz, ev, errs)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return nil, err
 | 
			
		||||
	}
 | 
			
		||||
	return &Watcher{b: b, Events: ev, Errors: errs}, nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Add starts monitoring the path for changes.
 | 
			
		||||
//
 | 
			
		||||
// A path can only be watched once; watching it more than once is a no-op and will
 | 
			
		||||
// not return an error. Paths that do not yet exist on the filesystem cannot be
 | 
			
		||||
// watched.
 | 
			
		||||
//
 | 
			
		||||
// A watch will be automatically removed if the watched path is deleted or
 | 
			
		||||
// renamed. The exception is the Windows backend, which doesn't remove the
 | 
			
		||||
// watcher on renames.
 | 
			
		||||
//
 | 
			
		||||
// Notifications on network filesystems (NFS, SMB, FUSE, etc.) or special
 | 
			
		||||
// filesystems (/proc, /sys, etc.) generally don't work.
 | 
			
		||||
//
 | 
			
		||||
// Returns [ErrClosed] if [Watcher.Close] was called.
 | 
			
		||||
//
 | 
			
		||||
// See [Watcher.AddWith] for a version that allows adding options.
 | 
			
		||||
//
 | 
			
		||||
// # 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 programs (especially editors) update files atomically: it
 | 
			
		||||
// will write to a temporary file which is then moved to destination,
 | 
			
		||||
// overwriting the original (or some variant thereof). The watcher on the
 | 
			
		||||
// original file is now lost, as that no longer exists.
 | 
			
		||||
//
 | 
			
		||||
// The upshot of this is that a power failure or crash won't leave a
 | 
			
		||||
// half-written file.
 | 
			
		||||
//
 | 
			
		||||
// 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(path string) error { return w.b.Add(path) }
 | 
			
		||||
 | 
			
		||||
// AddWith is like [Watcher.Add], but allows adding options. When using Add()
 | 
			
		||||
// the defaults described below are used.
 | 
			
		||||
//
 | 
			
		||||
// Possible options are:
 | 
			
		||||
//
 | 
			
		||||
//   - [WithBufferSize] sets the buffer size for the Windows backend; no-op on
 | 
			
		||||
//     other platforms. The default is 64K (65536 bytes).
 | 
			
		||||
func (w *Watcher) AddWith(path string, opts ...addOpt) error { return w.b.AddWith(path, opts...) }
 | 
			
		||||
 | 
			
		||||
// 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].
 | 
			
		||||
//
 | 
			
		||||
// Returns nil if [Watcher.Close] was called.
 | 
			
		||||
func (w *Watcher) Remove(path string) error { return w.b.Remove(path) }
 | 
			
		||||
 | 
			
		||||
// Close removes all watches and closes the Events channel.
 | 
			
		||||
func (w *Watcher) Close() error { return w.b.Close() }
 | 
			
		||||
 | 
			
		||||
// WatchList returns all paths explicitly added with [Watcher.Add] (and are not
 | 
			
		||||
// yet removed).
 | 
			
		||||
//
 | 
			
		||||
// Returns nil if [Watcher.Close] was called.
 | 
			
		||||
func (w *Watcher) WatchList() []string { return w.b.WatchList() }
 | 
			
		||||
 | 
			
		||||
// Supports reports if all the listed operations are supported by this platform.
 | 
			
		||||
//
 | 
			
		||||
// Create, Write, Remove, Rename, and Chmod are always supported. It can only
 | 
			
		||||
// return false for an Op starting with Unportable.
 | 
			
		||||
func (w *Watcher) xSupports(op Op) bool { return w.b.xSupports(op) }
 | 
			
		||||
 | 
			
		||||
func (o Op) String() string {
 | 
			
		||||
	var b strings.Builder
 | 
			
		||||
	if o.Has(Create) {
 | 
			
		||||
| 
						 | 
				
			
			@ -80,6 +357,18 @@ func (o Op) String() string {
 | 
			
		|||
	if o.Has(Write) {
 | 
			
		||||
		b.WriteString("|WRITE")
 | 
			
		||||
	}
 | 
			
		||||
	if o.Has(xUnportableOpen) {
 | 
			
		||||
		b.WriteString("|OPEN")
 | 
			
		||||
	}
 | 
			
		||||
	if o.Has(xUnportableRead) {
 | 
			
		||||
		b.WriteString("|READ")
 | 
			
		||||
	}
 | 
			
		||||
	if o.Has(xUnportableCloseWrite) {
 | 
			
		||||
		b.WriteString("|CLOSE_WRITE")
 | 
			
		||||
	}
 | 
			
		||||
	if o.Has(xUnportableCloseRead) {
 | 
			
		||||
		b.WriteString("|CLOSE_READ")
 | 
			
		||||
	}
 | 
			
		||||
	if o.Has(Rename) {
 | 
			
		||||
		b.WriteString("|RENAME")
 | 
			
		||||
	}
 | 
			
		||||
| 
						 | 
				
			
			@ -100,24 +389,48 @@ 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 {
 | 
			
		||||
	if e.renamedFrom != "" {
 | 
			
		||||
		return fmt.Sprintf("%-13s %q ← %q", e.Op.String(), e.Name, e.renamedFrom)
 | 
			
		||||
	}
 | 
			
		||||
	return fmt.Sprintf("%-13s %q", e.Op.String(), e.Name)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type (
 | 
			
		||||
	backend interface {
 | 
			
		||||
		Add(string) error
 | 
			
		||||
		AddWith(string, ...addOpt) error
 | 
			
		||||
		Remove(string) error
 | 
			
		||||
		WatchList() []string
 | 
			
		||||
		Close() error
 | 
			
		||||
		xSupports(Op) bool
 | 
			
		||||
	}
 | 
			
		||||
	addOpt   func(opt *withOpts)
 | 
			
		||||
	withOpts struct {
 | 
			
		||||
		bufsize int
 | 
			
		||||
		bufsize    int
 | 
			
		||||
		op         Op
 | 
			
		||||
		noFollow   bool
 | 
			
		||||
		sendCreate bool
 | 
			
		||||
	}
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
var debug = func() bool {
 | 
			
		||||
	// Check for exactly "1" (rather than mere existence) so we can add
 | 
			
		||||
	// options/flags in the future. I don't know if we ever want that, but it's
 | 
			
		||||
	// nice to leave the option open.
 | 
			
		||||
	return os.Getenv("FSNOTIFY_DEBUG") == "1"
 | 
			
		||||
}()
 | 
			
		||||
 | 
			
		||||
var defaultOpts = withOpts{
 | 
			
		||||
	bufsize: 65536, // 64K
 | 
			
		||||
	op:      Create | Write | Remove | Rename | Chmod,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func getOptions(opts ...addOpt) withOpts {
 | 
			
		||||
	with := defaultOpts
 | 
			
		||||
	for _, o := range opts {
 | 
			
		||||
		o(&with)
 | 
			
		||||
		if o != nil {
 | 
			
		||||
			o(&with)
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	return with
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -136,9 +449,44 @@ func WithBufferSize(bytes int) addOpt {
 | 
			
		|||
	return func(opt *withOpts) { opt.bufsize = bytes }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// WithOps sets which operations to listen for. The default is [Create],
 | 
			
		||||
// [Write], [Remove], [Rename], and [Chmod].
 | 
			
		||||
//
 | 
			
		||||
// Excluding operations you're not interested in can save quite a bit of CPU
 | 
			
		||||
// time; in some use cases there may be hundreds of thousands of useless Write
 | 
			
		||||
// or Chmod operations per second.
 | 
			
		||||
//
 | 
			
		||||
// This can also be used to add unportable operations not supported by all
 | 
			
		||||
// platforms; unportable operations all start with "Unportable":
 | 
			
		||||
// [UnportableOpen], [UnportableRead], [UnportableCloseWrite], and
 | 
			
		||||
// [UnportableCloseRead].
 | 
			
		||||
//
 | 
			
		||||
// AddWith returns an error when using an unportable operation that's not
 | 
			
		||||
// supported. Use [Watcher.Support] to check for support.
 | 
			
		||||
func withOps(op Op) addOpt {
 | 
			
		||||
	return func(opt *withOpts) { opt.op = op }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// WithNoFollow disables following symlinks, so the symlinks themselves are
 | 
			
		||||
// watched.
 | 
			
		||||
func withNoFollow() addOpt {
 | 
			
		||||
	return func(opt *withOpts) { opt.noFollow = true }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// "Internal" option for recursive watches on inotify.
 | 
			
		||||
func withCreate() addOpt {
 | 
			
		||||
	return func(opt *withOpts) { opt.sendCreate = true }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
var enableRecurse = false
 | 
			
		||||
 | 
			
		||||
// Check if this path is recursive (ends with "/..." or "\..."), and return the
 | 
			
		||||
// path with the /... stripped.
 | 
			
		||||
func recursivePath(path string) (string, bool) {
 | 
			
		||||
	path = filepath.Clean(path)
 | 
			
		||||
	if !enableRecurse { // Only enabled in tests for now.
 | 
			
		||||
		return path, false
 | 
			
		||||
	}
 | 
			
		||||
	if filepath.Base(path) == "..." {
 | 
			
		||||
		return filepath.Dir(path), true
 | 
			
		||||
	}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										39
									
								
								vendor/github.com/fsnotify/fsnotify/internal/darwin.go
									
										
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										39
									
								
								vendor/github.com/fsnotify/fsnotify/internal/darwin.go
									
										
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,39 @@
 | 
			
		|||
//go:build darwin
 | 
			
		||||
 | 
			
		||||
package internal
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"syscall"
 | 
			
		||||
 | 
			
		||||
	"golang.org/x/sys/unix"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
var (
 | 
			
		||||
	SyscallEACCES = syscall.EACCES
 | 
			
		||||
	UnixEACCES    = unix.EACCES
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
var maxfiles uint64
 | 
			
		||||
 | 
			
		||||
// Go 1.19 will do this automatically: https://go-review.googlesource.com/c/go/+/393354/
 | 
			
		||||
func SetRlimit() {
 | 
			
		||||
	var l syscall.Rlimit
 | 
			
		||||
	err := syscall.Getrlimit(syscall.RLIMIT_NOFILE, &l)
 | 
			
		||||
	if err == nil && l.Cur != l.Max {
 | 
			
		||||
		l.Cur = l.Max
 | 
			
		||||
		syscall.Setrlimit(syscall.RLIMIT_NOFILE, &l)
 | 
			
		||||
	}
 | 
			
		||||
	maxfiles = l.Cur
 | 
			
		||||
 | 
			
		||||
	if n, err := syscall.SysctlUint32("kern.maxfiles"); err == nil && uint64(n) < maxfiles {
 | 
			
		||||
		maxfiles = uint64(n)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if n, err := syscall.SysctlUint32("kern.maxfilesperproc"); err == nil && uint64(n) < maxfiles {
 | 
			
		||||
		maxfiles = uint64(n)
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func Maxfiles() uint64                              { return maxfiles }
 | 
			
		||||
func Mkfifo(path string, mode uint32) error         { return unix.Mkfifo(path, mode) }
 | 
			
		||||
func Mknod(path string, mode uint32, dev int) error { return unix.Mknod(path, mode, dev) }
 | 
			
		||||
							
								
								
									
										57
									
								
								vendor/github.com/fsnotify/fsnotify/internal/debug_darwin.go
									
										
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										57
									
								
								vendor/github.com/fsnotify/fsnotify/internal/debug_darwin.go
									
										
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,57 @@
 | 
			
		|||
package internal
 | 
			
		||||
 | 
			
		||||
import "golang.org/x/sys/unix"
 | 
			
		||||
 | 
			
		||||
var names = []struct {
 | 
			
		||||
	n string
 | 
			
		||||
	m uint32
 | 
			
		||||
}{
 | 
			
		||||
	{"NOTE_ABSOLUTE", unix.NOTE_ABSOLUTE},
 | 
			
		||||
	{"NOTE_ATTRIB", unix.NOTE_ATTRIB},
 | 
			
		||||
	{"NOTE_BACKGROUND", unix.NOTE_BACKGROUND},
 | 
			
		||||
	{"NOTE_CHILD", unix.NOTE_CHILD},
 | 
			
		||||
	{"NOTE_CRITICAL", unix.NOTE_CRITICAL},
 | 
			
		||||
	{"NOTE_DELETE", unix.NOTE_DELETE},
 | 
			
		||||
	{"NOTE_EXEC", unix.NOTE_EXEC},
 | 
			
		||||
	{"NOTE_EXIT", unix.NOTE_EXIT},
 | 
			
		||||
	{"NOTE_EXITSTATUS", unix.NOTE_EXITSTATUS},
 | 
			
		||||
	{"NOTE_EXIT_CSERROR", unix.NOTE_EXIT_CSERROR},
 | 
			
		||||
	{"NOTE_EXIT_DECRYPTFAIL", unix.NOTE_EXIT_DECRYPTFAIL},
 | 
			
		||||
	{"NOTE_EXIT_DETAIL", unix.NOTE_EXIT_DETAIL},
 | 
			
		||||
	{"NOTE_EXIT_DETAIL_MASK", unix.NOTE_EXIT_DETAIL_MASK},
 | 
			
		||||
	{"NOTE_EXIT_MEMORY", unix.NOTE_EXIT_MEMORY},
 | 
			
		||||
	{"NOTE_EXIT_REPARENTED", unix.NOTE_EXIT_REPARENTED},
 | 
			
		||||
	{"NOTE_EXTEND", unix.NOTE_EXTEND},
 | 
			
		||||
	{"NOTE_FFAND", unix.NOTE_FFAND},
 | 
			
		||||
	{"NOTE_FFCOPY", unix.NOTE_FFCOPY},
 | 
			
		||||
	{"NOTE_FFCTRLMASK", unix.NOTE_FFCTRLMASK},
 | 
			
		||||
	{"NOTE_FFLAGSMASK", unix.NOTE_FFLAGSMASK},
 | 
			
		||||
	{"NOTE_FFNOP", unix.NOTE_FFNOP},
 | 
			
		||||
	{"NOTE_FFOR", unix.NOTE_FFOR},
 | 
			
		||||
	{"NOTE_FORK", unix.NOTE_FORK},
 | 
			
		||||
	{"NOTE_FUNLOCK", unix.NOTE_FUNLOCK},
 | 
			
		||||
	{"NOTE_LEEWAY", unix.NOTE_LEEWAY},
 | 
			
		||||
	{"NOTE_LINK", unix.NOTE_LINK},
 | 
			
		||||
	{"NOTE_LOWAT", unix.NOTE_LOWAT},
 | 
			
		||||
	{"NOTE_MACHTIME", unix.NOTE_MACHTIME},
 | 
			
		||||
	{"NOTE_MACH_CONTINUOUS_TIME", unix.NOTE_MACH_CONTINUOUS_TIME},
 | 
			
		||||
	{"NOTE_NONE", unix.NOTE_NONE},
 | 
			
		||||
	{"NOTE_NSECONDS", unix.NOTE_NSECONDS},
 | 
			
		||||
	{"NOTE_OOB", unix.NOTE_OOB},
 | 
			
		||||
	//{"NOTE_PCTRLMASK", unix.NOTE_PCTRLMASK}, -0x100000 (?!)
 | 
			
		||||
	{"NOTE_PDATAMASK", unix.NOTE_PDATAMASK},
 | 
			
		||||
	{"NOTE_REAP", unix.NOTE_REAP},
 | 
			
		||||
	{"NOTE_RENAME", unix.NOTE_RENAME},
 | 
			
		||||
	{"NOTE_REVOKE", unix.NOTE_REVOKE},
 | 
			
		||||
	{"NOTE_SECONDS", unix.NOTE_SECONDS},
 | 
			
		||||
	{"NOTE_SIGNAL", unix.NOTE_SIGNAL},
 | 
			
		||||
	{"NOTE_TRACK", unix.NOTE_TRACK},
 | 
			
		||||
	{"NOTE_TRACKERR", unix.NOTE_TRACKERR},
 | 
			
		||||
	{"NOTE_TRIGGER", unix.NOTE_TRIGGER},
 | 
			
		||||
	{"NOTE_USECONDS", unix.NOTE_USECONDS},
 | 
			
		||||
	{"NOTE_VM_ERROR", unix.NOTE_VM_ERROR},
 | 
			
		||||
	{"NOTE_VM_PRESSURE", unix.NOTE_VM_PRESSURE},
 | 
			
		||||
	{"NOTE_VM_PRESSURE_SUDDEN_TERMINATE", unix.NOTE_VM_PRESSURE_SUDDEN_TERMINATE},
 | 
			
		||||
	{"NOTE_VM_PRESSURE_TERMINATE", unix.NOTE_VM_PRESSURE_TERMINATE},
 | 
			
		||||
	{"NOTE_WRITE", unix.NOTE_WRITE},
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										33
									
								
								vendor/github.com/fsnotify/fsnotify/internal/debug_dragonfly.go
									
										
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										33
									
								
								vendor/github.com/fsnotify/fsnotify/internal/debug_dragonfly.go
									
										
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,33 @@
 | 
			
		|||
package internal
 | 
			
		||||
 | 
			
		||||
import "golang.org/x/sys/unix"
 | 
			
		||||
 | 
			
		||||
var names = []struct {
 | 
			
		||||
	n string
 | 
			
		||||
	m uint32
 | 
			
		||||
}{
 | 
			
		||||
	{"NOTE_ATTRIB", unix.NOTE_ATTRIB},
 | 
			
		||||
	{"NOTE_CHILD", unix.NOTE_CHILD},
 | 
			
		||||
	{"NOTE_DELETE", unix.NOTE_DELETE},
 | 
			
		||||
	{"NOTE_EXEC", unix.NOTE_EXEC},
 | 
			
		||||
	{"NOTE_EXIT", unix.NOTE_EXIT},
 | 
			
		||||
	{"NOTE_EXTEND", unix.NOTE_EXTEND},
 | 
			
		||||
	{"NOTE_FFAND", unix.NOTE_FFAND},
 | 
			
		||||
	{"NOTE_FFCOPY", unix.NOTE_FFCOPY},
 | 
			
		||||
	{"NOTE_FFCTRLMASK", unix.NOTE_FFCTRLMASK},
 | 
			
		||||
	{"NOTE_FFLAGSMASK", unix.NOTE_FFLAGSMASK},
 | 
			
		||||
	{"NOTE_FFNOP", unix.NOTE_FFNOP},
 | 
			
		||||
	{"NOTE_FFOR", unix.NOTE_FFOR},
 | 
			
		||||
	{"NOTE_FORK", unix.NOTE_FORK},
 | 
			
		||||
	{"NOTE_LINK", unix.NOTE_LINK},
 | 
			
		||||
	{"NOTE_LOWAT", unix.NOTE_LOWAT},
 | 
			
		||||
	{"NOTE_OOB", unix.NOTE_OOB},
 | 
			
		||||
	{"NOTE_PCTRLMASK", unix.NOTE_PCTRLMASK},
 | 
			
		||||
	{"NOTE_PDATAMASK", unix.NOTE_PDATAMASK},
 | 
			
		||||
	{"NOTE_RENAME", unix.NOTE_RENAME},
 | 
			
		||||
	{"NOTE_REVOKE", unix.NOTE_REVOKE},
 | 
			
		||||
	{"NOTE_TRACK", unix.NOTE_TRACK},
 | 
			
		||||
	{"NOTE_TRACKERR", unix.NOTE_TRACKERR},
 | 
			
		||||
	{"NOTE_TRIGGER", unix.NOTE_TRIGGER},
 | 
			
		||||
	{"NOTE_WRITE", unix.NOTE_WRITE},
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										42
									
								
								vendor/github.com/fsnotify/fsnotify/internal/debug_freebsd.go
									
										
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										42
									
								
								vendor/github.com/fsnotify/fsnotify/internal/debug_freebsd.go
									
										
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,42 @@
 | 
			
		|||
package internal
 | 
			
		||||
 | 
			
		||||
import "golang.org/x/sys/unix"
 | 
			
		||||
 | 
			
		||||
var names = []struct {
 | 
			
		||||
	n string
 | 
			
		||||
	m uint32
 | 
			
		||||
}{
 | 
			
		||||
	{"NOTE_ABSTIME", unix.NOTE_ABSTIME},
 | 
			
		||||
	{"NOTE_ATTRIB", unix.NOTE_ATTRIB},
 | 
			
		||||
	{"NOTE_CHILD", unix.NOTE_CHILD},
 | 
			
		||||
	{"NOTE_CLOSE", unix.NOTE_CLOSE},
 | 
			
		||||
	{"NOTE_CLOSE_WRITE", unix.NOTE_CLOSE_WRITE},
 | 
			
		||||
	{"NOTE_DELETE", unix.NOTE_DELETE},
 | 
			
		||||
	{"NOTE_EXEC", unix.NOTE_EXEC},
 | 
			
		||||
	{"NOTE_EXIT", unix.NOTE_EXIT},
 | 
			
		||||
	{"NOTE_EXTEND", unix.NOTE_EXTEND},
 | 
			
		||||
	{"NOTE_FFAND", unix.NOTE_FFAND},
 | 
			
		||||
	{"NOTE_FFCOPY", unix.NOTE_FFCOPY},
 | 
			
		||||
	{"NOTE_FFCTRLMASK", unix.NOTE_FFCTRLMASK},
 | 
			
		||||
	{"NOTE_FFLAGSMASK", unix.NOTE_FFLAGSMASK},
 | 
			
		||||
	{"NOTE_FFNOP", unix.NOTE_FFNOP},
 | 
			
		||||
	{"NOTE_FFOR", unix.NOTE_FFOR},
 | 
			
		||||
	{"NOTE_FILE_POLL", unix.NOTE_FILE_POLL},
 | 
			
		||||
	{"NOTE_FORK", unix.NOTE_FORK},
 | 
			
		||||
	{"NOTE_LINK", unix.NOTE_LINK},
 | 
			
		||||
	{"NOTE_LOWAT", unix.NOTE_LOWAT},
 | 
			
		||||
	{"NOTE_MSECONDS", unix.NOTE_MSECONDS},
 | 
			
		||||
	{"NOTE_NSECONDS", unix.NOTE_NSECONDS},
 | 
			
		||||
	{"NOTE_OPEN", unix.NOTE_OPEN},
 | 
			
		||||
	{"NOTE_PCTRLMASK", unix.NOTE_PCTRLMASK},
 | 
			
		||||
	{"NOTE_PDATAMASK", unix.NOTE_PDATAMASK},
 | 
			
		||||
	{"NOTE_READ", unix.NOTE_READ},
 | 
			
		||||
	{"NOTE_RENAME", unix.NOTE_RENAME},
 | 
			
		||||
	{"NOTE_REVOKE", unix.NOTE_REVOKE},
 | 
			
		||||
	{"NOTE_SECONDS", unix.NOTE_SECONDS},
 | 
			
		||||
	{"NOTE_TRACK", unix.NOTE_TRACK},
 | 
			
		||||
	{"NOTE_TRACKERR", unix.NOTE_TRACKERR},
 | 
			
		||||
	{"NOTE_TRIGGER", unix.NOTE_TRIGGER},
 | 
			
		||||
	{"NOTE_USECONDS", unix.NOTE_USECONDS},
 | 
			
		||||
	{"NOTE_WRITE", unix.NOTE_WRITE},
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										32
									
								
								vendor/github.com/fsnotify/fsnotify/internal/debug_kqueue.go
									
										
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										32
									
								
								vendor/github.com/fsnotify/fsnotify/internal/debug_kqueue.go
									
										
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,32 @@
 | 
			
		|||
//go:build freebsd || openbsd || netbsd || dragonfly || darwin
 | 
			
		||||
 | 
			
		||||
package internal
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"fmt"
 | 
			
		||||
	"os"
 | 
			
		||||
	"strings"
 | 
			
		||||
	"time"
 | 
			
		||||
 | 
			
		||||
	"golang.org/x/sys/unix"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
func Debug(name string, kevent *unix.Kevent_t) {
 | 
			
		||||
	mask := uint32(kevent.Fflags)
 | 
			
		||||
 | 
			
		||||
	var (
 | 
			
		||||
		l       []string
 | 
			
		||||
		unknown = mask
 | 
			
		||||
	)
 | 
			
		||||
	for _, n := range names {
 | 
			
		||||
		if mask&n.m == n.m {
 | 
			
		||||
			l = append(l, n.n)
 | 
			
		||||
			unknown ^= n.m
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	if unknown > 0 {
 | 
			
		||||
		l = append(l, fmt.Sprintf("0x%x", unknown))
 | 
			
		||||
	}
 | 
			
		||||
	fmt.Fprintf(os.Stderr, "FSNOTIFY_DEBUG: %s  %10d:%-60s → %q\n",
 | 
			
		||||
		time.Now().Format("15:04:05.000000000"), mask, strings.Join(l, " | "), name)
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										56
									
								
								vendor/github.com/fsnotify/fsnotify/internal/debug_linux.go
									
										
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										56
									
								
								vendor/github.com/fsnotify/fsnotify/internal/debug_linux.go
									
										
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,56 @@
 | 
			
		|||
package internal
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"fmt"
 | 
			
		||||
	"os"
 | 
			
		||||
	"strings"
 | 
			
		||||
	"time"
 | 
			
		||||
 | 
			
		||||
	"golang.org/x/sys/unix"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
func Debug(name string, mask, cookie uint32) {
 | 
			
		||||
	names := []struct {
 | 
			
		||||
		n string
 | 
			
		||||
		m uint32
 | 
			
		||||
	}{
 | 
			
		||||
		{"IN_ACCESS", unix.IN_ACCESS},
 | 
			
		||||
		{"IN_ATTRIB", unix.IN_ATTRIB},
 | 
			
		||||
		{"IN_CLOSE", unix.IN_CLOSE},
 | 
			
		||||
		{"IN_CLOSE_NOWRITE", unix.IN_CLOSE_NOWRITE},
 | 
			
		||||
		{"IN_CLOSE_WRITE", unix.IN_CLOSE_WRITE},
 | 
			
		||||
		{"IN_CREATE", unix.IN_CREATE},
 | 
			
		||||
		{"IN_DELETE", unix.IN_DELETE},
 | 
			
		||||
		{"IN_DELETE_SELF", unix.IN_DELETE_SELF},
 | 
			
		||||
		{"IN_IGNORED", unix.IN_IGNORED},
 | 
			
		||||
		{"IN_ISDIR", unix.IN_ISDIR},
 | 
			
		||||
		{"IN_MODIFY", unix.IN_MODIFY},
 | 
			
		||||
		{"IN_MOVE", unix.IN_MOVE},
 | 
			
		||||
		{"IN_MOVED_FROM", unix.IN_MOVED_FROM},
 | 
			
		||||
		{"IN_MOVED_TO", unix.IN_MOVED_TO},
 | 
			
		||||
		{"IN_MOVE_SELF", unix.IN_MOVE_SELF},
 | 
			
		||||
		{"IN_OPEN", unix.IN_OPEN},
 | 
			
		||||
		{"IN_Q_OVERFLOW", unix.IN_Q_OVERFLOW},
 | 
			
		||||
		{"IN_UNMOUNT", unix.IN_UNMOUNT},
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	var (
 | 
			
		||||
		l       []string
 | 
			
		||||
		unknown = mask
 | 
			
		||||
	)
 | 
			
		||||
	for _, n := range names {
 | 
			
		||||
		if mask&n.m == n.m {
 | 
			
		||||
			l = append(l, n.n)
 | 
			
		||||
			unknown ^= n.m
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	if unknown > 0 {
 | 
			
		||||
		l = append(l, fmt.Sprintf("0x%x", unknown))
 | 
			
		||||
	}
 | 
			
		||||
	var c string
 | 
			
		||||
	if cookie > 0 {
 | 
			
		||||
		c = fmt.Sprintf("(cookie: %d) ", cookie)
 | 
			
		||||
	}
 | 
			
		||||
	fmt.Fprintf(os.Stderr, "FSNOTIFY_DEBUG: %s  %-30s → %s%q\n",
 | 
			
		||||
		time.Now().Format("15:04:05.000000000"), strings.Join(l, "|"), c, name)
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										25
									
								
								vendor/github.com/fsnotify/fsnotify/internal/debug_netbsd.go
									
										
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										25
									
								
								vendor/github.com/fsnotify/fsnotify/internal/debug_netbsd.go
									
										
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,25 @@
 | 
			
		|||
package internal
 | 
			
		||||
 | 
			
		||||
import "golang.org/x/sys/unix"
 | 
			
		||||
 | 
			
		||||
var names = []struct {
 | 
			
		||||
	n string
 | 
			
		||||
	m uint32
 | 
			
		||||
}{
 | 
			
		||||
	{"NOTE_ATTRIB", unix.NOTE_ATTRIB},
 | 
			
		||||
	{"NOTE_CHILD", unix.NOTE_CHILD},
 | 
			
		||||
	{"NOTE_DELETE", unix.NOTE_DELETE},
 | 
			
		||||
	{"NOTE_EXEC", unix.NOTE_EXEC},
 | 
			
		||||
	{"NOTE_EXIT", unix.NOTE_EXIT},
 | 
			
		||||
	{"NOTE_EXTEND", unix.NOTE_EXTEND},
 | 
			
		||||
	{"NOTE_FORK", unix.NOTE_FORK},
 | 
			
		||||
	{"NOTE_LINK", unix.NOTE_LINK},
 | 
			
		||||
	{"NOTE_LOWAT", unix.NOTE_LOWAT},
 | 
			
		||||
	{"NOTE_PCTRLMASK", unix.NOTE_PCTRLMASK},
 | 
			
		||||
	{"NOTE_PDATAMASK", unix.NOTE_PDATAMASK},
 | 
			
		||||
	{"NOTE_RENAME", unix.NOTE_RENAME},
 | 
			
		||||
	{"NOTE_REVOKE", unix.NOTE_REVOKE},
 | 
			
		||||
	{"NOTE_TRACK", unix.NOTE_TRACK},
 | 
			
		||||
	{"NOTE_TRACKERR", unix.NOTE_TRACKERR},
 | 
			
		||||
	{"NOTE_WRITE", unix.NOTE_WRITE},
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										28
									
								
								vendor/github.com/fsnotify/fsnotify/internal/debug_openbsd.go
									
										
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										28
									
								
								vendor/github.com/fsnotify/fsnotify/internal/debug_openbsd.go
									
										
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,28 @@
 | 
			
		|||
package internal
 | 
			
		||||
 | 
			
		||||
import "golang.org/x/sys/unix"
 | 
			
		||||
 | 
			
		||||
var names = []struct {
 | 
			
		||||
	n string
 | 
			
		||||
	m uint32
 | 
			
		||||
}{
 | 
			
		||||
	{"NOTE_ATTRIB", unix.NOTE_ATTRIB},
 | 
			
		||||
	// {"NOTE_CHANGE", unix.NOTE_CHANGE}, // Not on 386?
 | 
			
		||||
	{"NOTE_CHILD", unix.NOTE_CHILD},
 | 
			
		||||
	{"NOTE_DELETE", unix.NOTE_DELETE},
 | 
			
		||||
	{"NOTE_EOF", unix.NOTE_EOF},
 | 
			
		||||
	{"NOTE_EXEC", unix.NOTE_EXEC},
 | 
			
		||||
	{"NOTE_EXIT", unix.NOTE_EXIT},
 | 
			
		||||
	{"NOTE_EXTEND", unix.NOTE_EXTEND},
 | 
			
		||||
	{"NOTE_FORK", unix.NOTE_FORK},
 | 
			
		||||
	{"NOTE_LINK", unix.NOTE_LINK},
 | 
			
		||||
	{"NOTE_LOWAT", unix.NOTE_LOWAT},
 | 
			
		||||
	{"NOTE_PCTRLMASK", unix.NOTE_PCTRLMASK},
 | 
			
		||||
	{"NOTE_PDATAMASK", unix.NOTE_PDATAMASK},
 | 
			
		||||
	{"NOTE_RENAME", unix.NOTE_RENAME},
 | 
			
		||||
	{"NOTE_REVOKE", unix.NOTE_REVOKE},
 | 
			
		||||
	{"NOTE_TRACK", unix.NOTE_TRACK},
 | 
			
		||||
	{"NOTE_TRACKERR", unix.NOTE_TRACKERR},
 | 
			
		||||
	{"NOTE_TRUNCATE", unix.NOTE_TRUNCATE},
 | 
			
		||||
	{"NOTE_WRITE", unix.NOTE_WRITE},
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										45
									
								
								vendor/github.com/fsnotify/fsnotify/internal/debug_solaris.go
									
										
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										45
									
								
								vendor/github.com/fsnotify/fsnotify/internal/debug_solaris.go
									
										
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,45 @@
 | 
			
		|||
package internal
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"fmt"
 | 
			
		||||
	"os"
 | 
			
		||||
	"strings"
 | 
			
		||||
	"time"
 | 
			
		||||
 | 
			
		||||
	"golang.org/x/sys/unix"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
func Debug(name string, mask int32) {
 | 
			
		||||
	names := []struct {
 | 
			
		||||
		n string
 | 
			
		||||
		m int32
 | 
			
		||||
	}{
 | 
			
		||||
		{"FILE_ACCESS", unix.FILE_ACCESS},
 | 
			
		||||
		{"FILE_MODIFIED", unix.FILE_MODIFIED},
 | 
			
		||||
		{"FILE_ATTRIB", unix.FILE_ATTRIB},
 | 
			
		||||
		{"FILE_TRUNC", unix.FILE_TRUNC},
 | 
			
		||||
		{"FILE_NOFOLLOW", unix.FILE_NOFOLLOW},
 | 
			
		||||
		{"FILE_DELETE", unix.FILE_DELETE},
 | 
			
		||||
		{"FILE_RENAME_TO", unix.FILE_RENAME_TO},
 | 
			
		||||
		{"FILE_RENAME_FROM", unix.FILE_RENAME_FROM},
 | 
			
		||||
		{"UNMOUNTED", unix.UNMOUNTED},
 | 
			
		||||
		{"MOUNTEDOVER", unix.MOUNTEDOVER},
 | 
			
		||||
		{"FILE_EXCEPTION", unix.FILE_EXCEPTION},
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	var (
 | 
			
		||||
		l       []string
 | 
			
		||||
		unknown = mask
 | 
			
		||||
	)
 | 
			
		||||
	for _, n := range names {
 | 
			
		||||
		if mask&n.m == n.m {
 | 
			
		||||
			l = append(l, n.n)
 | 
			
		||||
			unknown ^= n.m
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	if unknown > 0 {
 | 
			
		||||
		l = append(l, fmt.Sprintf("0x%x", unknown))
 | 
			
		||||
	}
 | 
			
		||||
	fmt.Fprintf(os.Stderr, "FSNOTIFY_DEBUG: %s  %10d:%-30s → %q\n",
 | 
			
		||||
		time.Now().Format("15:04:05.000000000"), mask, strings.Join(l, " | "), name)
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										40
									
								
								vendor/github.com/fsnotify/fsnotify/internal/debug_windows.go
									
										
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										40
									
								
								vendor/github.com/fsnotify/fsnotify/internal/debug_windows.go
									
										
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,40 @@
 | 
			
		|||
package internal
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"fmt"
 | 
			
		||||
	"os"
 | 
			
		||||
	"path/filepath"
 | 
			
		||||
	"strings"
 | 
			
		||||
	"time"
 | 
			
		||||
 | 
			
		||||
	"golang.org/x/sys/windows"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
func Debug(name string, mask uint32) {
 | 
			
		||||
	names := []struct {
 | 
			
		||||
		n string
 | 
			
		||||
		m uint32
 | 
			
		||||
	}{
 | 
			
		||||
		{"FILE_ACTION_ADDED", windows.FILE_ACTION_ADDED},
 | 
			
		||||
		{"FILE_ACTION_REMOVED", windows.FILE_ACTION_REMOVED},
 | 
			
		||||
		{"FILE_ACTION_MODIFIED", windows.FILE_ACTION_MODIFIED},
 | 
			
		||||
		{"FILE_ACTION_RENAMED_OLD_NAME", windows.FILE_ACTION_RENAMED_OLD_NAME},
 | 
			
		||||
		{"FILE_ACTION_RENAMED_NEW_NAME", windows.FILE_ACTION_RENAMED_NEW_NAME},
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	var (
 | 
			
		||||
		l       []string
 | 
			
		||||
		unknown = mask
 | 
			
		||||
	)
 | 
			
		||||
	for _, n := range names {
 | 
			
		||||
		if mask&n.m == n.m {
 | 
			
		||||
			l = append(l, n.n)
 | 
			
		||||
			unknown ^= n.m
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	if unknown > 0 {
 | 
			
		||||
		l = append(l, fmt.Sprintf("0x%x", unknown))
 | 
			
		||||
	}
 | 
			
		||||
	fmt.Fprintf(os.Stderr, "FSNOTIFY_DEBUG: %s  %-65s → %q\n",
 | 
			
		||||
		time.Now().Format("15:04:05.000000000"), strings.Join(l, " | "), filepath.ToSlash(name))
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										31
									
								
								vendor/github.com/fsnotify/fsnotify/internal/freebsd.go
									
										
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										31
									
								
								vendor/github.com/fsnotify/fsnotify/internal/freebsd.go
									
										
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,31 @@
 | 
			
		|||
//go:build freebsd
 | 
			
		||||
 | 
			
		||||
package internal
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"syscall"
 | 
			
		||||
 | 
			
		||||
	"golang.org/x/sys/unix"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
var (
 | 
			
		||||
	SyscallEACCES = syscall.EACCES
 | 
			
		||||
	UnixEACCES    = unix.EACCES
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
var maxfiles uint64
 | 
			
		||||
 | 
			
		||||
func SetRlimit() {
 | 
			
		||||
	// Go 1.19 will do this automatically: https://go-review.googlesource.com/c/go/+/393354/
 | 
			
		||||
	var l syscall.Rlimit
 | 
			
		||||
	err := syscall.Getrlimit(syscall.RLIMIT_NOFILE, &l)
 | 
			
		||||
	if err == nil && l.Cur != l.Max {
 | 
			
		||||
		l.Cur = l.Max
 | 
			
		||||
		syscall.Setrlimit(syscall.RLIMIT_NOFILE, &l)
 | 
			
		||||
	}
 | 
			
		||||
	maxfiles = uint64(l.Cur)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func Maxfiles() uint64                              { return maxfiles }
 | 
			
		||||
func Mkfifo(path string, mode uint32) error         { return unix.Mkfifo(path, mode) }
 | 
			
		||||
func Mknod(path string, mode uint32, dev int) error { return unix.Mknod(path, mode, uint64(dev)) }
 | 
			
		||||
							
								
								
									
										2
									
								
								vendor/github.com/fsnotify/fsnotify/internal/internal.go
									
										
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										2
									
								
								vendor/github.com/fsnotify/fsnotify/internal/internal.go
									
										
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,2 @@
 | 
			
		|||
// Package internal contains some helpers.
 | 
			
		||||
package internal
 | 
			
		||||
							
								
								
									
										31
									
								
								vendor/github.com/fsnotify/fsnotify/internal/unix.go
									
										
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										31
									
								
								vendor/github.com/fsnotify/fsnotify/internal/unix.go
									
										
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,31 @@
 | 
			
		|||
//go:build !windows && !darwin && !freebsd
 | 
			
		||||
 | 
			
		||||
package internal
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"syscall"
 | 
			
		||||
 | 
			
		||||
	"golang.org/x/sys/unix"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
var (
 | 
			
		||||
	SyscallEACCES = syscall.EACCES
 | 
			
		||||
	UnixEACCES    = unix.EACCES
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
var maxfiles uint64
 | 
			
		||||
 | 
			
		||||
func SetRlimit() {
 | 
			
		||||
	// Go 1.19 will do this automatically: https://go-review.googlesource.com/c/go/+/393354/
 | 
			
		||||
	var l syscall.Rlimit
 | 
			
		||||
	err := syscall.Getrlimit(syscall.RLIMIT_NOFILE, &l)
 | 
			
		||||
	if err == nil && l.Cur != l.Max {
 | 
			
		||||
		l.Cur = l.Max
 | 
			
		||||
		syscall.Setrlimit(syscall.RLIMIT_NOFILE, &l)
 | 
			
		||||
	}
 | 
			
		||||
	maxfiles = uint64(l.Cur)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func Maxfiles() uint64                              { return maxfiles }
 | 
			
		||||
func Mkfifo(path string, mode uint32) error         { return unix.Mkfifo(path, mode) }
 | 
			
		||||
func Mknod(path string, mode uint32, dev int) error { return unix.Mknod(path, mode, dev) }
 | 
			
		||||
							
								
								
									
										7
									
								
								vendor/github.com/fsnotify/fsnotify/internal/unix2.go
									
										
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										7
									
								
								vendor/github.com/fsnotify/fsnotify/internal/unix2.go
									
										
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,7 @@
 | 
			
		|||
//go:build !windows
 | 
			
		||||
 | 
			
		||||
package internal
 | 
			
		||||
 | 
			
		||||
func HasPrivilegesForSymlink() bool {
 | 
			
		||||
	return true
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										41
									
								
								vendor/github.com/fsnotify/fsnotify/internal/windows.go
									
										
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										41
									
								
								vendor/github.com/fsnotify/fsnotify/internal/windows.go
									
										
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,41 @@
 | 
			
		|||
//go:build windows
 | 
			
		||||
 | 
			
		||||
package internal
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"errors"
 | 
			
		||||
 | 
			
		||||
	"golang.org/x/sys/windows"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
// Just a dummy.
 | 
			
		||||
var (
 | 
			
		||||
	SyscallEACCES = errors.New("dummy")
 | 
			
		||||
	UnixEACCES    = errors.New("dummy")
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
func SetRlimit()                                    {}
 | 
			
		||||
func Maxfiles() uint64                              { return 1<<64 - 1 }
 | 
			
		||||
func Mkfifo(path string, mode uint32) error         { return errors.New("no FIFOs on Windows") }
 | 
			
		||||
func Mknod(path string, mode uint32, dev int) error { return errors.New("no device nodes on Windows") }
 | 
			
		||||
 | 
			
		||||
func HasPrivilegesForSymlink() bool {
 | 
			
		||||
	var sid *windows.SID
 | 
			
		||||
	err := windows.AllocateAndInitializeSid(
 | 
			
		||||
		&windows.SECURITY_NT_AUTHORITY,
 | 
			
		||||
		2,
 | 
			
		||||
		windows.SECURITY_BUILTIN_DOMAIN_RID,
 | 
			
		||||
		windows.DOMAIN_ALIAS_RID_ADMINS,
 | 
			
		||||
		0, 0, 0, 0, 0, 0,
 | 
			
		||||
		&sid)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return false
 | 
			
		||||
	}
 | 
			
		||||
	defer windows.FreeSid(sid)
 | 
			
		||||
	token := windows.Token(0)
 | 
			
		||||
	member, err := token.IsMember(sid)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return false
 | 
			
		||||
	}
 | 
			
		||||
	return member || token.IsElevated()
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										259
									
								
								vendor/github.com/fsnotify/fsnotify/mkdoc.zsh
									
										
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										259
									
								
								vendor/github.com/fsnotify/fsnotify/mkdoc.zsh
									
										
									
										generated
									
									
										vendored
									
									
								
							| 
						 | 
				
			
			@ -1,259 +0,0 @@
 | 
			
		|||
#!/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 so you don't need
 | 
			
		||||
# to update the same comment 5 times.
 | 
			
		||||
 | 
			
		||||
watcher=$(<<EOF
 | 
			
		||||
// 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.
 | 
			
		||||
//
 | 
			
		||||
// # Windows notes
 | 
			
		||||
//
 | 
			
		||||
// Paths can be added as "C:\\path\\to\\dir", but forward slashes
 | 
			
		||||
// ("C:/path/to/dir") will also work.
 | 
			
		||||
//
 | 
			
		||||
// When a watched directory is removed it will always send an event for the
 | 
			
		||||
// directory itself, but may not send events for all files in that directory.
 | 
			
		||||
// Sometimes it will send events for all times, sometimes it will send no
 | 
			
		||||
// events, and often only for some files.
 | 
			
		||||
//
 | 
			
		||||
// The default ReadDirectoryChangesW() buffer size is 64K, which is the largest
 | 
			
		||||
// value that is guaranteed to work with SMB filesystems. If you have many
 | 
			
		||||
// events in quick succession this may not be enough, and you will have to use
 | 
			
		||||
// [WithBufferSize] to increase the value.
 | 
			
		||||
EOF
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
new=$(<<EOF
 | 
			
		||||
// NewWatcher creates a new Watcher.
 | 
			
		||||
EOF
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
newbuffered=$(<<EOF
 | 
			
		||||
// NewBufferedWatcher creates a new Watcher with a buffered Watcher.Events
 | 
			
		||||
// channel.
 | 
			
		||||
//
 | 
			
		||||
// The main use case for this is situations with a very large number of events
 | 
			
		||||
// where the kernel buffer size can't be increased (e.g. due to lack of
 | 
			
		||||
// permissions). An unbuffered Watcher will perform better for almost all use
 | 
			
		||||
// cases, and whenever possible you will be better off increasing the kernel
 | 
			
		||||
// buffers instead of adding a large userspace buffer.
 | 
			
		||||
EOF
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
add=$(<<EOF
 | 
			
		||||
// Add starts monitoring the path for changes.
 | 
			
		||||
//
 | 
			
		||||
// A path can only be watched once; watching it more than once is a no-op and will
 | 
			
		||||
// not return an error. Paths that do not yet exist on the filesystem cannot be
 | 
			
		||||
// watched.
 | 
			
		||||
//
 | 
			
		||||
// A watch will be automatically removed if the watched path is deleted or
 | 
			
		||||
// renamed. The exception is the Windows backend, which doesn't remove the
 | 
			
		||||
// watcher on renames.
 | 
			
		||||
//
 | 
			
		||||
// Notifications on network filesystems (NFS, SMB, FUSE, etc.) or special
 | 
			
		||||
// filesystems (/proc, /sys, etc.) generally don't work.
 | 
			
		||||
//
 | 
			
		||||
// Returns [ErrClosed] if [Watcher.Close] was called.
 | 
			
		||||
//
 | 
			
		||||
// See [Watcher.AddWith] for a version that allows adding options.
 | 
			
		||||
//
 | 
			
		||||
// # 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 programs (especially editors) update files atomically: it
 | 
			
		||||
// will write to a temporary file which is then moved to to destination,
 | 
			
		||||
// overwriting the original (or some variant thereof). The watcher on the
 | 
			
		||||
// original file is now lost, as that no longer exists.
 | 
			
		||||
//
 | 
			
		||||
// The upshot of this is that a power failure or crash won't leave a
 | 
			
		||||
// half-written file.
 | 
			
		||||
//
 | 
			
		||||
// 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.
 | 
			
		||||
EOF
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
addwith=$(<<EOF
 | 
			
		||||
// AddWith is like [Watcher.Add], but allows adding options. When using Add()
 | 
			
		||||
// the defaults described below are used.
 | 
			
		||||
//
 | 
			
		||||
// Possible options are:
 | 
			
		||||
//
 | 
			
		||||
//   - [WithBufferSize] sets the buffer size for the Windows backend; no-op on
 | 
			
		||||
//     other platforms. The default is 64K (65536 bytes).
 | 
			
		||||
EOF
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
remove=$(<<EOF
 | 
			
		||||
// 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].
 | 
			
		||||
//
 | 
			
		||||
// Returns nil if [Watcher.Close] was called.
 | 
			
		||||
EOF
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
close=$(<<EOF
 | 
			
		||||
// Close removes all watches and closes the Events channel.
 | 
			
		||||
EOF
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
watchlist=$(<<EOF
 | 
			
		||||
// WatchList returns all paths explicitly added with [Watcher.Add] (and are not
 | 
			
		||||
// yet removed).
 | 
			
		||||
//
 | 
			
		||||
// Returns nil if [Watcher.Close] was called.
 | 
			
		||||
EOF
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
events=$(<<EOF
 | 
			
		||||
	// 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, and you may
 | 
			
		||||
	//                      want to wait until you've stopped receiving them
 | 
			
		||||
	//                      (see the dedup example in cmd/fsnotify).
 | 
			
		||||
	//
 | 
			
		||||
	//                      Some systems may send Write event for directories
 | 
			
		||||
	//                      when the directory content changes.
 | 
			
		||||
	//
 | 
			
		||||
	//   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
 | 
			
		||||
	//                      when a file is truncated. On Windows it's never
 | 
			
		||||
	//                      sent.
 | 
			
		||||
EOF
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
errors=$(<<EOF
 | 
			
		||||
	// Errors sends any errors.
 | 
			
		||||
	//
 | 
			
		||||
	// ErrEventOverflow is used to indicate there are too many events:
 | 
			
		||||
	//
 | 
			
		||||
	//  - inotify:      There are too many queued events (fs.inotify.max_queued_events sysctl)
 | 
			
		||||
	//  - windows:      The buffer size is too small; WithBufferSize() can be used to increase it.
 | 
			
		||||
	//  - kqueue, fen:  Not used.
 | 
			
		||||
EOF
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
set-cmt() {
 | 
			
		||||
	local pat=$1
 | 
			
		||||
	local cmt=$2
 | 
			
		||||
 | 
			
		||||
	IFS=$'\n' local files=($(grep -n $pat backend_*~*_test.go))
 | 
			
		||||
	for f in $files; do
 | 
			
		||||
		IFS=':' local fields=($=f)
 | 
			
		||||
		local file=$fields[1]
 | 
			
		||||
		local end=$(( $fields[2] - 1 ))
 | 
			
		||||
 | 
			
		||||
		# Find start of comment.
 | 
			
		||||
		local start=0
 | 
			
		||||
		IFS=$'\n' local lines=($(head -n$end $file))
 | 
			
		||||
		for (( i = 1; i <= $#lines; i++ )); do
 | 
			
		||||
			local line=$lines[-$i]
 | 
			
		||||
			if ! grep -q '^[[:space:]]*//' <<<$line; then
 | 
			
		||||
				start=$(( end - (i - 2) ))
 | 
			
		||||
				break
 | 
			
		||||
			fi
 | 
			
		||||
		done
 | 
			
		||||
 | 
			
		||||
		head -n $(( start - 1 )) $file  >/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 NewBufferedWatcher('         $newbuffered
 | 
			
		||||
set-cmt '^func (w \*Watcher) Add('          $add
 | 
			
		||||
set-cmt '^func (w \*Watcher) AddWith('      $addwith
 | 
			
		||||
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
 | 
			
		||||
							
								
								
									
										1
									
								
								vendor/github.com/fsnotify/fsnotify/system_bsd.go
									
										
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										1
									
								
								vendor/github.com/fsnotify/fsnotify/system_bsd.go
									
										
									
										generated
									
									
										vendored
									
									
								
							| 
						 | 
				
			
			@ -1,5 +1,4 @@
 | 
			
		|||
//go:build freebsd || openbsd || netbsd || dragonfly
 | 
			
		||||
// +build freebsd openbsd netbsd dragonfly
 | 
			
		||||
 | 
			
		||||
package fsnotify
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										1
									
								
								vendor/github.com/fsnotify/fsnotify/system_darwin.go
									
										
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										1
									
								
								vendor/github.com/fsnotify/fsnotify/system_darwin.go
									
										
									
										generated
									
									
										vendored
									
									
								
							| 
						 | 
				
			
			@ -1,5 +1,4 @@
 | 
			
		|||
//go:build darwin
 | 
			
		||||
// +build darwin
 | 
			
		||||
 | 
			
		||||
package fsnotify
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue