vendor: update github.com/rjeczalik/notify for go1.10 (#15785)
This commit is contained in:
parent
3e0113fff4
commit
d2533d0efb
|
@ -18,4 +18,4 @@ Filesystem event notification library on steroids. (under active development)
|
|||
- [github.com/rjeczalik/cmd/notify](https://godoc.org/github.com/rjeczalik/cmd/notify)
|
||||
- [github.com/cortesi/devd](https://github.com/cortesi/devd)
|
||||
- [github.com/cortesi/modd](https://github.com/cortesi/modd)
|
||||
|
||||
- [github.com/syncthing/syncthing-inotify](https://github.com/syncthing/syncthing-inotify)
|
||||
|
|
|
@ -16,7 +16,7 @@ install:
|
|||
build_script:
|
||||
- go tool vet -all .
|
||||
- go build ./...
|
||||
- go test -v -race ./...
|
||||
- go test -v -timeout 60s -race ./...
|
||||
|
||||
test: off
|
||||
|
||||
|
|
|
@ -2,10 +2,52 @@
|
|||
// Use of this source code is governed by the MIT license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
// +build !debug
|
||||
|
||||
package notify
|
||||
|
||||
func dbgprint(...interface{}) {}
|
||||
import (
|
||||
"log"
|
||||
"os"
|
||||
"runtime"
|
||||
"strings"
|
||||
)
|
||||
|
||||
func dbgprintf(string, ...interface{}) {}
|
||||
var dbgprint func(...interface{})
|
||||
|
||||
var dbgprintf func(string, ...interface{})
|
||||
|
||||
var dbgcallstack func(max int) []string
|
||||
|
||||
func init() {
|
||||
if _, ok := os.LookupEnv("NOTIFY_DEBUG"); ok || debugTag {
|
||||
log.SetOutput(os.Stdout)
|
||||
log.SetFlags(log.Ldate | log.Ltime | log.Lmicroseconds)
|
||||
dbgprint = func(v ...interface{}) {
|
||||
v = append([]interface{}{"[D] "}, v...)
|
||||
log.Println(v...)
|
||||
}
|
||||
dbgprintf = func(format string, v ...interface{}) {
|
||||
format = "[D] " + format
|
||||
log.Printf(format, v...)
|
||||
}
|
||||
dbgcallstack = func(max int) []string {
|
||||
pc, stack := make([]uintptr, max), make([]string, 0, max)
|
||||
runtime.Callers(2, pc)
|
||||
for _, pc := range pc {
|
||||
if f := runtime.FuncForPC(pc); f != nil {
|
||||
fname := f.Name()
|
||||
idx := strings.LastIndex(fname, string(os.PathSeparator))
|
||||
if idx != -1 {
|
||||
stack = append(stack, fname[idx+1:])
|
||||
} else {
|
||||
stack = append(stack, fname)
|
||||
}
|
||||
}
|
||||
}
|
||||
return stack
|
||||
}
|
||||
return
|
||||
}
|
||||
dbgprint = func(v ...interface{}) {}
|
||||
dbgprintf = func(format string, v ...interface{}) {}
|
||||
dbgcallstack = func(max int) []string { return nil }
|
||||
}
|
||||
|
|
|
@ -6,38 +6,4 @@
|
|||
|
||||
package notify
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"runtime"
|
||||
"strings"
|
||||
)
|
||||
|
||||
func dbgprint(v ...interface{}) {
|
||||
fmt.Printf("[D] ")
|
||||
fmt.Print(v...)
|
||||
fmt.Printf("\n\n")
|
||||
}
|
||||
|
||||
func dbgprintf(format string, v ...interface{}) {
|
||||
fmt.Printf("[D] ")
|
||||
fmt.Printf(format, v...)
|
||||
fmt.Printf("\n\n")
|
||||
}
|
||||
|
||||
func dbgcallstack(max int) []string {
|
||||
pc, stack := make([]uintptr, max), make([]string, 0, max)
|
||||
runtime.Callers(2, pc)
|
||||
for _, pc := range pc {
|
||||
if f := runtime.FuncForPC(pc); f != nil {
|
||||
fname := f.Name()
|
||||
idx := strings.LastIndex(fname, string(os.PathSeparator))
|
||||
if idx != -1 {
|
||||
stack = append(stack, fname[idx+1:])
|
||||
} else {
|
||||
stack = append(stack, fname)
|
||||
}
|
||||
}
|
||||
}
|
||||
return stack
|
||||
}
|
||||
var debugTag bool = true
|
||||
|
|
|
@ -0,0 +1,9 @@
|
|||
// Copyright (c) 2014-2015 The Notify Authors. All rights reserved.
|
||||
// Use of this source code is governed by the MIT license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
// +build !debug
|
||||
|
||||
package notify
|
||||
|
||||
var debugTag bool = false
|
|
@ -12,11 +12,14 @@
|
|||
// source file.
|
||||
//
|
||||
// On top of filesystem watchers notify maintains a watchpoint tree, which provides
|
||||
// strategy for creating and closing filesystem watches and dispatching filesystem
|
||||
// a strategy for creating and closing filesystem watches and dispatching filesystem
|
||||
// events to user channels.
|
||||
//
|
||||
// An event set is just an event list joint using bitwise OR operator
|
||||
// into a single event value.
|
||||
// Both the platform-independent (see Constants) and specific events can be used.
|
||||
// Refer to the event_*.go source files for information about the available
|
||||
// events.
|
||||
//
|
||||
// A filesystem watch or just a watch is platform-specific entity which represents
|
||||
// a single path registered for notifications for specific event set. Setting a watch
|
||||
|
@ -35,6 +38,6 @@
|
|||
// A watchpoint is a list of user channel and event set pairs for particular
|
||||
// path (watchpoint tree's node). A single watchpoint can contain multiple
|
||||
// different user channels registered to listen for one or more events. A single
|
||||
// user channel can be registered in one or more watchpoints, recurisve and
|
||||
// user channel can be registered in one or more watchpoints, recursive and
|
||||
// non-recursive ones as well.
|
||||
package notify
|
||||
|
|
|
@ -73,7 +73,7 @@ func (e Event) String() string {
|
|||
//
|
||||
// https://developer.apple.com/library/mac/documentation/Darwin/Reference/FSEvents_Ref/index.html#//apple_ref/doc/constant_group/FSEventStreamEventFlags
|
||||
//
|
||||
// Under Linux (inotify) Sys() always returns a non-nil *syscall.InotifyEvent
|
||||
// Under Linux (inotify) Sys() always returns a non-nil *unix.InotifyEvent
|
||||
// value, defined as:
|
||||
//
|
||||
// type InotifyEvent struct {
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
|
||||
package notify
|
||||
|
||||
import "syscall"
|
||||
import "golang.org/x/sys/unix"
|
||||
|
||||
// Platform independent event values.
|
||||
const (
|
||||
|
@ -25,18 +25,18 @@ const (
|
|||
// Inotify specific masks are legal, implemented events that are guaranteed to
|
||||
// work with notify package on linux-based systems.
|
||||
const (
|
||||
InAccess = Event(syscall.IN_ACCESS) // File was accessed
|
||||
InModify = Event(syscall.IN_MODIFY) // File was modified
|
||||
InAttrib = Event(syscall.IN_ATTRIB) // Metadata changed
|
||||
InCloseWrite = Event(syscall.IN_CLOSE_WRITE) // Writtable file was closed
|
||||
InCloseNowrite = Event(syscall.IN_CLOSE_NOWRITE) // Unwrittable file closed
|
||||
InOpen = Event(syscall.IN_OPEN) // File was opened
|
||||
InMovedFrom = Event(syscall.IN_MOVED_FROM) // File was moved from X
|
||||
InMovedTo = Event(syscall.IN_MOVED_TO) // File was moved to Y
|
||||
InCreate = Event(syscall.IN_CREATE) // Subfile was created
|
||||
InDelete = Event(syscall.IN_DELETE) // Subfile was deleted
|
||||
InDeleteSelf = Event(syscall.IN_DELETE_SELF) // Self was deleted
|
||||
InMoveSelf = Event(syscall.IN_MOVE_SELF) // Self was moved
|
||||
InAccess = Event(unix.IN_ACCESS) // File was accessed
|
||||
InModify = Event(unix.IN_MODIFY) // File was modified
|
||||
InAttrib = Event(unix.IN_ATTRIB) // Metadata changed
|
||||
InCloseWrite = Event(unix.IN_CLOSE_WRITE) // Writtable file was closed
|
||||
InCloseNowrite = Event(unix.IN_CLOSE_NOWRITE) // Unwrittable file closed
|
||||
InOpen = Event(unix.IN_OPEN) // File was opened
|
||||
InMovedFrom = Event(unix.IN_MOVED_FROM) // File was moved from X
|
||||
InMovedTo = Event(unix.IN_MOVED_TO) // File was moved to Y
|
||||
InCreate = Event(unix.IN_CREATE) // Subfile was created
|
||||
InDelete = Event(unix.IN_DELETE) // Subfile was deleted
|
||||
InDeleteSelf = Event(unix.IN_DELETE_SELF) // Self was deleted
|
||||
InMoveSelf = Event(unix.IN_MOVE_SELF) // Self was moved
|
||||
)
|
||||
|
||||
var osestr = map[Event]string{
|
||||
|
@ -56,15 +56,15 @@ var osestr = map[Event]string{
|
|||
|
||||
// Inotify behavior events are not **currently** supported by notify package.
|
||||
const (
|
||||
inDontFollow = Event(syscall.IN_DONT_FOLLOW)
|
||||
inExclUnlink = Event(syscall.IN_EXCL_UNLINK)
|
||||
inMaskAdd = Event(syscall.IN_MASK_ADD)
|
||||
inOneshot = Event(syscall.IN_ONESHOT)
|
||||
inOnlydir = Event(syscall.IN_ONLYDIR)
|
||||
inDontFollow = Event(unix.IN_DONT_FOLLOW)
|
||||
inExclUnlink = Event(unix.IN_EXCL_UNLINK)
|
||||
inMaskAdd = Event(unix.IN_MASK_ADD)
|
||||
inOneshot = Event(unix.IN_ONESHOT)
|
||||
inOnlydir = Event(unix.IN_ONLYDIR)
|
||||
)
|
||||
|
||||
type event struct {
|
||||
sys syscall.InotifyEvent
|
||||
sys unix.InotifyEvent
|
||||
path string
|
||||
event Event
|
||||
}
|
||||
|
@ -72,4 +72,4 @@ type event struct {
|
|||
func (e *event) Event() Event { return e.event }
|
||||
func (e *event) Path() string { return e.path }
|
||||
func (e *event) Sys() interface{} { return &e.sys }
|
||||
func (e *event) isDir() (bool, error) { return e.sys.Mask&syscall.IN_ISDIR != 0, nil }
|
||||
func (e *event) isDir() (bool, error) { return e.sys.Mask&unix.IN_ISDIR != 0, nil }
|
||||
|
|
|
@ -27,7 +27,11 @@ const (
|
|||
dirmarker
|
||||
)
|
||||
|
||||
// ReadDirectoryChangesW filters.
|
||||
// ReadDirectoryChangesW filters
|
||||
// On Windows the following events can be passed to Watch. A different set of
|
||||
// events (see actions below) are received on the channel passed to Watch.
|
||||
// For more information refer to
|
||||
// https://msdn.microsoft.com/en-us/library/windows/desktop/aa365465(v=vs.85).aspx
|
||||
const (
|
||||
FileNotifyChangeFileName = Event(syscall.FILE_NOTIFY_CHANGE_FILE_NAME)
|
||||
FileNotifyChangeDirName = Event(syscall.FILE_NOTIFY_CHANGE_DIR_NAME)
|
||||
|
@ -48,7 +52,13 @@ const (
|
|||
// this flag should be declared in: http://golang.org/src/pkg/syscall/ztypes_windows.go
|
||||
const syscallFileNotifyChangeSecurity = 0x00000100
|
||||
|
||||
// ReadDirectoryChangesW actions.
|
||||
// ReadDirectoryChangesW actions
|
||||
// The following events are returned on the channel passed to Watch, but cannot
|
||||
// be passed to Watch itself (see filters above). You can find a table showing
|
||||
// the relation between actions and filteres at
|
||||
// https://github.com/rjeczalik/notify/issues/10#issuecomment-66179535
|
||||
// The msdn documentation on actions is part of
|
||||
// https://msdn.microsoft.com/en-us/library/windows/desktop/aa364391(v=vs.85).aspx
|
||||
const (
|
||||
FileActionAdded = Event(syscall.FILE_ACTION_ADDED) << 12
|
||||
FileActionRemoved = Event(syscall.FILE_ACTION_REMOVED) << 12
|
||||
|
|
|
@ -6,7 +6,6 @@ package notify
|
|||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"path/filepath"
|
||||
|
@ -71,7 +70,11 @@ Traverse:
|
|||
case errSkip:
|
||||
continue Traverse
|
||||
default:
|
||||
return fmt.Errorf("error while traversing %q: %v", nd.Name, err)
|
||||
return &os.PathError{
|
||||
Op: "error while traversing",
|
||||
Path: nd.Name,
|
||||
Err: err,
|
||||
}
|
||||
}
|
||||
// TODO(rjeczalik): tolerate open failures - add failed names to
|
||||
// AddDirError and notify users which names are not added to the tree.
|
||||
|
|
|
@ -33,14 +33,7 @@ type fen struct {
|
|||
|
||||
// watched is a data structure representing watched file/directory.
|
||||
type watched struct {
|
||||
// p is a path to watched file/directory
|
||||
p string
|
||||
// fi provides information about watched file/dir
|
||||
fi os.FileInfo
|
||||
// eDir represents events watched directly
|
||||
eDir Event
|
||||
// eNonDir represents events watched indirectly
|
||||
eNonDir Event
|
||||
trgWatched
|
||||
}
|
||||
|
||||
// Stop implements trigger.
|
||||
|
@ -55,7 +48,7 @@ func (f *fen) Close() (err error) {
|
|||
|
||||
// NewWatched implements trigger.
|
||||
func (*fen) NewWatched(p string, fi os.FileInfo) (*watched, error) {
|
||||
return &watched{p: p, fi: fi}, nil
|
||||
return &watched{trgWatched{p: p, fi: fi}}, nil
|
||||
}
|
||||
|
||||
// Record implements trigger.
|
||||
|
|
|
@ -12,8 +12,6 @@ import (
|
|||
"sync/atomic"
|
||||
)
|
||||
|
||||
// TODO(rjeczalik): get rid of calls to canonical, it's tree responsibility
|
||||
|
||||
const (
|
||||
failure = uint32(FSEventsMustScanSubDirs | FSEventsUserDropped | FSEventsKernelDropped)
|
||||
filter = uint32(FSEventsCreated | FSEventsRemoved | FSEventsRenamed |
|
||||
|
@ -189,9 +187,6 @@ func newWatcher(c chan<- EventInfo) watcher {
|
|||
}
|
||||
|
||||
func (fse *fsevents) watch(path string, event Event, isrec int32) (err error) {
|
||||
if path, err = canonical(path); err != nil {
|
||||
return err
|
||||
}
|
||||
if _, ok := fse.watches[path]; ok {
|
||||
return errAlreadyWatched
|
||||
}
|
||||
|
@ -211,9 +206,6 @@ func (fse *fsevents) watch(path string, event Event, isrec int32) (err error) {
|
|||
}
|
||||
|
||||
func (fse *fsevents) unwatch(path string) (err error) {
|
||||
if path, err = canonical(path); err != nil {
|
||||
return
|
||||
}
|
||||
w, ok := fse.watches[path]
|
||||
if !ok {
|
||||
return errNotWatched
|
||||
|
|
|
@ -48,7 +48,7 @@ var wg sync.WaitGroup // used to wait until the runloop starts
|
|||
// started and is ready via the wg. It also serves purpose of a dummy source,
|
||||
// thanks to it the runloop does not return as it also has at least one source
|
||||
// registered.
|
||||
var source = C.CFRunLoopSourceCreate(nil, 0, &C.CFRunLoopSourceContext{
|
||||
var source = C.CFRunLoopSourceCreate(refZero, 0, &C.CFRunLoopSourceContext{
|
||||
perform: (C.CFRunLoopPerformCallBack)(C.gosource),
|
||||
})
|
||||
|
||||
|
@ -159,8 +159,8 @@ func (s *stream) Start() error {
|
|||
return nil
|
||||
}
|
||||
wg.Wait()
|
||||
p := C.CFStringCreateWithCStringNoCopy(nil, C.CString(s.path), C.kCFStringEncodingUTF8, nil)
|
||||
path := C.CFArrayCreate(nil, (*unsafe.Pointer)(unsafe.Pointer(&p)), 1, nil)
|
||||
p := C.CFStringCreateWithCStringNoCopy(refZero, C.CString(s.path), C.kCFStringEncodingUTF8, refZero)
|
||||
path := C.CFArrayCreate(refZero, (*unsafe.Pointer)(unsafe.Pointer(&p)), 1, nil)
|
||||
ctx := C.FSEventStreamContext{}
|
||||
ref := C.EventStreamCreate(&ctx, C.uintptr_t(s.info), path, C.FSEventStreamEventId(atomic.LoadUint64(&since)), latency, flags)
|
||||
if ref == nilstream {
|
||||
|
|
|
@ -0,0 +1,9 @@
|
|||
// Copyright (c) 2017 The Notify Authors. All rights reserved.
|
||||
// Use of this source code is governed by the MIT license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
// +build darwin,!kqueue,go1.10
|
||||
|
||||
package notify
|
||||
|
||||
const refZero = 0
|
|
@ -0,0 +1,14 @@
|
|||
// Copyright (c) 2017 The Notify Authors. All rights reserved.
|
||||
// Use of this source code is governed by the MIT license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
// +build darwin,!kqueue,cgo,!go1.10
|
||||
|
||||
package notify
|
||||
|
||||
/*
|
||||
#include <CoreServices/CoreServices.h>
|
||||
*/
|
||||
import "C"
|
||||
|
||||
var refZero = (*C.struct___CFAllocator)(nil)
|
|
@ -13,14 +13,15 @@ import (
|
|||
"runtime"
|
||||
"sync"
|
||||
"sync/atomic"
|
||||
"syscall"
|
||||
"unsafe"
|
||||
|
||||
"golang.org/x/sys/unix"
|
||||
)
|
||||
|
||||
// eventBufferSize defines the size of the buffer given to read(2) function. One
|
||||
// should not depend on this value, since it was arbitrary chosen and may be
|
||||
// changed in the future.
|
||||
const eventBufferSize = 64 * (syscall.SizeofInotifyEvent + syscall.PathMax + 1)
|
||||
const eventBufferSize = 64 * (unix.SizeofInotifyEvent + unix.PathMax + 1)
|
||||
|
||||
// consumersCount defines the number of consumers in producer-consumer based
|
||||
// implementation. Each consumer is run in a separate goroutine and has read
|
||||
|
@ -43,7 +44,7 @@ type inotify struct {
|
|||
fd int32 // inotify file descriptor
|
||||
pipefd []int // pipe's read and write descriptors
|
||||
epfd int // epoll descriptor
|
||||
epes []syscall.EpollEvent // epoll events
|
||||
epes []unix.EpollEvent // epoll events
|
||||
buffer [eventBufferSize]byte // inotify event buffer
|
||||
wg sync.WaitGroup // wait group used to close main loop
|
||||
c chan<- EventInfo // event dispatcher channel
|
||||
|
@ -56,13 +57,13 @@ func newWatcher(c chan<- EventInfo) watcher {
|
|||
fd: invalidDescriptor,
|
||||
pipefd: []int{invalidDescriptor, invalidDescriptor},
|
||||
epfd: invalidDescriptor,
|
||||
epes: make([]syscall.EpollEvent, 0),
|
||||
epes: make([]unix.EpollEvent, 0),
|
||||
c: c,
|
||||
}
|
||||
runtime.SetFinalizer(i, func(i *inotify) {
|
||||
i.epollclose()
|
||||
if i.fd != invalidDescriptor {
|
||||
syscall.Close(int(i.fd))
|
||||
unix.Close(int(i.fd))
|
||||
}
|
||||
})
|
||||
return i
|
||||
|
@ -82,13 +83,13 @@ func (i *inotify) Rewatch(path string, _, newevent Event) error {
|
|||
// one. If called for the first time, this function initializes inotify filesystem
|
||||
// monitor and starts producer-consumers goroutines.
|
||||
func (i *inotify) watch(path string, e Event) (err error) {
|
||||
if e&^(All|Event(syscall.IN_ALL_EVENTS)) != 0 {
|
||||
if e&^(All|Event(unix.IN_ALL_EVENTS)) != 0 {
|
||||
return errors.New("notify: unknown event")
|
||||
}
|
||||
if err = i.lazyinit(); err != nil {
|
||||
return
|
||||
}
|
||||
iwd, err := syscall.InotifyAddWatch(int(i.fd), path, encode(e))
|
||||
iwd, err := unix.InotifyAddWatch(int(i.fd), path, encode(e))
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
@ -119,13 +120,13 @@ func (i *inotify) lazyinit() error {
|
|||
i.Lock()
|
||||
defer i.Unlock()
|
||||
if atomic.LoadInt32(&i.fd) == invalidDescriptor {
|
||||
fd, err := syscall.InotifyInit()
|
||||
fd, err := unix.InotifyInit1(unix.IN_CLOEXEC)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
i.fd = int32(fd)
|
||||
if err = i.epollinit(); err != nil {
|
||||
_, _ = i.epollclose(), syscall.Close(int(fd)) // Ignore errors.
|
||||
_, _ = i.epollclose(), unix.Close(int(fd)) // Ignore errors.
|
||||
i.fd = invalidDescriptor
|
||||
return err
|
||||
}
|
||||
|
@ -145,33 +146,33 @@ func (i *inotify) lazyinit() error {
|
|||
// with inotify event queue and the read end of the pipe are added to epoll set.
|
||||
// Note that `fd` member must be set before this function is called.
|
||||
func (i *inotify) epollinit() (err error) {
|
||||
if i.epfd, err = syscall.EpollCreate1(0); err != nil {
|
||||
if i.epfd, err = unix.EpollCreate1(0); err != nil {
|
||||
return
|
||||
}
|
||||
if err = syscall.Pipe(i.pipefd); err != nil {
|
||||
if err = unix.Pipe(i.pipefd); err != nil {
|
||||
return
|
||||
}
|
||||
i.epes = []syscall.EpollEvent{
|
||||
{Events: syscall.EPOLLIN, Fd: i.fd},
|
||||
{Events: syscall.EPOLLIN, Fd: int32(i.pipefd[0])},
|
||||
i.epes = []unix.EpollEvent{
|
||||
{Events: unix.EPOLLIN, Fd: i.fd},
|
||||
{Events: unix.EPOLLIN, Fd: int32(i.pipefd[0])},
|
||||
}
|
||||
if err = syscall.EpollCtl(i.epfd, syscall.EPOLL_CTL_ADD, int(i.fd), &i.epes[0]); err != nil {
|
||||
if err = unix.EpollCtl(i.epfd, unix.EPOLL_CTL_ADD, int(i.fd), &i.epes[0]); err != nil {
|
||||
return
|
||||
}
|
||||
return syscall.EpollCtl(i.epfd, syscall.EPOLL_CTL_ADD, i.pipefd[0], &i.epes[1])
|
||||
return unix.EpollCtl(i.epfd, unix.EPOLL_CTL_ADD, i.pipefd[0], &i.epes[1])
|
||||
}
|
||||
|
||||
// epollclose closes the file descriptor created by the call to epoll_create(2)
|
||||
// and two file descriptors opened by pipe(2) function.
|
||||
func (i *inotify) epollclose() (err error) {
|
||||
if i.epfd != invalidDescriptor {
|
||||
if err = syscall.Close(i.epfd); err == nil {
|
||||
if err = unix.Close(i.epfd); err == nil {
|
||||
i.epfd = invalidDescriptor
|
||||
}
|
||||
}
|
||||
for n, fd := range i.pipefd {
|
||||
if fd != invalidDescriptor {
|
||||
switch e := syscall.Close(fd); {
|
||||
switch e := unix.Close(fd); {
|
||||
case e != nil && err == nil:
|
||||
err = e
|
||||
case e == nil:
|
||||
|
@ -187,10 +188,10 @@ func (i *inotify) epollclose() (err error) {
|
|||
// one of the event's consumers. If pipe fd became ready, loop function closes
|
||||
// all file descriptors opened by lazyinit method and returns afterwards.
|
||||
func (i *inotify) loop(esch chan<- []*event) {
|
||||
epes := make([]syscall.EpollEvent, 1)
|
||||
epes := make([]unix.EpollEvent, 1)
|
||||
fd := atomic.LoadInt32(&i.fd)
|
||||
for {
|
||||
switch _, err := syscall.EpollWait(i.epfd, epes, -1); err {
|
||||
switch _, err := unix.EpollWait(i.epfd, epes, -1); err {
|
||||
case nil:
|
||||
switch epes[0].Fd {
|
||||
case fd:
|
||||
|
@ -199,17 +200,17 @@ func (i *inotify) loop(esch chan<- []*event) {
|
|||
case int32(i.pipefd[0]):
|
||||
i.Lock()
|
||||
defer i.Unlock()
|
||||
if err = syscall.Close(int(fd)); err != nil && err != syscall.EINTR {
|
||||
if err = unix.Close(int(fd)); err != nil && err != unix.EINTR {
|
||||
panic("notify: close(2) error " + err.Error())
|
||||
}
|
||||
atomic.StoreInt32(&i.fd, invalidDescriptor)
|
||||
if err = i.epollclose(); err != nil && err != syscall.EINTR {
|
||||
if err = i.epollclose(); err != nil && err != unix.EINTR {
|
||||
panic("notify: epollclose error " + err.Error())
|
||||
}
|
||||
close(esch)
|
||||
return
|
||||
}
|
||||
case syscall.EINTR:
|
||||
case unix.EINTR:
|
||||
continue
|
||||
default: // We should never reach this line.
|
||||
panic("notify: epoll_wait(2) error " + err.Error())
|
||||
|
@ -220,22 +221,22 @@ func (i *inotify) loop(esch chan<- []*event) {
|
|||
// read reads events from an inotify file descriptor. It does not handle errors
|
||||
// returned from read(2) function since they are not critical to watcher logic.
|
||||
func (i *inotify) read() (es []*event) {
|
||||
n, err := syscall.Read(int(i.fd), i.buffer[:])
|
||||
if err != nil || n < syscall.SizeofInotifyEvent {
|
||||
n, err := unix.Read(int(i.fd), i.buffer[:])
|
||||
if err != nil || n < unix.SizeofInotifyEvent {
|
||||
return
|
||||
}
|
||||
var sys *syscall.InotifyEvent
|
||||
nmin := n - syscall.SizeofInotifyEvent
|
||||
var sys *unix.InotifyEvent
|
||||
nmin := n - unix.SizeofInotifyEvent
|
||||
for pos, path := 0, ""; pos <= nmin; {
|
||||
sys = (*syscall.InotifyEvent)(unsafe.Pointer(&i.buffer[pos]))
|
||||
pos += syscall.SizeofInotifyEvent
|
||||
sys = (*unix.InotifyEvent)(unsafe.Pointer(&i.buffer[pos]))
|
||||
pos += unix.SizeofInotifyEvent
|
||||
if path = ""; sys.Len > 0 {
|
||||
endpos := pos + int(sys.Len)
|
||||
path = string(bytes.TrimRight(i.buffer[pos:endpos], "\x00"))
|
||||
pos = endpos
|
||||
}
|
||||
es = append(es, &event{
|
||||
sys: syscall.InotifyEvent{
|
||||
sys: unix.InotifyEvent{
|
||||
Wd: sys.Wd,
|
||||
Mask: sys.Mask,
|
||||
Cookie: sys.Cookie,
|
||||
|
@ -268,7 +269,7 @@ func (i *inotify) transform(es []*event) []*event {
|
|||
var multi []*event
|
||||
i.RLock()
|
||||
for idx, e := range es {
|
||||
if e.sys.Mask&(syscall.IN_IGNORED|syscall.IN_Q_OVERFLOW) != 0 {
|
||||
if e.sys.Mask&(unix.IN_IGNORED|unix.IN_Q_OVERFLOW) != 0 {
|
||||
es[idx] = nil
|
||||
continue
|
||||
}
|
||||
|
@ -317,7 +318,7 @@ func encode(e Event) uint32 {
|
|||
// can be nil when the event should not be passed on.
|
||||
func decode(mask Event, e *event) (syse *event) {
|
||||
if sysmask := uint32(mask) & e.sys.Mask; sysmask != 0 {
|
||||
syse = &event{sys: syscall.InotifyEvent{
|
||||
syse = &event{sys: unix.InotifyEvent{
|
||||
Wd: e.sys.Wd,
|
||||
Mask: e.sys.Mask,
|
||||
Cookie: e.sys.Cookie,
|
||||
|
@ -357,7 +358,7 @@ func (i *inotify) Unwatch(path string) (err error) {
|
|||
return errors.New("notify: path " + path + " is already watched")
|
||||
}
|
||||
fd := atomic.LoadInt32(&i.fd)
|
||||
if _, err = syscall.InotifyRmWatch(int(fd), uint32(iwd)); err != nil {
|
||||
if err = removeInotifyWatch(fd, iwd); err != nil {
|
||||
return
|
||||
}
|
||||
i.Lock()
|
||||
|
@ -377,12 +378,12 @@ func (i *inotify) Close() (err error) {
|
|||
return nil
|
||||
}
|
||||
for iwd := range i.m {
|
||||
if _, e := syscall.InotifyRmWatch(int(i.fd), uint32(iwd)); e != nil && err == nil {
|
||||
if e := removeInotifyWatch(i.fd, iwd); e != nil && err == nil {
|
||||
err = e
|
||||
}
|
||||
delete(i.m, iwd)
|
||||
}
|
||||
switch _, errwrite := syscall.Write(i.pipefd[1], []byte{0x00}); {
|
||||
switch _, errwrite := unix.Write(i.pipefd[1], []byte{0x00}); {
|
||||
case errwrite != nil && err == nil:
|
||||
err = errwrite
|
||||
fallthrough
|
||||
|
@ -394,3 +395,11 @@ func (i *inotify) Close() (err error) {
|
|||
}
|
||||
return
|
||||
}
|
||||
|
||||
// if path was removed, notify already removed the watch and returns EINVAL error
|
||||
func removeInotifyWatch(fd int32, iwd int32) (err error) {
|
||||
if _, err = unix.InotifyRmWatch(int(fd), uint32(iwd)); err != nil && err != unix.EINVAL {
|
||||
return
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
|
|
@ -36,16 +36,9 @@ type kq struct {
|
|||
|
||||
// watched is a data structure representing watched file/directory.
|
||||
type watched struct {
|
||||
// p is a path to watched file/directory.
|
||||
p string
|
||||
trgWatched
|
||||
// fd is a file descriptor for watched file/directory.
|
||||
fd int
|
||||
// fi provides information about watched file/dir.
|
||||
fi os.FileInfo
|
||||
// eDir represents events watched directly.
|
||||
eDir Event
|
||||
// eNonDir represents events watched indirectly.
|
||||
eNonDir Event
|
||||
}
|
||||
|
||||
// Stop implements trigger.
|
||||
|
@ -66,7 +59,10 @@ func (*kq) NewWatched(p string, fi os.FileInfo) (*watched, error) {
|
|||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &watched{fd: fd, p: p, fi: fi}, nil
|
||||
return &watched{
|
||||
trgWatched: trgWatched{p: p, fi: fi},
|
||||
fd: fd,
|
||||
}, nil
|
||||
}
|
||||
|
||||
// Record implements trigger.
|
||||
|
|
|
@ -284,16 +284,18 @@ func (r *readdcw) watch(path string, event Event, recursive bool) (err error) {
|
|||
return
|
||||
}
|
||||
r.Lock()
|
||||
defer r.Unlock()
|
||||
if wd, ok = r.m[path]; ok {
|
||||
r.Unlock()
|
||||
dbgprint("watch: exists already")
|
||||
return
|
||||
}
|
||||
if wd, err = newWatched(r.cph, uint32(event), recursive, path); err != nil {
|
||||
r.Unlock()
|
||||
return
|
||||
}
|
||||
r.m[path] = wd
|
||||
r.Unlock()
|
||||
dbgprint("watch: new watch added")
|
||||
} else {
|
||||
dbgprint("watch: exists already")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
@ -337,33 +339,32 @@ func (r *readdcw) loop() {
|
|||
continue
|
||||
}
|
||||
overEx := (*overlappedEx)(unsafe.Pointer(overlapped))
|
||||
if n == 0 {
|
||||
r.loopstate(overEx)
|
||||
} else {
|
||||
if n != 0 {
|
||||
r.loopevent(n, overEx)
|
||||
if err = overEx.parent.readDirChanges(); err != nil {
|
||||
// TODO: error handling
|
||||
}
|
||||
}
|
||||
r.loopstate(overEx)
|
||||
}
|
||||
}
|
||||
|
||||
// TODO(pknap) : doc
|
||||
func (r *readdcw) loopstate(overEx *overlappedEx) {
|
||||
filter := atomic.LoadUint32(&overEx.parent.parent.filter)
|
||||
r.Lock()
|
||||
defer r.Unlock()
|
||||
filter := overEx.parent.parent.filter
|
||||
if filter&onlyMachineStates == 0 {
|
||||
return
|
||||
}
|
||||
if overEx.parent.parent.count--; overEx.parent.parent.count == 0 {
|
||||
switch filter & onlyMachineStates {
|
||||
case stateRewatch:
|
||||
r.Lock()
|
||||
dbgprint("loopstate rewatch")
|
||||
overEx.parent.parent.recreate(r.cph)
|
||||
r.Unlock()
|
||||
case stateUnwatch:
|
||||
r.Lock()
|
||||
dbgprint("loopstate unwatch")
|
||||
delete(r.m, syscall.UTF16ToString(overEx.parent.pathw))
|
||||
r.Unlock()
|
||||
case stateCPClose:
|
||||
default:
|
||||
panic(`notify: windows loopstate logic error`)
|
||||
|
@ -450,8 +451,8 @@ func (r *readdcw) rewatch(path string, oldevent, newevent uint32, recursive bool
|
|||
}
|
||||
var wd *watched
|
||||
r.Lock()
|
||||
if wd, err = r.nonStateWatched(path); err != nil {
|
||||
r.Unlock()
|
||||
defer r.Unlock()
|
||||
if wd, err = r.nonStateWatchedLocked(path); err != nil {
|
||||
return
|
||||
}
|
||||
if wd.filter&(onlyNotifyChanges|onlyNGlobalEvents) != oldevent {
|
||||
|
@ -462,21 +463,19 @@ func (r *readdcw) rewatch(path string, oldevent, newevent uint32, recursive bool
|
|||
if err = wd.closeHandle(); err != nil {
|
||||
wd.filter = oldevent
|
||||
wd.recursive = recursive
|
||||
r.Unlock()
|
||||
return
|
||||
}
|
||||
r.Unlock()
|
||||
return
|
||||
}
|
||||
|
||||
// TODO : pknap
|
||||
func (r *readdcw) nonStateWatched(path string) (wd *watched, err error) {
|
||||
func (r *readdcw) nonStateWatchedLocked(path string) (wd *watched, err error) {
|
||||
wd, ok := r.m[path]
|
||||
if !ok || wd == nil {
|
||||
err = errors.New(`notify: ` + path + ` path is unwatched`)
|
||||
return
|
||||
}
|
||||
if filter := atomic.LoadUint32(&wd.filter); filter&onlyMachineStates != 0 {
|
||||
if wd.filter&onlyMachineStates != 0 {
|
||||
err = errors.New(`notify: another re/unwatching operation in progress`)
|
||||
return
|
||||
}
|
||||
|
@ -497,17 +496,26 @@ func (r *readdcw) RecursiveUnwatch(path string) error {
|
|||
func (r *readdcw) unwatch(path string) (err error) {
|
||||
var wd *watched
|
||||
r.Lock()
|
||||
if wd, err = r.nonStateWatched(path); err != nil {
|
||||
r.Unlock()
|
||||
defer r.Unlock()
|
||||
if wd, err = r.nonStateWatchedLocked(path); err != nil {
|
||||
return
|
||||
}
|
||||
wd.filter |= stateUnwatch
|
||||
if err = wd.closeHandle(); err != nil {
|
||||
wd.filter &^= stateUnwatch
|
||||
r.Unlock()
|
||||
return
|
||||
}
|
||||
r.Unlock()
|
||||
if _, attrErr := syscall.GetFileAttributes(&wd.pathw[0]); attrErr != nil {
|
||||
for _, g := range wd.digrip {
|
||||
if g != nil {
|
||||
dbgprint("unwatch: posting")
|
||||
if err = syscall.PostQueuedCompletionStatus(r.cph, 0, 0, (*syscall.Overlapped)(unsafe.Pointer(g.ovlapped))); err != nil {
|
||||
wd.filter &^= stateUnwatch
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
|
|
|
@ -23,6 +23,7 @@
|
|||
package notify
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
|
@ -56,6 +57,19 @@ type trigger interface {
|
|||
IsStop(n interface{}, err error) bool
|
||||
}
|
||||
|
||||
// trgWatched is a the base data structure representing watched file/directory.
|
||||
// The platform specific full data structure (watched) must embed this type.
|
||||
type trgWatched struct {
|
||||
// p is a path to watched file/directory.
|
||||
p string
|
||||
// fi provides information about watched file/dir.
|
||||
fi os.FileInfo
|
||||
// eDir represents events watched directly.
|
||||
eDir Event
|
||||
// eNonDir represents events watched indirectly.
|
||||
eNonDir Event
|
||||
}
|
||||
|
||||
// encode Event to native representation. Implementation is to be provided by
|
||||
// platform specific implementation.
|
||||
var encode func(Event, bool) int64
|
||||
|
@ -117,6 +131,9 @@ func (t *trg) Close() (err error) {
|
|||
dbgprintf("trg: closing native watch failed: %q\n", e)
|
||||
err = nonil(err, e)
|
||||
}
|
||||
if remaining := len(t.pthLkp); remaining != 0 {
|
||||
err = nonil(err, fmt.Errorf("Not all watches were removed: len(t.pthLkp) == %v", len(t.pthLkp)))
|
||||
}
|
||||
t.Unlock()
|
||||
return
|
||||
}
|
||||
|
@ -175,7 +192,7 @@ func decode(o int64, w Event) (e Event) {
|
|||
func (t *trg) watch(p string, e Event, fi os.FileInfo) error {
|
||||
if err := t.singlewatch(p, e, dir, fi); err != nil {
|
||||
if err != errAlreadyWatched {
|
||||
return nil
|
||||
return err
|
||||
}
|
||||
}
|
||||
if fi.IsDir() {
|
||||
|
@ -361,7 +378,7 @@ func (t *trg) singleunwatch(p string, direct mode) error {
|
|||
}
|
||||
if w.eNonDir|w.eDir != 0 {
|
||||
mod := dir
|
||||
if w.eNonDir == 0 {
|
||||
if w.eNonDir != 0 {
|
||||
mod = ndir
|
||||
}
|
||||
if err := t.singlewatch(p, w.eNonDir|w.eDir, mod,
|
||||
|
|
|
@ -286,10 +286,10 @@
|
|||
"revisionTime": "2016-11-28T21:05:44Z"
|
||||
},
|
||||
{
|
||||
"checksumSHA1": "yOMpVYuaPAtsMIo9DvQP8WZqxQs=",
|
||||
"checksumSHA1": "tnQdt7bxmueZFl0EPrW9YrWiqGg=",
|
||||
"path": "github.com/rjeczalik/notify",
|
||||
"revision": "9d5aa0c3b735c3340018a4627446c3ea5a04a097",
|
||||
"revisionTime": "2017-01-28T20:05:44Z"
|
||||
"revision": "e1801ee34d54c4bf45126ef51fe9750b4e42bee8",
|
||||
"revisionTime": "2017-12-10T15:45:11Z"
|
||||
},
|
||||
{
|
||||
"checksumSHA1": "5uqO4ITTDMklKi3uNaE/D9LQ5nM=",
|
||||
|
|
Loading…
Reference in New Issue