mirror of
				https://github.com/superseriousbusiness/gotosocial.git
				synced 2025-11-04 09:32:25 -06:00 
			
		
		
		
	[chore] update dependencies (#4423)
- codeberg.org/gruf/go-ffmpreg: v0.6.10 -> v0.6.11 - github.com/spf13/cast: v1.9.2 -> v1.10.0 - github.com/spf13/viper: v1.20.1 -> v1.21.0 - golang.org/x/crypto: v0.41.0 -> v0.42.0 - golang.org/x/image: v0.30.0 -> v0.31.0 Reviewed-on: https://codeberg.org/superseriousbusiness/gotosocial/pulls/4423 Co-authored-by: kim <grufwub@gmail.com> Co-committed-by: kim <grufwub@gmail.com>
This commit is contained in:
		
					parent
					
						
							
								a6429b5410
							
						
					
				
			
			
				commit
				
					
						c949b9f2d1
					
				
			
		
					 97 changed files with 14611 additions and 3494 deletions
				
			
		
							
								
								
									
										2
									
								
								vendor/github.com/fsnotify/fsnotify/.cirrus.yml
									
										
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										2
									
								
								vendor/github.com/fsnotify/fsnotify/.cirrus.yml
									
										
									
										generated
									
									
										vendored
									
									
								
							| 
						 | 
				
			
			@ -1,7 +1,7 @@
 | 
			
		|||
freebsd_task:
 | 
			
		||||
  name: 'FreeBSD'
 | 
			
		||||
  freebsd_instance:
 | 
			
		||||
    image_family: freebsd-14-1
 | 
			
		||||
    image_family: freebsd-14-2
 | 
			
		||||
  install_script:
 | 
			
		||||
    - pkg update -f
 | 
			
		||||
    - pkg install -y go
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										35
									
								
								vendor/github.com/fsnotify/fsnotify/CHANGELOG.md
									
										
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										35
									
								
								vendor/github.com/fsnotify/fsnotify/CHANGELOG.md
									
										
									
										generated
									
									
										vendored
									
									
								
							| 
						 | 
				
			
			@ -1,6 +1,39 @@
 | 
			
		|||
# Changelog
 | 
			
		||||
 | 
			
		||||
1.8.0 2023-10-31
 | 
			
		||||
1.9.0 2024-04-04
 | 
			
		||||
----------------
 | 
			
		||||
 | 
			
		||||
### Changes and fixes
 | 
			
		||||
 | 
			
		||||
- all: make BufferedWatcher buffered again ([#657])
 | 
			
		||||
 | 
			
		||||
- inotify: fix race when adding/removing watches while a watched path is being
 | 
			
		||||
  deleted ([#678], [#686])
 | 
			
		||||
 | 
			
		||||
- inotify: don't send empty event if a watched path is unmounted ([#655])
 | 
			
		||||
 | 
			
		||||
- inotify: don't register duplicate watches when watching both a symlink and its
 | 
			
		||||
  target; previously that would get "half-added" and removing the second would
 | 
			
		||||
  panic ([#679])
 | 
			
		||||
 | 
			
		||||
- kqueue: fix watching relative symlinks ([#681])
 | 
			
		||||
 | 
			
		||||
- kqueue: correctly mark pre-existing entries when watching a link to a dir on
 | 
			
		||||
  kqueue ([#682])
 | 
			
		||||
 | 
			
		||||
- illumos: don't send error if changed file is deleted while processing the
 | 
			
		||||
  event ([#678])
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
[#657]: https://github.com/fsnotify/fsnotify/pull/657
 | 
			
		||||
[#678]: https://github.com/fsnotify/fsnotify/pull/678
 | 
			
		||||
[#686]: https://github.com/fsnotify/fsnotify/pull/686
 | 
			
		||||
[#655]: https://github.com/fsnotify/fsnotify/pull/655
 | 
			
		||||
[#681]: https://github.com/fsnotify/fsnotify/pull/681
 | 
			
		||||
[#679]: https://github.com/fsnotify/fsnotify/pull/679
 | 
			
		||||
[#682]: https://github.com/fsnotify/fsnotify/pull/682
 | 
			
		||||
 | 
			
		||||
1.8.0 2024-10-31
 | 
			
		||||
----------------
 | 
			
		||||
 | 
			
		||||
### Additions
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										1
									
								
								vendor/github.com/fsnotify/fsnotify/CONTRIBUTING.md
									
										
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										1
									
								
								vendor/github.com/fsnotify/fsnotify/CONTRIBUTING.md
									
										
									
										generated
									
									
										vendored
									
									
								
							| 
						 | 
				
			
			@ -77,6 +77,7 @@ End-of-line escapes with `\` are not supported.
 | 
			
		|||
    debug [yes/no]      # Enable/disable FSNOTIFY_DEBUG (tests are run in
 | 
			
		||||
                          parallel by default, so -parallel=1 is probably a good
 | 
			
		||||
                          idea).
 | 
			
		||||
    print [any strings] # Print text to stdout; for debugging.
 | 
			
		||||
 | 
			
		||||
    touch path
 | 
			
		||||
    mkdir [-p] dir
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										2
									
								
								vendor/github.com/fsnotify/fsnotify/README.md
									
										
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										2
									
								
								vendor/github.com/fsnotify/fsnotify/README.md
									
										
									
										generated
									
									
										vendored
									
									
								
							| 
						 | 
				
			
			@ -15,7 +15,6 @@ Platform support:
 | 
			
		|||
| ReadDirectoryChangesW | Windows    | Supported                                                                 |
 | 
			
		||||
| FEN                   | illumos    | Supported                                                                 |
 | 
			
		||||
| fanotify              | Linux 5.9+ | [Not yet](https://github.com/fsnotify/fsnotify/issues/114)                |
 | 
			
		||||
| AHAFS                 | AIX        | [aix branch]; experimental due to lack of maintainer and test environment |
 | 
			
		||||
| FSEvents              | macOS      | [Needs support in x/sys/unix][fsevents]                                   |
 | 
			
		||||
| USN Journals          | Windows    | [Needs support in x/sys/windows][usn]                                     |
 | 
			
		||||
| Polling               | *All*      | [Not yet](https://github.com/fsnotify/fsnotify/issues/9)                  |
 | 
			
		||||
| 
						 | 
				
			
			@ -25,7 +24,6 @@ untested.
 | 
			
		|||
 | 
			
		||||
[fsevents]:   https://github.com/fsnotify/fsnotify/issues/11#issuecomment-1279133120
 | 
			
		||||
[usn]:        https://github.com/fsnotify/fsnotify/issues/53#issuecomment-1279829847
 | 
			
		||||
[aix branch]: https://github.com/fsnotify/fsnotify/issues/353#issuecomment-1284590129
 | 
			
		||||
 | 
			
		||||
Usage
 | 
			
		||||
-----
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										107
									
								
								vendor/github.com/fsnotify/fsnotify/backend_fen.go
									
										
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										107
									
								
								vendor/github.com/fsnotify/fsnotify/backend_fen.go
									
										
									
										generated
									
									
										vendored
									
									
								
							| 
						 | 
				
			
			@ -9,6 +9,7 @@ package fsnotify
 | 
			
		|||
import (
 | 
			
		||||
	"errors"
 | 
			
		||||
	"fmt"
 | 
			
		||||
	"io/fs"
 | 
			
		||||
	"os"
 | 
			
		||||
	"path/filepath"
 | 
			
		||||
	"sync"
 | 
			
		||||
| 
						 | 
				
			
			@ -19,27 +20,25 @@ import (
 | 
			
		|||
)
 | 
			
		||||
 | 
			
		||||
type fen struct {
 | 
			
		||||
	*shared
 | 
			
		||||
	Events chan Event
 | 
			
		||||
	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]Op // Explicitly watched directories
 | 
			
		||||
	watches map[string]Op // Explicitly watched non-directories
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func newBackend(ev chan Event, errs chan error) (backend, error) {
 | 
			
		||||
	return newBufferedBackend(0, ev, errs)
 | 
			
		||||
}
 | 
			
		||||
var defaultBufferSize = 0
 | 
			
		||||
 | 
			
		||||
func newBufferedBackend(sz uint, ev chan Event, errs chan error) (backend, error) {
 | 
			
		||||
func newBackend(ev chan Event, errs chan error) (backend, error) {
 | 
			
		||||
	w := &fen{
 | 
			
		||||
		shared:  newShared(ev, errs),
 | 
			
		||||
		Events:  ev,
 | 
			
		||||
		Errors:  errs,
 | 
			
		||||
		dirs:    make(map[string]Op),
 | 
			
		||||
		watches: make(map[string]Op),
 | 
			
		||||
		done:    make(chan struct{}),
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	var err error
 | 
			
		||||
| 
						 | 
				
			
			@ -52,49 +51,10 @@ func newBufferedBackend(sz uint, ev chan Event, errs chan error) (backend, error
 | 
			
		|||
	return w, nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// 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 *fen) sendEvent(name string, op Op) (sent bool) {
 | 
			
		||||
	select {
 | 
			
		||||
	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 *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 *fen) isClosed() bool {
 | 
			
		||||
	select {
 | 
			
		||||
	case <-w.done:
 | 
			
		||||
		return true
 | 
			
		||||
	default:
 | 
			
		||||
		return false
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (w *fen) Close() error {
 | 
			
		||||
	// Take the lock used by associateFile to prevent lingering events from
 | 
			
		||||
	// being processed after the close
 | 
			
		||||
	w.mu.Lock()
 | 
			
		||||
	defer w.mu.Unlock()
 | 
			
		||||
	if w.isClosed() {
 | 
			
		||||
	if w.shared.close() {
 | 
			
		||||
		return nil
 | 
			
		||||
	}
 | 
			
		||||
	close(w.done)
 | 
			
		||||
	return w.port.Close()
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -209,7 +169,7 @@ func (w *fen) readEvents() {
 | 
			
		|||
				return
 | 
			
		||||
			}
 | 
			
		||||
			// There was an error not caused by calling w.Close()
 | 
			
		||||
			if !w.sendError(err) {
 | 
			
		||||
			if !w.sendError(fmt.Errorf("port.Get: %w", err)) {
 | 
			
		||||
				return
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
| 
						 | 
				
			
			@ -277,13 +237,13 @@ func (w *fen) handleEvent(event *unix.PortEvent) error {
 | 
			
		|||
	isWatched := watchedDir || watchedPath
 | 
			
		||||
 | 
			
		||||
	if events&unix.FILE_DELETE != 0 {
 | 
			
		||||
		if !w.sendEvent(path, Remove) {
 | 
			
		||||
		if !w.sendEvent(Event{Name: path, Op: Remove}) {
 | 
			
		||||
			return nil
 | 
			
		||||
		}
 | 
			
		||||
		reRegister = false
 | 
			
		||||
	}
 | 
			
		||||
	if events&unix.FILE_RENAME_FROM != 0 {
 | 
			
		||||
		if !w.sendEvent(path, Rename) {
 | 
			
		||||
		if !w.sendEvent(Event{Name: path, Op: Rename}) {
 | 
			
		||||
			return nil
 | 
			
		||||
		}
 | 
			
		||||
		// Don't keep watching the new file name
 | 
			
		||||
| 
						 | 
				
			
			@ -297,7 +257,7 @@ func (w *fen) handleEvent(event *unix.PortEvent) error {
 | 
			
		|||
 | 
			
		||||
		// inotify reports a Remove event in this case, so we simulate this
 | 
			
		||||
		// here.
 | 
			
		||||
		if !w.sendEvent(path, Remove) {
 | 
			
		||||
		if !w.sendEvent(Event{Name: path, Op: Remove}) {
 | 
			
		||||
			return nil
 | 
			
		||||
		}
 | 
			
		||||
		// Don't keep watching the file that was removed
 | 
			
		||||
| 
						 | 
				
			
			@ -331,7 +291,7 @@ func (w *fen) handleEvent(event *unix.PortEvent) error {
 | 
			
		|||
		// get here, the sudirectory is already gone. Clearly we were watching
 | 
			
		||||
		// this path but now it is gone. Let's tell the user that it was
 | 
			
		||||
		// removed.
 | 
			
		||||
		if !w.sendEvent(path, Remove) {
 | 
			
		||||
		if !w.sendEvent(Event{Name: path, Op: Remove}) {
 | 
			
		||||
			return nil
 | 
			
		||||
		}
 | 
			
		||||
		// Suppress extra write events on removed directories; they are not
 | 
			
		||||
| 
						 | 
				
			
			@ -346,7 +306,7 @@ func (w *fen) handleEvent(event *unix.PortEvent) error {
 | 
			
		|||
		if err != nil {
 | 
			
		||||
			// The symlink still exists, but the target is gone. Report the
 | 
			
		||||
			// Remove similar to above.
 | 
			
		||||
			if !w.sendEvent(path, Remove) {
 | 
			
		||||
			if !w.sendEvent(Event{Name: path, Op: Remove}) {
 | 
			
		||||
				return nil
 | 
			
		||||
			}
 | 
			
		||||
			// Don't return the error
 | 
			
		||||
| 
						 | 
				
			
			@ -359,7 +319,7 @@ func (w *fen) handleEvent(event *unix.PortEvent) error {
 | 
			
		|||
				return err
 | 
			
		||||
			}
 | 
			
		||||
		} else {
 | 
			
		||||
			if !w.sendEvent(path, Write) {
 | 
			
		||||
			if !w.sendEvent(Event{Name: path, Op: Write}) {
 | 
			
		||||
				return nil
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
| 
						 | 
				
			
			@ -367,7 +327,7 @@ func (w *fen) handleEvent(event *unix.PortEvent) error {
 | 
			
		|||
	if events&unix.FILE_ATTRIB != 0 && stat != nil {
 | 
			
		||||
		// Only send Chmod if perms changed
 | 
			
		||||
		if stat.Mode().Perm() != fmode.Perm() {
 | 
			
		||||
			if !w.sendEvent(path, Chmod) {
 | 
			
		||||
			if !w.sendEvent(Event{Name: path, Op: Chmod}) {
 | 
			
		||||
				return nil
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
| 
						 | 
				
			
			@ -376,17 +336,27 @@ func (w *fen) handleEvent(event *unix.PortEvent) error {
 | 
			
		|||
	if stat != nil {
 | 
			
		||||
		// If we get here, it means we've hit an event above that requires us to
 | 
			
		||||
		// continue watching the file or directory
 | 
			
		||||
		return w.associateFile(path, stat, isWatched)
 | 
			
		||||
		err := w.associateFile(path, stat, isWatched)
 | 
			
		||||
		if errors.Is(err, fs.ErrNotExist) {
 | 
			
		||||
			// Path may have been removed since the stat.
 | 
			
		||||
			err = nil
 | 
			
		||||
		}
 | 
			
		||||
		return err
 | 
			
		||||
	}
 | 
			
		||||
	return nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// 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.
 | 
			
		||||
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.
 | 
			
		||||
	files, err := os.ReadDir(path)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		// Directory no longer exists: probably just deleted since we got the
 | 
			
		||||
		// event.
 | 
			
		||||
		if errors.Is(err, fs.ErrNotExist) {
 | 
			
		||||
			return nil
 | 
			
		||||
		}
 | 
			
		||||
		return err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -401,10 +371,15 @@ func (w *fen) updateDirectory(path string) error {
 | 
			
		|||
			return err
 | 
			
		||||
		}
 | 
			
		||||
		err = w.associateFile(path, finfo, false)
 | 
			
		||||
		if errors.Is(err, fs.ErrNotExist) {
 | 
			
		||||
			// File may have disappeared between getting the dir listing and
 | 
			
		||||
			// adding the port: that's okay to ignore.
 | 
			
		||||
			continue
 | 
			
		||||
		}
 | 
			
		||||
		if !w.sendError(err) {
 | 
			
		||||
			return nil
 | 
			
		||||
		}
 | 
			
		||||
		if !w.sendEvent(path, Create) {
 | 
			
		||||
		if !w.sendEvent(Event{Name: path, Op: Create}) {
 | 
			
		||||
			return nil
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
| 
						 | 
				
			
			@ -430,7 +405,7 @@ func (w *fen) associateFile(path string, stat os.FileInfo, follow bool) error {
 | 
			
		|||
		// has fired but we haven't processed it yet.
 | 
			
		||||
		err := w.port.DissociatePath(path)
 | 
			
		||||
		if err != nil && !errors.Is(err, unix.ENOENT) {
 | 
			
		||||
			return err
 | 
			
		||||
			return fmt.Errorf("port.DissociatePath(%q): %w", path, err)
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -446,14 +421,22 @@ func (w *fen) associateFile(path string, stat os.FileInfo, follow bool) error {
 | 
			
		|||
	if true {
 | 
			
		||||
		events |= unix.FILE_ATTRIB
 | 
			
		||||
	}
 | 
			
		||||
	return w.port.AssociatePath(path, stat, events, stat.Mode())
 | 
			
		||||
	err := w.port.AssociatePath(path, stat, events, stat.Mode())
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return fmt.Errorf("port.AssociatePath(%q): %w", path, err)
 | 
			
		||||
	}
 | 
			
		||||
	return nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (w *fen) dissociateFile(path string, stat os.FileInfo, unused bool) error {
 | 
			
		||||
	if !w.port.PathIsWatched(path) {
 | 
			
		||||
		return nil
 | 
			
		||||
	}
 | 
			
		||||
	return w.port.DissociatePath(path)
 | 
			
		||||
	err := w.port.DissociatePath(path)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return fmt.Errorf("port.DissociatePath(%q): %w", path, err)
 | 
			
		||||
	}
 | 
			
		||||
	return nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (w *fen) WatchList() []string {
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										441
									
								
								vendor/github.com/fsnotify/fsnotify/backend_inotify.go
									
										
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										441
									
								
								vendor/github.com/fsnotify/fsnotify/backend_inotify.go
									
										
									
										generated
									
									
										vendored
									
									
								
							| 
						 | 
				
			
			@ -19,6 +19,7 @@ import (
 | 
			
		|||
)
 | 
			
		||||
 | 
			
		||||
type inotify struct {
 | 
			
		||||
	*shared
 | 
			
		||||
	Events chan Event
 | 
			
		||||
	Errors chan error
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -27,8 +28,6 @@ type inotify struct {
 | 
			
		|||
	fd          int
 | 
			
		||||
	inotifyFile *os.File
 | 
			
		||||
	watches     *watches
 | 
			
		||||
	done        chan struct{} // Channel for sending a "quit message" to the reader goroutine
 | 
			
		||||
	doneMu      sync.Mutex
 | 
			
		||||
	doneResp    chan struct{} // Channel to respond to Close
 | 
			
		||||
 | 
			
		||||
	// Store rename cookies in an array, with the index wrapping to 0. Almost
 | 
			
		||||
| 
						 | 
				
			
			@ -52,7 +51,6 @@ type inotify struct {
 | 
			
		|||
 | 
			
		||||
type (
 | 
			
		||||
	watches struct {
 | 
			
		||||
		mu   sync.RWMutex
 | 
			
		||||
		wd   map[uint32]*watch // wd → watch
 | 
			
		||||
		path map[string]uint32 // pathname → wd
 | 
			
		||||
	}
 | 
			
		||||
| 
						 | 
				
			
			@ -75,34 +73,13 @@ func newWatches() *watches {
 | 
			
		|||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (w *watches) len() int {
 | 
			
		||||
	w.mu.RLock()
 | 
			
		||||
	defer w.mu.RUnlock()
 | 
			
		||||
	return len(w.wd)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (w *watches) add(ww *watch) {
 | 
			
		||||
	w.mu.Lock()
 | 
			
		||||
	defer w.mu.Unlock()
 | 
			
		||||
	w.wd[ww.wd] = ww
 | 
			
		||||
	w.path[ww.path] = ww.wd
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (w *watches) remove(wd uint32) {
 | 
			
		||||
	w.mu.Lock()
 | 
			
		||||
	defer w.mu.Unlock()
 | 
			
		||||
	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) byPath(path string) *watch { return w.wd[w.path[path]] }
 | 
			
		||||
func (w *watches) byWd(wd uint32) *watch     { return w.wd[wd] }
 | 
			
		||||
func (w *watches) len() int                  { return len(w.wd) }
 | 
			
		||||
func (w *watches) add(ww *watch)             { w.wd[ww.wd] = ww; w.path[ww.path] = ww.wd }
 | 
			
		||||
func (w *watches) remove(watch *watch)       { delete(w.path, watch.path); delete(w.wd, watch.wd) }
 | 
			
		||||
 | 
			
		||||
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 {
 | 
			
		||||
| 
						 | 
				
			
			@ -123,7 +100,7 @@ func (w *watches) removePath(path string) ([]uint32, error) {
 | 
			
		|||
	wds := make([]uint32, 0, 8)
 | 
			
		||||
	wds = append(wds, wd)
 | 
			
		||||
	for p, rwd := range w.path {
 | 
			
		||||
		if filepath.HasPrefix(p, path) {
 | 
			
		||||
		if strings.HasPrefix(p, path) {
 | 
			
		||||
			delete(w.path, p)
 | 
			
		||||
			delete(w.wd, rwd)
 | 
			
		||||
			wds = append(wds, rwd)
 | 
			
		||||
| 
						 | 
				
			
			@ -132,22 +109,7 @@ func (w *watches) removePath(path string) ([]uint32, error) {
 | 
			
		|||
	return wds, nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (w *watches) byPath(path string) *watch {
 | 
			
		||||
	w.mu.RLock()
 | 
			
		||||
	defer w.mu.RUnlock()
 | 
			
		||||
	return w.wd[w.path[path]]
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (w *watches) byWd(wd uint32) *watch {
 | 
			
		||||
	w.mu.RLock()
 | 
			
		||||
	defer w.mu.RUnlock()
 | 
			
		||||
	return w.wd[wd]
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (w *watches) updatePath(path string, f func(*watch) (*watch, error)) error {
 | 
			
		||||
	w.mu.Lock()
 | 
			
		||||
	defer w.mu.Unlock()
 | 
			
		||||
 | 
			
		||||
	var existing *watch
 | 
			
		||||
	wd, ok := w.path[path]
 | 
			
		||||
	if ok {
 | 
			
		||||
| 
						 | 
				
			
			@ -170,11 +132,9 @@ func (w *watches) updatePath(path string, f func(*watch) (*watch, error)) error
 | 
			
		|||
	return nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func newBackend(ev chan Event, errs chan error) (backend, error) {
 | 
			
		||||
	return newBufferedBackend(0, ev, errs)
 | 
			
		||||
}
 | 
			
		||||
var defaultBufferSize = 0
 | 
			
		||||
 | 
			
		||||
func newBufferedBackend(sz uint, ev chan Event, errs chan error) (backend, error) {
 | 
			
		||||
func newBackend(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)
 | 
			
		||||
| 
						 | 
				
			
			@ -183,12 +143,12 @@ func newBufferedBackend(sz uint, ev chan Event, errs chan error) (backend, error
 | 
			
		|||
	}
 | 
			
		||||
 | 
			
		||||
	w := &inotify{
 | 
			
		||||
		shared:      newShared(ev, errs),
 | 
			
		||||
		Events:      ev,
 | 
			
		||||
		Errors:      errs,
 | 
			
		||||
		fd:          fd,
 | 
			
		||||
		inotifyFile: os.NewFile(uintptr(fd), ""),
 | 
			
		||||
		watches:     newWatches(),
 | 
			
		||||
		done:        make(chan struct{}),
 | 
			
		||||
		doneResp:    make(chan struct{}),
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -196,46 +156,10 @@ func newBufferedBackend(sz uint, ev chan Event, errs chan error) (backend, error
 | 
			
		|||
	return w, nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Returns true if the event was sent, or false if watcher is closed.
 | 
			
		||||
func (w *inotify) sendEvent(e Event) bool {
 | 
			
		||||
	select {
 | 
			
		||||
	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 *inotify) sendError(err error) bool {
 | 
			
		||||
	if err == nil {
 | 
			
		||||
		return true
 | 
			
		||||
	}
 | 
			
		||||
	select {
 | 
			
		||||
	case <-w.done:
 | 
			
		||||
		return false
 | 
			
		||||
	case w.Errors <- err:
 | 
			
		||||
		return true
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (w *inotify) isClosed() bool {
 | 
			
		||||
	select {
 | 
			
		||||
	case <-w.done:
 | 
			
		||||
		return true
 | 
			
		||||
	default:
 | 
			
		||||
		return false
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (w *inotify) Close() error {
 | 
			
		||||
	w.doneMu.Lock()
 | 
			
		||||
	if w.isClosed() {
 | 
			
		||||
		w.doneMu.Unlock()
 | 
			
		||||
	if w.shared.close() {
 | 
			
		||||
		return nil
 | 
			
		||||
	}
 | 
			
		||||
	close(w.done)
 | 
			
		||||
	w.doneMu.Unlock()
 | 
			
		||||
 | 
			
		||||
	// Causes any blocking reads to return with an error, provided the file
 | 
			
		||||
	// still supports deadline operations.
 | 
			
		||||
| 
						 | 
				
			
			@ -244,9 +168,7 @@ func (w *inotify) Close() error {
 | 
			
		|||
		return err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// Wait for goroutine to close
 | 
			
		||||
	<-w.doneResp
 | 
			
		||||
 | 
			
		||||
	<-w.doneResp // Wait for readEvents() to finish.
 | 
			
		||||
	return nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -266,6 +188,43 @@ func (w *inotify) AddWith(path string, opts ...addOpt) error {
 | 
			
		|||
		return fmt.Errorf("%w: %s", xErrUnsupported, with.op)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	add := func(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)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	w.mu.Lock()
 | 
			
		||||
	defer w.mu.Unlock()
 | 
			
		||||
	path, recurse := recursivePath(path)
 | 
			
		||||
	if recurse {
 | 
			
		||||
		return filepath.WalkDir(path, func(root string, d fs.DirEntry, err error) error {
 | 
			
		||||
| 
						 | 
				
			
			@ -289,46 +248,11 @@ func (w *inotify) AddWith(path string, opts ...addOpt) error {
 | 
			
		|||
				w.sendEvent(Event{Name: root, Op: Create})
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			return w.add(root, with, true)
 | 
			
		||||
			return 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)
 | 
			
		||||
	return add(path, with, false)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (w *inotify) register(path string, flags uint32, recurse bool) error {
 | 
			
		||||
| 
						 | 
				
			
			@ -342,6 +266,10 @@ func (w *inotify) register(path string, flags uint32, recurse bool) error {
 | 
			
		|||
			return nil, err
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		if e, ok := w.watches.wd[uint32(wd)]; ok {
 | 
			
		||||
			return e, nil
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		if existing == nil {
 | 
			
		||||
			return &watch{
 | 
			
		||||
				wd:      uint32(wd),
 | 
			
		||||
| 
						 | 
				
			
			@ -365,6 +293,9 @@ func (w *inotify) Remove(name string) error {
 | 
			
		|||
		fmt.Fprintf(os.Stderr, "FSNOTIFY_DEBUG: %s  Remove(%q)\n",
 | 
			
		||||
			time.Now().Format("15:04:05.000000000"), name)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	w.mu.Lock()
 | 
			
		||||
	defer w.mu.Unlock()
 | 
			
		||||
	return w.remove(filepath.Clean(name))
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -399,13 +330,12 @@ func (w *inotify) WatchList() []string {
 | 
			
		|||
		return nil
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	w.mu.Lock()
 | 
			
		||||
	defer w.mu.Unlock()
 | 
			
		||||
	entries := make([]string, 0, w.watches.len())
 | 
			
		||||
	w.watches.mu.RLock()
 | 
			
		||||
	for pathname := range w.watches.path {
 | 
			
		||||
		entries = append(entries, pathname)
 | 
			
		||||
	}
 | 
			
		||||
	w.watches.mu.RUnlock()
 | 
			
		||||
 | 
			
		||||
	return entries
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -418,21 +348,17 @@ func (w *inotify) readEvents() {
 | 
			
		|||
		close(w.Events)
 | 
			
		||||
	}()
 | 
			
		||||
 | 
			
		||||
	var (
 | 
			
		||||
		buf   [unix.SizeofInotifyEvent * 4096]byte // Buffer for a maximum of 4096 raw events
 | 
			
		||||
		errno error                                // Syscall errno
 | 
			
		||||
	)
 | 
			
		||||
	var buf [unix.SizeofInotifyEvent * 4096]byte // Buffer for a maximum of 4096 raw events
 | 
			
		||||
	for {
 | 
			
		||||
		// See if we have been closed.
 | 
			
		||||
		if w.isClosed() {
 | 
			
		||||
			return
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		n, err := w.inotifyFile.Read(buf[:])
 | 
			
		||||
		switch {
 | 
			
		||||
		case errors.Unwrap(err) == os.ErrClosed:
 | 
			
		||||
			return
 | 
			
		||||
		case err != nil:
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			if errors.Is(err, os.ErrClosed) {
 | 
			
		||||
				return
 | 
			
		||||
			}
 | 
			
		||||
			if !w.sendError(err) {
 | 
			
		||||
				return
 | 
			
		||||
			}
 | 
			
		||||
| 
						 | 
				
			
			@ -440,13 +366,9 @@ func (w *inotify) readEvents() {
 | 
			
		|||
		}
 | 
			
		||||
 | 
			
		||||
		if n < unix.SizeofInotifyEvent {
 | 
			
		||||
			var err error
 | 
			
		||||
			err := errors.New("notify: short read in readEvents()") // Read was too short.
 | 
			
		||||
			if n == 0 {
 | 
			
		||||
				err = io.EOF // If EOF is received. This should really never happen.
 | 
			
		||||
			} else if n < 0 {
 | 
			
		||||
				err = errno // If an error occurred while reading.
 | 
			
		||||
			} else {
 | 
			
		||||
				err = errors.New("notify: short read in readEvents()") // Read was too short.
 | 
			
		||||
			}
 | 
			
		||||
			if !w.sendError(err) {
 | 
			
		||||
				return
 | 
			
		||||
| 
						 | 
				
			
			@ -454,134 +376,137 @@ func (w *inotify) readEvents() {
 | 
			
		|||
			continue
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		// We don't know how many events we just read into the buffer
 | 
			
		||||
		// While the offset points to at least one whole event...
 | 
			
		||||
		// 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 }
 | 
			
		||||
			)
 | 
			
		||||
			// Point to the event in the buffer.
 | 
			
		||||
			inEvent := (*unix.InotifyEvent)(unsafe.Pointer(&buf[offset]))
 | 
			
		||||
 | 
			
		||||
			if mask&unix.IN_Q_OVERFLOW != 0 {
 | 
			
		||||
			if inEvent.Mask&unix.IN_Q_OVERFLOW != 0 {
 | 
			
		||||
				if !w.sendError(ErrEventOverflow) {
 | 
			
		||||
					return
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			/// If the event happened to the watched directory or the watched
 | 
			
		||||
			/// file, the kernel doesn't append the filename to the event, but
 | 
			
		||||
			/// we would like to always fill the the "Name" field with a valid
 | 
			
		||||
			/// filename. We retrieve the path of the watch from the "paths"
 | 
			
		||||
			/// map.
 | 
			
		||||
			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
 | 
			
		||||
			ev, ok := w.handleEvent(inEvent, &buf, offset)
 | 
			
		||||
			if !ok {
 | 
			
		||||
				return
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			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 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 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) {
 | 
			
		||||
						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
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			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()
 | 
			
		||||
 | 
			
		||||
			// Move to the next event in the buffer
 | 
			
		||||
			offset += unix.SizeofInotifyEvent + inEvent.Len
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (w *inotify) handleEvent(inEvent *unix.InotifyEvent, buf *[65536]byte, offset uint32) (Event, bool) {
 | 
			
		||||
	w.mu.Lock()
 | 
			
		||||
	defer w.mu.Unlock()
 | 
			
		||||
 | 
			
		||||
	/// 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.
 | 
			
		||||
	///
 | 
			
		||||
	/// 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.
 | 
			
		||||
	watch := w.watches.byWd(uint32(inEvent.Wd))
 | 
			
		||||
	if watch == nil {
 | 
			
		||||
		return Event{}, true
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	var (
 | 
			
		||||
		name    = watch.path
 | 
			
		||||
		nameLen = uint32(inEvent.Len)
 | 
			
		||||
	)
 | 
			
		||||
	if nameLen > 0 {
 | 
			
		||||
		/// Point "bytes" at the first byte of the filename
 | 
			
		||||
		bb := *buf
 | 
			
		||||
		bytes := (*[unix.PathMax]byte)(unsafe.Pointer(&bb[offset+unix.SizeofInotifyEvent]))[:nameLen:nameLen]
 | 
			
		||||
		/// The filename is padded with NULL bytes. TrimRight() gets rid of those.
 | 
			
		||||
		name += "/" + strings.TrimRight(string(bytes[0:nameLen]), "\x00")
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if debug {
 | 
			
		||||
		internal.Debug(name, inEvent.Mask, inEvent.Cookie)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if inEvent.Mask&unix.IN_IGNORED != 0 || inEvent.Mask&unix.IN_UNMOUNT != 0 {
 | 
			
		||||
		w.watches.remove(watch)
 | 
			
		||||
		return Event{}, true
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// inotify will automatically remove the watch on deletes; just need
 | 
			
		||||
	// to clean our state here.
 | 
			
		||||
	if inEvent.Mask&unix.IN_DELETE_SELF == unix.IN_DELETE_SELF {
 | 
			
		||||
		w.watches.remove(watch)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// 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 inEvent.Mask&unix.IN_MOVE_SELF == unix.IN_MOVE_SELF {
 | 
			
		||||
		if watch.recurse { // Do nothing
 | 
			
		||||
			return Event{}, true
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		err := w.remove(watch.path)
 | 
			
		||||
		if err != nil && !errors.Is(err, ErrNonExistentWatch) {
 | 
			
		||||
			if !w.sendError(err) {
 | 
			
		||||
				return Event{}, false
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/// 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 inEvent.Mask&unix.IN_DELETE_SELF != 0 {
 | 
			
		||||
		_, ok := w.watches.path[filepath.Dir(watch.path)]
 | 
			
		||||
		if ok {
 | 
			
		||||
			return Event{}, true
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	ev := w.newEvent(name, inEvent.Mask, inEvent.Cookie)
 | 
			
		||||
	// Need to update watch path for recurse.
 | 
			
		||||
	if watch.recurse {
 | 
			
		||||
		isDir := inEvent.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 Event{}, false
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			// 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 != "" {
 | 
			
		||||
				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
 | 
			
		||||
					}
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return ev, true
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
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.
 | 
			
		||||
| 
						 | 
				
			
			@ -650,8 +575,8 @@ func (w *inotify) xSupports(op Op) bool {
 | 
			
		|||
}
 | 
			
		||||
 | 
			
		||||
func (w *inotify) state() {
 | 
			
		||||
	w.watches.mu.Lock()
 | 
			
		||||
	defer w.watches.mu.Unlock()
 | 
			
		||||
	w.mu.Lock()
 | 
			
		||||
	defer w.mu.Unlock()
 | 
			
		||||
	for wd, ww := range w.watches.wd {
 | 
			
		||||
		fmt.Fprintf(os.Stderr, "%4d: recurse=%t %q\n", wd, ww.recurse, ww.path)
 | 
			
		||||
	}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										112
									
								
								vendor/github.com/fsnotify/fsnotify/backend_kqueue.go
									
										
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										112
									
								
								vendor/github.com/fsnotify/fsnotify/backend_kqueue.go
									
										
									
										generated
									
									
										vendored
									
									
								
							| 
						 | 
				
			
			@ -16,14 +16,13 @@ import (
 | 
			
		|||
)
 | 
			
		||||
 | 
			
		||||
type kqueue struct {
 | 
			
		||||
	*shared
 | 
			
		||||
	Events chan Event
 | 
			
		||||
	Errors chan error
 | 
			
		||||
 | 
			
		||||
	kq        int    // File descriptor (as returned by the kqueue() syscall).
 | 
			
		||||
	closepipe [2]int // Pipe used for closing kq.
 | 
			
		||||
	watches   *watches
 | 
			
		||||
	done      chan struct{}
 | 
			
		||||
	doneMu    sync.Mutex
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type (
 | 
			
		||||
| 
						 | 
				
			
			@ -132,14 +131,18 @@ func (w *watches) byPath(path string) (watch, bool) {
 | 
			
		|||
	return info, ok
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (w *watches) updateDirFlags(path string, flags uint32) {
 | 
			
		||||
func (w *watches) updateDirFlags(path string, flags uint32) bool {
 | 
			
		||||
	w.mu.Lock()
 | 
			
		||||
	defer w.mu.Unlock()
 | 
			
		||||
 | 
			
		||||
	fd := w.path[path]
 | 
			
		||||
	fd, ok := w.path[path]
 | 
			
		||||
	if !ok { // Already deleted: don't re-set it here.
 | 
			
		||||
		return false
 | 
			
		||||
	}
 | 
			
		||||
	info := w.wd[fd]
 | 
			
		||||
	info.dirFlags = flags
 | 
			
		||||
	w.wd[fd] = info
 | 
			
		||||
	return true
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (w *watches) remove(fd int, path string) bool {
 | 
			
		||||
| 
						 | 
				
			
			@ -179,22 +182,20 @@ func (w *watches) seenBefore(path string) bool {
 | 
			
		|||
	return ok
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func newBackend(ev chan Event, errs chan error) (backend, error) {
 | 
			
		||||
	return newBufferedBackend(0, ev, errs)
 | 
			
		||||
}
 | 
			
		||||
var defaultBufferSize = 0
 | 
			
		||||
 | 
			
		||||
func newBufferedBackend(sz uint, ev chan Event, errs chan error) (backend, error) {
 | 
			
		||||
func newBackend(ev chan Event, errs chan error) (backend, error) {
 | 
			
		||||
	kq, closepipe, err := newKqueue()
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return nil, err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	w := &kqueue{
 | 
			
		||||
		shared:    newShared(ev, errs),
 | 
			
		||||
		Events:    ev,
 | 
			
		||||
		Errors:    errs,
 | 
			
		||||
		kq:        kq,
 | 
			
		||||
		closepipe: closepipe,
 | 
			
		||||
		done:      make(chan struct{}),
 | 
			
		||||
		watches:   newWatches(),
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -210,7 +211,7 @@ func newBufferedBackend(sz uint, ev chan Event, errs chan error) (backend, error
 | 
			
		|||
// all.
 | 
			
		||||
func newKqueue() (kq int, closepipe [2]int, err error) {
 | 
			
		||||
	kq, err = unix.Kqueue()
 | 
			
		||||
	if kq == -1 {
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return kq, closepipe, err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -239,54 +240,17 @@ func newKqueue() (kq int, closepipe [2]int, err error) {
 | 
			
		|||
	return kq, closepipe, nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Returns true if the event was sent, or false if watcher is closed.
 | 
			
		||||
func (w *kqueue) sendEvent(e Event) bool {
 | 
			
		||||
	select {
 | 
			
		||||
	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 *kqueue) sendError(err error) bool {
 | 
			
		||||
	if err == nil {
 | 
			
		||||
		return true
 | 
			
		||||
	}
 | 
			
		||||
	select {
 | 
			
		||||
	case <-w.done:
 | 
			
		||||
		return false
 | 
			
		||||
	case w.Errors <- err:
 | 
			
		||||
		return true
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (w *kqueue) isClosed() bool {
 | 
			
		||||
	select {
 | 
			
		||||
	case <-w.done:
 | 
			
		||||
		return true
 | 
			
		||||
	default:
 | 
			
		||||
		return false
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (w *kqueue) Close() error {
 | 
			
		||||
	w.doneMu.Lock()
 | 
			
		||||
	if w.isClosed() {
 | 
			
		||||
		w.doneMu.Unlock()
 | 
			
		||||
	if w.shared.close() {
 | 
			
		||||
		return nil
 | 
			
		||||
	}
 | 
			
		||||
	close(w.done)
 | 
			
		||||
	w.doneMu.Unlock()
 | 
			
		||||
 | 
			
		||||
	pathsToRemove := w.watches.listPaths(false)
 | 
			
		||||
	for _, name := range pathsToRemove {
 | 
			
		||||
		w.Remove(name)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// Send "quit" message to the reader goroutine.
 | 
			
		||||
	unix.Close(w.closepipe[1])
 | 
			
		||||
	unix.Close(w.closepipe[1]) // Send "quit" message to readEvents
 | 
			
		||||
	return nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -303,7 +267,7 @@ func (w *kqueue) AddWith(name string, opts ...addOpt) error {
 | 
			
		|||
		return fmt.Errorf("%w: %s", xErrUnsupported, with.op)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	_, err := w.addWatch(name, noteAllEvents)
 | 
			
		||||
	_, err := w.addWatch(name, noteAllEvents, false)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return err
 | 
			
		||||
	}
 | 
			
		||||
| 
						 | 
				
			
			@ -366,7 +330,7 @@ const noteAllEvents = unix.NOTE_DELETE | unix.NOTE_WRITE | unix.NOTE_ATTRIB | un
 | 
			
		|||
// described in kevent(2).
 | 
			
		||||
//
 | 
			
		||||
// Returns the real path to the file which was added, with symlinks resolved.
 | 
			
		||||
func (w *kqueue) addWatch(name string, flags uint32) (string, error) {
 | 
			
		||||
func (w *kqueue) addWatch(name string, flags uint32, listDir bool) (string, error) {
 | 
			
		||||
	if w.isClosed() {
 | 
			
		||||
		return "", ErrClosed
 | 
			
		||||
	}
 | 
			
		||||
| 
						 | 
				
			
			@ -385,15 +349,15 @@ func (w *kqueue) addWatch(name string, flags uint32) (string, error) {
 | 
			
		|||
			return "", nil
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		// Follow symlinks.
 | 
			
		||||
		if fi.Mode()&os.ModeSymlink == os.ModeSymlink {
 | 
			
		||||
		// Follow symlinks, but only for paths added with Add(), and not paths
 | 
			
		||||
		// we're adding from internalWatch from a listdir.
 | 
			
		||||
		if !listDir && fi.Mode()&os.ModeSymlink == os.ModeSymlink {
 | 
			
		||||
			link, err := os.Readlink(name)
 | 
			
		||||
			if err != nil {
 | 
			
		||||
				// Return nil because Linux can add unresolvable symlinks to the
 | 
			
		||||
				// watch list without problems, so maintain consistency with
 | 
			
		||||
				// that. There will be no file events for broken symlinks.
 | 
			
		||||
				// TODO: more specific check; returns os.PathError; ENOENT?
 | 
			
		||||
				return "", nil
 | 
			
		||||
				return "", err
 | 
			
		||||
			}
 | 
			
		||||
			if !filepath.IsAbs(link) {
 | 
			
		||||
				link = filepath.Join(filepath.Dir(name), link)
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			_, alreadyWatching = w.watches.byPath(link)
 | 
			
		||||
| 
						 | 
				
			
			@ -408,7 +372,7 @@ func (w *kqueue) addWatch(name string, flags uint32) (string, error) {
 | 
			
		|||
			name = link
 | 
			
		||||
			fi, err = os.Lstat(name)
 | 
			
		||||
			if err != nil {
 | 
			
		||||
				return "", nil
 | 
			
		||||
				return "", err
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -422,7 +386,6 @@ func (w *kqueue) addWatch(name string, flags uint32) (string, error) {
 | 
			
		|||
			if errors.Is(err, unix.EINTR) {
 | 
			
		||||
				continue
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			return "", err
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -444,10 +407,16 @@ func (w *kqueue) addWatch(name string, flags uint32) (string, error) {
 | 
			
		|||
	if info.isDir {
 | 
			
		||||
		watchDir := (flags&unix.NOTE_WRITE) == unix.NOTE_WRITE &&
 | 
			
		||||
			(!alreadyWatching || (info.dirFlags&unix.NOTE_WRITE) != unix.NOTE_WRITE)
 | 
			
		||||
		w.watches.updateDirFlags(name, flags)
 | 
			
		||||
		if !w.watches.updateDirFlags(name, flags) {
 | 
			
		||||
			return "", nil
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		if watchDir {
 | 
			
		||||
			if err := w.watchDirectoryFiles(name); err != nil {
 | 
			
		||||
			d := name
 | 
			
		||||
			if info.linkName != "" {
 | 
			
		||||
				d = info.linkName
 | 
			
		||||
			}
 | 
			
		||||
			if err := w.watchDirectoryFiles(d); err != nil {
 | 
			
		||||
				return "", err
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
| 
						 | 
				
			
			@ -644,19 +613,22 @@ func (w *kqueue) dirChange(dir string) error {
 | 
			
		|||
		if errors.Is(err, os.ErrNotExist) {
 | 
			
		||||
			return nil
 | 
			
		||||
		}
 | 
			
		||||
		return fmt.Errorf("fsnotify.dirChange: %w", err)
 | 
			
		||||
		return fmt.Errorf("fsnotify.dirChange %q: %w", dir, err)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	for _, f := range files {
 | 
			
		||||
		fi, err := f.Info()
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			if errors.Is(err, os.ErrNotExist) {
 | 
			
		||||
				return nil
 | 
			
		||||
			}
 | 
			
		||||
			return fmt.Errorf("fsnotify.dirChange: %w", err)
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		err = w.sendCreateIfNew(filepath.Join(dir, fi.Name()), fi)
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			// Don't need to send an error if this file isn't readable.
 | 
			
		||||
			if errors.Is(err, unix.EACCES) || errors.Is(err, unix.EPERM) {
 | 
			
		||||
			if errors.Is(err, unix.EACCES) || errors.Is(err, unix.EPERM) || errors.Is(err, os.ErrNotExist) {
 | 
			
		||||
				return nil
 | 
			
		||||
			}
 | 
			
		||||
			return fmt.Errorf("fsnotify.dirChange: %w", err)
 | 
			
		||||
| 
						 | 
				
			
			@ -688,11 +660,11 @@ func (w *kqueue) internalWatch(name string, fi os.FileInfo) (string, error) {
 | 
			
		|||
		// mimic Linux providing delete events for subdirectories, but preserve
 | 
			
		||||
		// the flags used if currently watching subdirectory
 | 
			
		||||
		info, _ := w.watches.byPath(name)
 | 
			
		||||
		return w.addWatch(name, info.dirFlags|unix.NOTE_DELETE|unix.NOTE_RENAME)
 | 
			
		||||
		return w.addWatch(name, info.dirFlags|unix.NOTE_DELETE|unix.NOTE_RENAME, true)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// watch file to mimic Linux inotify
 | 
			
		||||
	return w.addWatch(name, noteAllEvents)
 | 
			
		||||
	// Watch file to mimic Linux inotify.
 | 
			
		||||
	return w.addWatch(name, noteAllEvents, true)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Register events with the queue.
 | 
			
		||||
| 
						 | 
				
			
			@ -722,9 +694,9 @@ func (w *kqueue) read(events []unix.Kevent_t) ([]unix.Kevent_t, error) {
 | 
			
		|||
}
 | 
			
		||||
 | 
			
		||||
func (w *kqueue) xSupports(op Op) bool {
 | 
			
		||||
	if runtime.GOOS == "freebsd" {
 | 
			
		||||
		//return true // Supports everything.
 | 
			
		||||
	}
 | 
			
		||||
	//if runtime.GOOS == "freebsd" {
 | 
			
		||||
	//	return true // Supports everything.
 | 
			
		||||
	//}
 | 
			
		||||
	if op.Has(xUnportableOpen) || op.Has(xUnportableRead) ||
 | 
			
		||||
		op.Has(xUnportableCloseWrite) || op.Has(xUnportableCloseRead) {
 | 
			
		||||
		return false
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										5
									
								
								vendor/github.com/fsnotify/fsnotify/backend_other.go
									
										
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										5
									
								
								vendor/github.com/fsnotify/fsnotify/backend_other.go
									
										
									
										generated
									
									
										vendored
									
									
								
							| 
						 | 
				
			
			@ -9,12 +9,11 @@ type other struct {
 | 
			
		|||
	Errors chan error
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
var defaultBufferSize = 0
 | 
			
		||||
 | 
			
		||||
func newBackend(ev chan Event, errs chan error) (backend, error) {
 | 
			
		||||
	return nil, errors.New("fsnotify not supported on the current platform")
 | 
			
		||||
}
 | 
			
		||||
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 }
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										24
									
								
								vendor/github.com/fsnotify/fsnotify/backend_windows.go
									
										
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										24
									
								
								vendor/github.com/fsnotify/fsnotify/backend_windows.go
									
										
									
										generated
									
									
										vendored
									
									
								
							| 
						 | 
				
			
			@ -28,18 +28,16 @@ type readDirChangesW struct {
 | 
			
		|||
 | 
			
		||||
	port  windows.Handle // Handle to completion port
 | 
			
		||||
	input chan *input    // Inputs to the reader are sent on this channel
 | 
			
		||||
	quit  chan chan<- error
 | 
			
		||||
	done  chan chan<- error
 | 
			
		||||
 | 
			
		||||
	mu      sync.Mutex // Protects access to watches, closed
 | 
			
		||||
	watches watchMap   // Map of watches (key: i-number)
 | 
			
		||||
	closed  bool       // Set to true when Close() is first called
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func newBackend(ev chan Event, errs chan error) (backend, error) {
 | 
			
		||||
	return newBufferedBackend(50, ev, errs)
 | 
			
		||||
}
 | 
			
		||||
var defaultBufferSize = 50
 | 
			
		||||
 | 
			
		||||
func newBufferedBackend(sz uint, ev chan Event, errs chan error) (backend, error) {
 | 
			
		||||
func newBackend(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)
 | 
			
		||||
| 
						 | 
				
			
			@ -50,7 +48,7 @@ func newBufferedBackend(sz uint, ev chan Event, errs chan error) (backend, error
 | 
			
		|||
		port:    port,
 | 
			
		||||
		watches: make(watchMap),
 | 
			
		||||
		input:   make(chan *input, 1),
 | 
			
		||||
		quit:    make(chan chan<- error, 1),
 | 
			
		||||
		done:    make(chan chan<- error, 1),
 | 
			
		||||
	}
 | 
			
		||||
	go w.readEvents()
 | 
			
		||||
	return w, nil
 | 
			
		||||
| 
						 | 
				
			
			@ -70,8 +68,8 @@ func (w *readDirChangesW) sendEvent(name, renamedFrom string, mask uint64) bool
 | 
			
		|||
	event := w.newEvent(name, uint32(mask))
 | 
			
		||||
	event.renamedFrom = renamedFrom
 | 
			
		||||
	select {
 | 
			
		||||
	case ch := <-w.quit:
 | 
			
		||||
		w.quit <- ch
 | 
			
		||||
	case ch := <-w.done:
 | 
			
		||||
		w.done <- ch
 | 
			
		||||
	case w.Events <- event:
 | 
			
		||||
	}
 | 
			
		||||
	return true
 | 
			
		||||
| 
						 | 
				
			
			@ -83,10 +81,10 @@ func (w *readDirChangesW) sendError(err error) bool {
 | 
			
		|||
		return true
 | 
			
		||||
	}
 | 
			
		||||
	select {
 | 
			
		||||
	case <-w.done:
 | 
			
		||||
		return false
 | 
			
		||||
	case w.Errors <- err:
 | 
			
		||||
		return true
 | 
			
		||||
	case <-w.quit:
 | 
			
		||||
		return false
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -99,9 +97,9 @@ func (w *readDirChangesW) Close() error {
 | 
			
		|||
	w.closed = true
 | 
			
		||||
	w.mu.Unlock()
 | 
			
		||||
 | 
			
		||||
	// Send "quit" message to the reader goroutine
 | 
			
		||||
	// Send "done" message to the reader goroutine
 | 
			
		||||
	ch := make(chan error)
 | 
			
		||||
	w.quit <- ch
 | 
			
		||||
	w.done <- ch
 | 
			
		||||
	if err := w.wakeupReader(); err != nil {
 | 
			
		||||
		return err
 | 
			
		||||
	}
 | 
			
		||||
| 
						 | 
				
			
			@ -495,7 +493,7 @@ func (w *readDirChangesW) readEvents() {
 | 
			
		|||
		watch := (*watch)(unsafe.Pointer(ov))
 | 
			
		||||
		if watch == nil {
 | 
			
		||||
			select {
 | 
			
		||||
			case ch := <-w.quit:
 | 
			
		||||
			case ch := <-w.done:
 | 
			
		||||
				w.mu.Lock()
 | 
			
		||||
				var indexes []indexMap
 | 
			
		||||
				for _, index := range w.watches {
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										10
									
								
								vendor/github.com/fsnotify/fsnotify/fsnotify.go
									
										
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										10
									
								
								vendor/github.com/fsnotify/fsnotify/fsnotify.go
									
										
									
										generated
									
									
										vendored
									
									
								
							| 
						 | 
				
			
			@ -244,12 +244,13 @@ var (
 | 
			
		|||
 | 
			
		||||
	// ErrUnsupported is returned by AddWith() when WithOps() specified an
 | 
			
		||||
	// Unportable event that's not supported on this platform.
 | 
			
		||||
	//lint:ignore ST1012 not relevant
 | 
			
		||||
	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)
 | 
			
		||||
	ev, errs := make(chan Event, defaultBufferSize), make(chan error)
 | 
			
		||||
	b, err := newBackend(ev, errs)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return nil, err
 | 
			
		||||
| 
						 | 
				
			
			@ -266,8 +267,8 @@ func NewWatcher() (*Watcher, error) {
 | 
			
		|||
// 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)
 | 
			
		||||
	ev, errs := make(chan Event, sz), make(chan error)
 | 
			
		||||
	b, err := newBackend(ev, errs)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return nil, err
 | 
			
		||||
	}
 | 
			
		||||
| 
						 | 
				
			
			@ -337,7 +338,8 @@ 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.
 | 
			
		||||
// The order is undefined, and may differ per call. 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.
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										6
									
								
								vendor/github.com/fsnotify/fsnotify/internal/darwin.go
									
										
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										6
									
								
								vendor/github.com/fsnotify/fsnotify/internal/darwin.go
									
										
									
										generated
									
									
										vendored
									
									
								
							| 
						 | 
				
			
			@ -9,14 +9,14 @@ import (
 | 
			
		|||
)
 | 
			
		||||
 | 
			
		||||
var (
 | 
			
		||||
	SyscallEACCES = syscall.EACCES
 | 
			
		||||
	UnixEACCES    = unix.EACCES
 | 
			
		||||
	ErrSyscallEACCES = syscall.EACCES
 | 
			
		||||
	ErrUnixEACCES    = unix.EACCES
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
var maxfiles uint64
 | 
			
		||||
 | 
			
		||||
// Go 1.19 will do this automatically: https://go-review.googlesource.com/c/go/+/393354/
 | 
			
		||||
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 {
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										4
									
								
								vendor/github.com/fsnotify/fsnotify/internal/freebsd.go
									
										
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										4
									
								
								vendor/github.com/fsnotify/fsnotify/internal/freebsd.go
									
										
									
										generated
									
									
										vendored
									
									
								
							| 
						 | 
				
			
			@ -9,8 +9,8 @@ import (
 | 
			
		|||
)
 | 
			
		||||
 | 
			
		||||
var (
 | 
			
		||||
	SyscallEACCES = syscall.EACCES
 | 
			
		||||
	UnixEACCES    = unix.EACCES
 | 
			
		||||
	ErrSyscallEACCES = syscall.EACCES
 | 
			
		||||
	ErrUnixEACCES    = unix.EACCES
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
var maxfiles uint64
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										6
									
								
								vendor/github.com/fsnotify/fsnotify/internal/unix.go
									
										
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										6
									
								
								vendor/github.com/fsnotify/fsnotify/internal/unix.go
									
										
									
										generated
									
									
										vendored
									
									
								
							| 
						 | 
				
			
			@ -1,4 +1,4 @@
 | 
			
		|||
//go:build !windows && !darwin && !freebsd
 | 
			
		||||
//go:build !windows && !darwin && !freebsd && !plan9
 | 
			
		||||
 | 
			
		||||
package internal
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -9,8 +9,8 @@ import (
 | 
			
		|||
)
 | 
			
		||||
 | 
			
		||||
var (
 | 
			
		||||
	SyscallEACCES = syscall.EACCES
 | 
			
		||||
	UnixEACCES    = unix.EACCES
 | 
			
		||||
	ErrSyscallEACCES = syscall.EACCES
 | 
			
		||||
	ErrUnixEACCES    = unix.EACCES
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
var maxfiles uint64
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										4
									
								
								vendor/github.com/fsnotify/fsnotify/internal/windows.go
									
										
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										4
									
								
								vendor/github.com/fsnotify/fsnotify/internal/windows.go
									
										
									
										generated
									
									
										vendored
									
									
								
							| 
						 | 
				
			
			@ -10,8 +10,8 @@ import (
 | 
			
		|||
 | 
			
		||||
// Just a dummy.
 | 
			
		||||
var (
 | 
			
		||||
	SyscallEACCES = errors.New("dummy")
 | 
			
		||||
	UnixEACCES    = errors.New("dummy")
 | 
			
		||||
	ErrSyscallEACCES = errors.New("dummy")
 | 
			
		||||
	ErrUnixEACCES    = errors.New("dummy")
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
func SetRlimit()                                    {}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										64
									
								
								vendor/github.com/fsnotify/fsnotify/shared.go
									
										
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										64
									
								
								vendor/github.com/fsnotify/fsnotify/shared.go
									
										
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,64 @@
 | 
			
		|||
package fsnotify
 | 
			
		||||
 | 
			
		||||
import "sync"
 | 
			
		||||
 | 
			
		||||
type shared struct {
 | 
			
		||||
	Events chan Event
 | 
			
		||||
	Errors chan error
 | 
			
		||||
	done   chan struct{}
 | 
			
		||||
	mu     sync.Mutex
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func newShared(ev chan Event, errs chan error) *shared {
 | 
			
		||||
	return &shared{
 | 
			
		||||
		Events: ev,
 | 
			
		||||
		Errors: errs,
 | 
			
		||||
		done:   make(chan struct{}),
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Returns true if the event was sent, or false if watcher is closed.
 | 
			
		||||
func (w *shared) sendEvent(e Event) bool {
 | 
			
		||||
	if e.Op == 0 {
 | 
			
		||||
		return true
 | 
			
		||||
	}
 | 
			
		||||
	select {
 | 
			
		||||
	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 *shared) sendError(err error) bool {
 | 
			
		||||
	if err == nil {
 | 
			
		||||
		return true
 | 
			
		||||
	}
 | 
			
		||||
	select {
 | 
			
		||||
	case <-w.done:
 | 
			
		||||
		return false
 | 
			
		||||
	case w.Errors <- err:
 | 
			
		||||
		return true
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (w *shared) isClosed() bool {
 | 
			
		||||
	select {
 | 
			
		||||
	case <-w.done:
 | 
			
		||||
		return true
 | 
			
		||||
	default:
 | 
			
		||||
		return false
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Mark as closed; returns true if it was already closed.
 | 
			
		||||
func (w *shared) close() bool {
 | 
			
		||||
	w.mu.Lock()
 | 
			
		||||
	defer w.mu.Unlock()
 | 
			
		||||
	if w.isClosed() {
 | 
			
		||||
		return true
 | 
			
		||||
	}
 | 
			
		||||
	close(w.done)
 | 
			
		||||
	return false
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										3
									
								
								vendor/github.com/fsnotify/fsnotify/staticcheck.conf
									
										
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										3
									
								
								vendor/github.com/fsnotify/fsnotify/staticcheck.conf
									
										
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,3 @@
 | 
			
		|||
checks = ['all',
 | 
			
		||||
	'-U1000',  # Don't complain about unused functions.
 | 
			
		||||
]
 | 
			
		||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue