Update dependencies

This commit is contained in:
bluepython508
2025-04-09 01:00:12 +01:00
parent f0641ffd6e
commit 5a9cfc022c
882 changed files with 68930 additions and 24201 deletions

8
vendor/github.com/illarion/gonotify/v3/.gitignore generated vendored Normal file
View File

@@ -0,0 +1,8 @@
*.so
*.dylib
# Test binary, build with `go test -c`
*.test
# Output of the go coverage tool, specifically when used with LiteIDE
*.out

21
vendor/github.com/illarion/gonotify/v3/LICENSE generated vendored Normal file
View File

@@ -0,0 +1,21 @@
MIT License
Copyright (c) 2018-2023 Ilarion Kovalchuk
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

71
vendor/github.com/illarion/gonotify/v3/README.md generated vendored Normal file
View File

@@ -0,0 +1,71 @@
## Gonotify
Simple Golang inotify wrapper.
[![GoDoc](https://godoc.org/github.com/illarion/gonotify/v3?status.svg)](https://godoc.org/github.com/illarion/gonotify/v3)
### Provides following primitives:
* Low level
* `Inotify` - wrapper around [inotify(7)](http://man7.org/linux/man-pages/man7/inotify.7.html)
* `InotifyEvent` - generated file/folder event. Contains `Name` (full path), `Wd` - watch descriptor and `Mask` that describes the event.
* Higher level
* `FileWatcher` - higher level utility, helps to watch the list of files for changes, creation or removal
* `DirWatcher` - higher level utility, recursively watches given root folder for added, removed or changed files.
* `FileEvent` - embeds `InotifyEvent` and keeps additional field `Eof` to notify user that there will be no more events.
Use `FileWatcher` and `DirWatcher` as an example and build your own utility classes.
### Usage
```go
package main
import (
"fmt"
"github.com/illarion/gonotify/v3"
"time"
"context"
)
func main() {
ctx, cancel := context.WithCancel(context.Background())
watcher, err := gonotify.NewDirWatcher(ctx, gonotify.IN_CREATE|gonotify.IN_CLOSE, "/tmp")
if err != nil {
panic(err)
}
main:
for {
select {
case event := <-watcher.C:
fmt.Printf("Event: %s\n", event)
if event.Is(gonotify.IN_CREATE) {
fmt.Printf("File created: %s\n", event.Name)
}
if event.IsAny(gonotify.IN_CLOSE, gonotify.IN_CLOSE_WRITE) {
fmt.Printf("File closed: %s\n", event.Name)
}
case <-time.After(5 * time.Second):
fmt.Println("Good bye!")
cancel()
break main
}
}
// Wait for watcher to finish all internal goroutines
<-watcher.Done()
fmt.Println("Watcher is done")
}
```
## License
MIT. See [LICENSE](LICENSE) file for more details.

218
vendor/github.com/illarion/gonotify/v3/dirwatcher.go generated vendored Normal file
View File

@@ -0,0 +1,218 @@
package gonotify
import (
"context"
"os"
"path/filepath"
"sync"
)
// DirWatcher recursively watches the given root folder, waiting for file events.
// Events can be masked by providing fileMask. DirWatcher does not generate events for
// folders or subfolders.
type DirWatcher struct {
C chan FileEvent
done chan struct{}
}
// NewDirWatcher creates DirWatcher recursively waiting for events in the given root folder and
// emitting FileEvents in channel C, that correspond to fileMask. Folder events are ignored (having IN_ISDIR set to 1)
func NewDirWatcher(ctx context.Context, fileMask uint32, root string) (*DirWatcher, error) {
dw := &DirWatcher{
C: make(chan FileEvent),
done: make(chan struct{}),
}
i, err := NewInotify(ctx)
if err != nil {
return nil, err
}
queue := make([]FileEvent, 0, 100)
err = filepath.Walk(root, func(path string, f os.FileInfo, err error) error {
if err != nil {
return nil
}
if !f.IsDir() {
//fake event for existing files
queue = append(queue, FileEvent{
InotifyEvent: InotifyEvent{
Name: path,
Mask: IN_CREATE,
},
})
return nil
}
_, err = i.AddWatch(path, IN_ALL_EVENTS)
return err
})
if err != nil {
return nil, err
}
events := make(chan FileEvent)
wg := sync.WaitGroup{}
wg.Add(1)
go func() {
defer wg.Done()
for _, event := range queue {
select {
case <-ctx.Done():
close(events)
return
case events <- event:
}
}
queue = nil
for {
select {
case <-ctx.Done():
close(events)
return
default:
}
raw, err := i.Read()
if err != nil {
close(events)
return
}
select {
case <-ctx.Done():
close(events)
return
default:
}
for _, event := range raw {
// Skip ignored events queued from removed watchers
if event.Mask&IN_IGNORED == IN_IGNORED {
continue
}
// Add watch for folders created in watched folders (recursion)
if event.Mask&(IN_CREATE|IN_ISDIR) == IN_CREATE|IN_ISDIR {
// After the watch for subfolder is added, it may be already late to detect files
// created there right after subfolder creation, so we should generate such events
// ourselves:
filepath.Walk(event.Name, func(path string, f os.FileInfo, err error) error {
if err != nil {
return nil
}
if !f.IsDir() {
// fake event, but there can be duplicates of this event provided by real watcher
select {
case <-ctx.Done():
return nil
case events <- FileEvent{
InotifyEvent: InotifyEvent{
Name: path,
Mask: IN_CREATE,
},
}: //noop
}
}
return nil
})
// Wait for further files to be added
i.AddWatch(event.Name, IN_ALL_EVENTS)
continue
}
// Remove watch for deleted folders
if event.Mask&IN_DELETE_SELF == IN_DELETE_SELF {
i.RmWd(event.Wd)
continue
}
// Skip sub-folder events
if event.Mask&IN_ISDIR == IN_ISDIR {
continue
}
select {
case <-ctx.Done():
return
case events <- FileEvent{
InotifyEvent: event,
}: //noop
}
}
}
}()
wg.Add(1)
go func() {
defer wg.Done()
defer close(dw.C)
for {
select {
case <-ctx.Done():
// drain events
for {
select {
case _, ok := <-events:
if !ok {
return
}
default:
return
}
}
case event, ok := <-events:
if !ok {
select {
case <-ctx.Done():
case dw.C <- FileEvent{
Eof: true,
}:
}
return
}
// Skip events not conforming with provided mask
if event.Mask&fileMask == 0 {
continue
}
select {
case dw.C <- event:
case <-ctx.Done():
return
}
}
}
}()
go func() {
wg.Wait()
<-i.Done()
close(dw.done)
}()
return dw, nil
}
// Done returns a channel that is closed when DirWatcher is done
func (dw *DirWatcher) Done() <-chan struct{} {
return dw.done
}

138
vendor/github.com/illarion/gonotify/v3/event.go generated vendored Normal file
View File

@@ -0,0 +1,138 @@
//go:build linux
// +build linux
package gonotify
import (
"fmt"
"strings"
"syscall"
)
const (
IN_ACCESS = uint32(syscall.IN_ACCESS) // File was accessed
IN_ATTRIB = uint32(syscall.IN_ATTRIB) // Metadata changed
IN_CLOSE_WRITE = uint32(syscall.IN_CLOSE_WRITE) // File opened for writing was closed.
IN_CLOSE_NOWRITE = uint32(syscall.IN_CLOSE_NOWRITE) // File or directory not opened for writing was closed.
IN_CREATE = uint32(syscall.IN_CREATE) // File/directory created in watched directory
IN_DELETE = uint32(syscall.IN_DELETE) // File/directory deleted from watched directory.
IN_DELETE_SELF = uint32(syscall.IN_DELETE_SELF) // Watched file/directory was itself deleted.
IN_MODIFY = uint32(syscall.IN_MODIFY) // File was modified
IN_MOVE_SELF = uint32(syscall.IN_MOVE_SELF) // Watched file/directory was itself moved.
IN_MOVED_FROM = uint32(syscall.IN_MOVED_FROM) // Generated for the directory containing the old filename when a file is renamed.
IN_MOVED_TO = uint32(syscall.IN_MOVED_TO) // Generated for the directory containing the new filename when a file is renamed.
IN_OPEN = uint32(syscall.IN_OPEN) // File or directory was opened.
IN_ALL_EVENTS = uint32(syscall.IN_ALL_EVENTS) // bit mask of all of the above events.
IN_MOVE = uint32(syscall.IN_MOVE) // Equates to IN_MOVED_FROM | IN_MOVED_TO.
IN_CLOSE = uint32(syscall.IN_CLOSE) // Equates to IN_CLOSE_WRITE | IN_CLOSE_NOWRITE.
/* The following further bits can be specified in mask when calling Inotify.AddWatch() */
IN_DONT_FOLLOW = uint32(syscall.IN_DONT_FOLLOW) // Don't dereference pathname if it is a symbolic link.
IN_EXCL_UNLINK = uint32(syscall.IN_EXCL_UNLINK) // Don't generate events for children if they have been unlinked from the directory.
IN_MASK_ADD = uint32(syscall.IN_MASK_ADD) // Add (OR) the events in mask to the watch mask
IN_ONESHOT = uint32(syscall.IN_ONESHOT) // Monitor the filesystem object corresponding to pathname for one event, then remove from watch list.
IN_ONLYDIR = uint32(syscall.IN_ONLYDIR) // Watch pathname only if it is a directory.
/* The following bits may be set in the mask field returned by Inotify.Read() */
IN_IGNORED = uint32(syscall.IN_IGNORED) // Watch was removed explicitly or automatically
IN_ISDIR = uint32(syscall.IN_ISDIR) // Subject of this event is a directory.
IN_Q_OVERFLOW = uint32(syscall.IN_Q_OVERFLOW) // Event queue overflowed (wd is -1 for this event).
IN_UNMOUNT = uint32(syscall.IN_UNMOUNT) // Filesystem containing watched object was unmounted.
)
var in_mapping = map[uint32]string{
IN_ACCESS: "IN_ACCESS",
IN_ATTRIB: "IN_ATTRIB",
IN_CLOSE_WRITE: "IN_CLOSE_WRITE",
IN_CLOSE_NOWRITE: "IN_CLOSE_NOWRITE",
IN_CREATE: "IN_CREATE",
IN_DELETE: "IN_DELETE",
IN_DELETE_SELF: "IN_DELETE_SELF",
IN_MODIFY: "IN_MODIFY",
IN_MOVE_SELF: "IN_MOVE_SELF",
IN_MOVED_FROM: "IN_MOVED_FROM",
IN_MOVED_TO: "IN_MOVED_TO",
IN_OPEN: "IN_OPEN",
IN_IGNORED: "IN_IGNORED",
IN_ISDIR: "IN_ISDIR",
IN_Q_OVERFLOW: "IN_Q_OVERFLOW",
IN_UNMOUNT: "IN_UNMOUNT",
}
func InMaskToString(in_mask uint32) string {
sb := &strings.Builder{}
divide := false
for mask, str := range in_mapping {
if in_mask&mask == mask {
if divide {
sb.WriteString("|")
}
sb.WriteString(str)
divide = true
}
}
return sb.String()
}
// InotifyEvent is the go representation of inotify_event found in sys/inotify.h
type InotifyEvent struct {
// Watch descriptor
Wd int
// File or directory name
Name string
// Contains bits that describe the event that occurred
Mask uint32
// Usually 0, but if events (like IN_MOVED_FROM and IN_MOVED_TO) are linked then they will have equal cookie
Cookie uint32
}
func (i InotifyEvent) GoString() string {
return fmt.Sprintf("gonotify.InotifyEvent{Wd=%#v, Name=%s, Cookie=%#v, Mask=%#v=%s}", i.Wd, i.Name, i.Cookie, i.Mask, InMaskToString(i.Mask))
}
func (i InotifyEvent) String() string {
return fmt.Sprintf("{Wd=%d, Name=%s, Cookie=%d, Mask=%s}", i.Wd, i.Name, i.Cookie, InMaskToString(i.Mask))
}
// IsAny returns true if any of the in_mask is set in the event
func (i InotifyEvent) IsAny(in_mask ...uint32) bool {
for _, mask := range in_mask {
if i.Mask&mask == mask {
return true
}
}
return false
}
// IsAll returns true if all the in_masks is set in the event
func (i InotifyEvent) IsAll(in_mask ...uint32) bool {
for _, mask := range in_mask {
if i.Mask&mask != mask {
return false
}
}
return true
}
func (i InotifyEvent) Is(in_mask uint32) bool {
return i.Mask&in_mask == in_mask
}
// FileEvent is the wrapper around InotifyEvent with additional Eof marker. Reading from
// FileEvents from DirWatcher.C or FileWatcher.C may end with Eof when underlying inotify is closed
type FileEvent struct {
InotifyEvent
Eof bool
}
func (f FileEvent) GoString() string {
return fmt.Sprintf("gonotify.FileEvent{InotifyEvent=%#v, Eof=%#v}", f.InotifyEvent, f.Eof)
}
func (f FileEvent) String() string {
return fmt.Sprintf("{InotifyEvent=%s, Eof=%v}", f.InotifyEvent, f.Eof)
}

115
vendor/github.com/illarion/gonotify/v3/filewatcher.go generated vendored Normal file
View File

@@ -0,0 +1,115 @@
package gonotify
import (
"context"
"path/filepath"
"sync"
)
// FileWatcher waits for events generated by filesystem for a specific list of file paths, including
// IN_CREATE for not yet existing files and IN_DELETE for removed.
type FileWatcher struct {
C chan FileEvent
done chan struct{}
}
// NewFileWatcher creates FileWatcher with provided inotify mask and list of files to wait events for.
func NewFileWatcher(ctx context.Context, mask uint32, files ...string) (*FileWatcher, error) {
f := &FileWatcher{
C: make(chan FileEvent),
done: make(chan struct{}),
}
inotify, err := NewInotify(ctx)
if err != nil {
return nil, err
}
expectedPaths := make(map[string]bool)
for _, file := range files {
_, err := inotify.AddWatch(filepath.Dir(file), mask)
if err != nil {
return nil, err
}
expectedPaths[file] = true
}
events := make(chan FileEvent)
wg := sync.WaitGroup{}
wg.Add(1)
go func() {
defer wg.Done()
for {
select {
case <-ctx.Done():
close(events)
return
default:
}
raw, err := inotify.Read()
if err != nil {
close(events)
return
}
for _, event := range raw {
select {
case <-ctx.Done():
return
case events <- FileEvent{
InotifyEvent: event,
}: //noop
}
}
}
}()
wg.Add(1)
go func() {
defer wg.Done()
defer close(f.C)
for {
select {
case <-ctx.Done():
return
case event, ok := <-events:
if !ok {
select {
case <-ctx.Done():
case f.C <- FileEvent{Eof: true}:
}
return
}
if !expectedPaths[event.Name] {
continue
}
select {
case <-ctx.Done():
return
case f.C <- event:
}
}
}
}()
go func() {
<-inotify.Done()
wg.Wait()
close(f.done)
}()
return f, nil
}
// Done returns a channel that is closed when the FileWatcher is done.
func (f *FileWatcher) Done() <-chan struct{} {
return f.done
}

527
vendor/github.com/illarion/gonotify/v3/inotify.go generated vendored Normal file
View File

@@ -0,0 +1,527 @@
//go:build linux
// +build linux
package gonotify
import (
"context"
"errors"
"os"
"path/filepath"
"strings"
"sync"
"syscall"
"time"
"unsafe"
"github.com/illarion/gonotify/v3/syscallf"
)
const (
// maxEvents is the maximum number of events to read in one syscall
maxEvents = 1024
)
type addWatchResult struct {
wd int
err error
}
type addWatchRequest struct {
pathName string
mask uint32
result chan addWatchResult
}
type rmWdRequest struct {
wd int
ignored bool // if true, the watch was removed automatically
result chan error
}
type rmPathRequest struct {
pathName string
result chan error
}
type eventItem struct {
InotifyEvent
err error
}
// Inotify is the low level wrapper around inotify_init(), inotify_add_watch() and inotify_rm_watch()
type Inotify struct {
ctx context.Context
done chan struct{}
addWatchIn chan addWatchRequest
rmByWdIn chan rmWdRequest
rmByPathIn chan rmPathRequest
eventsOut chan eventItem
readMutex sync.Mutex
}
// NewInotify creates new inotify instance
func NewInotify(ctx context.Context) (*Inotify, error) {
fd, err := syscall.InotifyInit1(syscall.IN_CLOEXEC | syscall.IN_NONBLOCK)
if err != nil {
return nil, err
}
file := os.NewFile(uintptr(fd), "inotify")
inotify := &Inotify{
ctx: ctx,
done: make(chan struct{}),
addWatchIn: make(chan addWatchRequest),
rmByWdIn: make(chan rmWdRequest),
rmByPathIn: make(chan rmPathRequest),
eventsOut: make(chan eventItem, maxEvents),
}
type getPathRequest struct {
wd int
result chan string
}
getPathIn := make(chan getPathRequest)
wg := sync.WaitGroup{}
wg.Add(1)
go func() {
//defer cancel()
<-ctx.Done()
//file.Close()
wg.Done()
}()
wg.Add(1)
// read events goroutine. Only this goroutine can read or close the inotify file descriptor
go func() {
defer wg.Done()
defer close(inotify.eventsOut)
// reusable buffers for reading inotify events. Make sure they're not
// leaked into other goroutines, as they're not thread safe
buf := make([]byte, maxEvents*(syscall.SizeofInotifyEvent+syscall.NAME_MAX+1))
for {
select {
case <-ctx.Done():
return
default:
}
var n int
for {
select {
case <-ctx.Done():
return
default:
}
n, err = file.Read(buf)
if err != nil {
// if we got an error, we should return
select {
case inotify.eventsOut <- eventItem{
InotifyEvent: InotifyEvent{},
err: err,
}:
default:
}
return
}
if n > 0 {
break
}
}
if n < syscall.SizeofInotifyEvent {
select {
case <-ctx.Done():
return
default:
continue
}
}
offset := 0
for offset+syscall.SizeofInotifyEvent <= n {
event := (*syscall.InotifyEvent)(unsafe.Pointer(&buf[offset]))
var name string
{
nameStart := offset + syscall.SizeofInotifyEvent
nameEnd := offset + syscall.SizeofInotifyEvent + int(event.Len)
if nameEnd > n {
continue
}
name = strings.TrimRight(string(buf[nameStart:nameEnd]), "\x00")
offset = nameEnd
}
req := getPathRequest{wd: int(event.Wd), result: make(chan string)}
var watchName string
select {
case <-ctx.Done():
return
case getPathIn <- req:
select {
case <-ctx.Done():
return
case watchName = <-req.result:
}
}
if watchName == "" {
continue
}
name = filepath.Join(watchName, name)
inotifyEvent := InotifyEvent{
Wd: int(event.Wd),
Name: name,
Mask: event.Mask,
Cookie: event.Cookie,
}
// watch was removed explicitly or automatically
if inotifyEvent.Is(IN_IGNORED) {
// remove watch
result := make(chan error)
select {
case <-ctx.Done():
return
case inotify.rmByWdIn <- rmWdRequest{
wd: int(event.Wd),
ignored: true,
result: result,
}:
case <-time.After(1 * time.Second):
}
select {
case <-ctx.Done():
return
case err := <-result:
if err != nil {
// TODO log error
}
}
continue
}
select {
case <-ctx.Done():
return
case inotify.eventsOut <- eventItem{
InotifyEvent: inotifyEvent,
err: nil,
}:
}
}
}
}()
wg.Add(1)
// main goroutine (handle channels)
go func() {
//defer cancel()
defer wg.Done()
watches := make(map[string]int)
paths := make(map[int]string)
for {
select {
case <-ctx.Done():
// Handle pending requests
draining := true
for draining {
select {
case req := <-inotify.addWatchIn:
// Send error to addWatch requests
select {
case req.result <- addWatchResult{
wd: 0,
err: errors.New("Inotify instance closed"),
}:
default:
}
case <-inotify.rmByWdIn:
case <-inotify.addWatchIn:
case <-inotify.rmByPathIn:
case <-getPathIn:
default:
draining = false
}
}
for _, w := range watches {
_, err := syscallf.InotifyRmWatch(fd, w)
if err != nil {
continue
}
}
return
case req := <-inotify.addWatchIn:
wd, err := syscall.InotifyAddWatch(fd, req.pathName, req.mask)
if err == nil {
watches[req.pathName] = wd
paths[wd] = req.pathName
}
select {
case req.result <- addWatchResult{wd: wd, err: err}:
case <-ctx.Done():
}
case req := <-inotify.rmByWdIn:
pathName, ok := paths[req.wd]
if !ok {
continue
}
if !req.ignored {
_, err = syscallf.InotifyRmWatch(fd, req.wd)
}
delete(watches, pathName)
delete(paths, req.wd)
select {
case req.result <- err:
case <-ctx.Done():
}
case req := <-inotify.rmByPathIn:
wd, ok := watches[req.pathName]
if !ok {
continue
}
_, err := syscallf.InotifyRmWatch(fd, wd)
delete(watches, req.pathName)
delete(paths, wd)
select {
case req.result <- err:
case <-ctx.Done():
}
case req := <-getPathIn:
wd := paths[req.wd]
select {
case req.result <- wd:
case <-ctx.Done():
}
}
}
}()
go func() {
//defer cancel()
wg.Wait()
close(inotify.done)
}()
return inotify, nil
}
// Done returns a channel that is closed when Inotify is done
func (i *Inotify) Done() <-chan struct{} {
return i.done
}
// AddWatch adds given path to list of watched files / folders
func (i *Inotify) AddWatch(pathName string, mask uint32) (int, error) {
req := addWatchRequest{
pathName: pathName,
mask: mask,
result: make(chan addWatchResult),
}
select {
case <-i.ctx.Done():
return 0, i.ctx.Err()
case i.addWatchIn <- req:
select {
case <-i.ctx.Done():
return 0, i.ctx.Err()
case result := <-req.result:
return result.wd, result.err
}
}
}
// RmWd removes watch by watch descriptor
func (i *Inotify) RmWd(wd int) error {
req := rmWdRequest{
wd: wd,
ignored: false,
result: make(chan error),
}
select {
case <-i.ctx.Done():
return i.ctx.Err()
case i.rmByWdIn <- req:
}
select {
case <-i.ctx.Done():
return i.ctx.Err()
case err := <-req.result:
return err
}
}
// RmWatch removes watch by pathName
func (i *Inotify) RmWatch(pathName string) error {
req := rmPathRequest{
pathName: pathName,
result: make(chan error),
}
select {
case <-i.ctx.Done():
return i.ctx.Err()
case i.rmByPathIn <- req:
}
select {
case <-i.ctx.Done():
return i.ctx.Err()
case err := <-req.result:
return err
}
}
// Read reads portion of InotifyEvents and may fail with an error. If no events are available, it will
// wait forever, until context is cancelled.
func (i *Inotify) Read() ([]InotifyEvent, error) {
i.readMutex.Lock()
defer i.readMutex.Unlock()
events := make([]InotifyEvent, 0, maxEvents)
select {
case <-i.ctx.Done():
return events, i.ctx.Err()
case <-i.Done():
return events, errors.New("inotify closed")
case evt, ok := <-i.eventsOut:
if !ok {
return events, errors.New("inotify closed")
}
if evt.err != nil {
return events, evt.err
}
if evt.InotifyEvent.Wd != 0 {
// append first event
events = append(events, evt.InotifyEvent)
}
if len(events) >= maxEvents {
return events, nil
}
// read all available events
read:
for {
select {
case <-i.ctx.Done():
return events, i.ctx.Err()
case <-i.Done():
return events, errors.New("inotify closed")
case evt, ok := <-i.eventsOut:
if !ok {
return events, errors.New("inotify closed")
}
if evt.err != nil {
return events, evt.err
}
if evt.InotifyEvent.Wd != 0 {
// append event
events = append(events, evt.InotifyEvent)
}
if len(events) >= maxEvents {
return events, nil
}
default:
break read
}
}
}
return events, nil
}
// ReadDeadline waits for InotifyEvents until deadline is reached, or context is cancelled. If
// deadline is reached, it will return all events read until that point.
func (i *Inotify) ReadDeadline(deadline time.Time) ([]InotifyEvent, error) {
i.readMutex.Lock()
defer i.readMutex.Unlock()
events := make([]InotifyEvent, 0, maxEvents)
for {
select {
case <-i.ctx.Done():
return events, i.ctx.Err()
case <-i.Done():
return events, errors.New("Inotify closed")
case <-time.After(time.Until(deadline)):
return events, nil
case evt, ok := <-i.eventsOut:
if !ok {
return events, errors.New("Inotify closed")
}
if evt.err != nil {
return events, evt.err
}
events = append(events, evt.InotifyEvent)
if len(events) >= maxEvents {
return events, nil
}
}
}
}

View File

@@ -0,0 +1,17 @@
//go:build linux
package syscallf
import "syscall"
func InotifyRmWatch(fd int, watchdesc int) (int, error) {
var success int
var err error
r0, _, e1 := syscall.RawSyscall(syscall.SYS_INOTIFY_RM_WATCH, uintptr(fd), uintptr(watchdesc), 0)
success = int(r0)
if e1 != 0 {
err = e1
}
return success, err
}