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/rjeczalik/cmd/notify](https://godoc.org/github.com/rjeczalik/cmd/notify)
|
||||||
- [github.com/cortesi/devd](https://github.com/cortesi/devd)
|
- [github.com/cortesi/devd](https://github.com/cortesi/devd)
|
||||||
- [github.com/cortesi/modd](https://github.com/cortesi/modd)
|
- [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:
|
build_script:
|
||||||
- go tool vet -all .
|
- go tool vet -all .
|
||||||
- go build ./...
|
- go build ./...
|
||||||
- go test -v -race ./...
|
- go test -v -timeout 60s -race ./...
|
||||||
|
|
||||||
test: off
|
test: off
|
||||||
|
|
||||||
|
|
|
@ -2,10 +2,52 @@
|
||||||
// Use of this source code is governed by the MIT license that can be
|
// Use of this source code is governed by the MIT license that can be
|
||||||
// found in the LICENSE file.
|
// found in the LICENSE file.
|
||||||
|
|
||||||
// +build !debug
|
|
||||||
|
|
||||||
package notify
|
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
|
package notify
|
||||||
|
|
||||||
import (
|
var debugTag bool = true
|
||||||
"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
|
|
||||||
}
|
|
||||||
|
|
|
@ -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.
|
// source file.
|
||||||
//
|
//
|
||||||
// On top of filesystem watchers notify maintains a watchpoint tree, which provides
|
// 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.
|
// events to user channels.
|
||||||
//
|
//
|
||||||
// An event set is just an event list joint using bitwise OR operator
|
// An event set is just an event list joint using bitwise OR operator
|
||||||
// into a single event value.
|
// 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 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
|
// 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
|
// 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
|
// path (watchpoint tree's node). A single watchpoint can contain multiple
|
||||||
// different user channels registered to listen for one or more events. A single
|
// 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.
|
// non-recursive ones as well.
|
||||||
package notify
|
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
|
// 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:
|
// value, defined as:
|
||||||
//
|
//
|
||||||
// type InotifyEvent struct {
|
// type InotifyEvent struct {
|
||||||
|
|
|
@ -6,7 +6,7 @@
|
||||||
|
|
||||||
package notify
|
package notify
|
||||||
|
|
||||||
import "syscall"
|
import "golang.org/x/sys/unix"
|
||||||
|
|
||||||
// Platform independent event values.
|
// Platform independent event values.
|
||||||
const (
|
const (
|
||||||
|
@ -25,18 +25,18 @@ const (
|
||||||
// Inotify specific masks are legal, implemented events that are guaranteed to
|
// Inotify specific masks are legal, implemented events that are guaranteed to
|
||||||
// work with notify package on linux-based systems.
|
// work with notify package on linux-based systems.
|
||||||
const (
|
const (
|
||||||
InAccess = Event(syscall.IN_ACCESS) // File was accessed
|
InAccess = Event(unix.IN_ACCESS) // File was accessed
|
||||||
InModify = Event(syscall.IN_MODIFY) // File was modified
|
InModify = Event(unix.IN_MODIFY) // File was modified
|
||||||
InAttrib = Event(syscall.IN_ATTRIB) // Metadata changed
|
InAttrib = Event(unix.IN_ATTRIB) // Metadata changed
|
||||||
InCloseWrite = Event(syscall.IN_CLOSE_WRITE) // Writtable file was closed
|
InCloseWrite = Event(unix.IN_CLOSE_WRITE) // Writtable file was closed
|
||||||
InCloseNowrite = Event(syscall.IN_CLOSE_NOWRITE) // Unwrittable file closed
|
InCloseNowrite = Event(unix.IN_CLOSE_NOWRITE) // Unwrittable file closed
|
||||||
InOpen = Event(syscall.IN_OPEN) // File was opened
|
InOpen = Event(unix.IN_OPEN) // File was opened
|
||||||
InMovedFrom = Event(syscall.IN_MOVED_FROM) // File was moved from X
|
InMovedFrom = Event(unix.IN_MOVED_FROM) // File was moved from X
|
||||||
InMovedTo = Event(syscall.IN_MOVED_TO) // File was moved to Y
|
InMovedTo = Event(unix.IN_MOVED_TO) // File was moved to Y
|
||||||
InCreate = Event(syscall.IN_CREATE) // Subfile was created
|
InCreate = Event(unix.IN_CREATE) // Subfile was created
|
||||||
InDelete = Event(syscall.IN_DELETE) // Subfile was deleted
|
InDelete = Event(unix.IN_DELETE) // Subfile was deleted
|
||||||
InDeleteSelf = Event(syscall.IN_DELETE_SELF) // Self was deleted
|
InDeleteSelf = Event(unix.IN_DELETE_SELF) // Self was deleted
|
||||||
InMoveSelf = Event(syscall.IN_MOVE_SELF) // Self was moved
|
InMoveSelf = Event(unix.IN_MOVE_SELF) // Self was moved
|
||||||
)
|
)
|
||||||
|
|
||||||
var osestr = map[Event]string{
|
var osestr = map[Event]string{
|
||||||
|
@ -56,15 +56,15 @@ var osestr = map[Event]string{
|
||||||
|
|
||||||
// Inotify behavior events are not **currently** supported by notify package.
|
// Inotify behavior events are not **currently** supported by notify package.
|
||||||
const (
|
const (
|
||||||
inDontFollow = Event(syscall.IN_DONT_FOLLOW)
|
inDontFollow = Event(unix.IN_DONT_FOLLOW)
|
||||||
inExclUnlink = Event(syscall.IN_EXCL_UNLINK)
|
inExclUnlink = Event(unix.IN_EXCL_UNLINK)
|
||||||
inMaskAdd = Event(syscall.IN_MASK_ADD)
|
inMaskAdd = Event(unix.IN_MASK_ADD)
|
||||||
inOneshot = Event(syscall.IN_ONESHOT)
|
inOneshot = Event(unix.IN_ONESHOT)
|
||||||
inOnlydir = Event(syscall.IN_ONLYDIR)
|
inOnlydir = Event(unix.IN_ONLYDIR)
|
||||||
)
|
)
|
||||||
|
|
||||||
type event struct {
|
type event struct {
|
||||||
sys syscall.InotifyEvent
|
sys unix.InotifyEvent
|
||||||
path string
|
path string
|
||||||
event Event
|
event Event
|
||||||
}
|
}
|
||||||
|
@ -72,4 +72,4 @@ type event struct {
|
||||||
func (e *event) Event() Event { return e.event }
|
func (e *event) Event() Event { return e.event }
|
||||||
func (e *event) Path() string { return e.path }
|
func (e *event) Path() string { return e.path }
|
||||||
func (e *event) Sys() interface{} { return &e.sys }
|
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
|
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 (
|
const (
|
||||||
FileNotifyChangeFileName = Event(syscall.FILE_NOTIFY_CHANGE_FILE_NAME)
|
FileNotifyChangeFileName = Event(syscall.FILE_NOTIFY_CHANGE_FILE_NAME)
|
||||||
FileNotifyChangeDirName = Event(syscall.FILE_NOTIFY_CHANGE_DIR_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
|
// this flag should be declared in: http://golang.org/src/pkg/syscall/ztypes_windows.go
|
||||||
const syscallFileNotifyChangeSecurity = 0x00000100
|
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 (
|
const (
|
||||||
FileActionAdded = Event(syscall.FILE_ACTION_ADDED) << 12
|
FileActionAdded = Event(syscall.FILE_ACTION_ADDED) << 12
|
||||||
FileActionRemoved = Event(syscall.FILE_ACTION_REMOVED) << 12
|
FileActionRemoved = Event(syscall.FILE_ACTION_REMOVED) << 12
|
||||||
|
|
|
@ -6,7 +6,6 @@ package notify
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
"os"
|
"os"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
|
@ -71,7 +70,11 @@ Traverse:
|
||||||
case errSkip:
|
case errSkip:
|
||||||
continue Traverse
|
continue Traverse
|
||||||
default:
|
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
|
// TODO(rjeczalik): tolerate open failures - add failed names to
|
||||||
// AddDirError and notify users which names are not added to the tree.
|
// 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.
|
// watched is a data structure representing watched file/directory.
|
||||||
type watched struct {
|
type watched struct {
|
||||||
// p is a path to watched file/directory
|
trgWatched
|
||||||
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
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Stop implements trigger.
|
// Stop implements trigger.
|
||||||
|
@ -55,7 +48,7 @@ func (f *fen) Close() (err error) {
|
||||||
|
|
||||||
// NewWatched implements trigger.
|
// NewWatched implements trigger.
|
||||||
func (*fen) NewWatched(p string, fi os.FileInfo) (*watched, error) {
|
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.
|
// Record implements trigger.
|
||||||
|
|
|
@ -12,8 +12,6 @@ import (
|
||||||
"sync/atomic"
|
"sync/atomic"
|
||||||
)
|
)
|
||||||
|
|
||||||
// TODO(rjeczalik): get rid of calls to canonical, it's tree responsibility
|
|
||||||
|
|
||||||
const (
|
const (
|
||||||
failure = uint32(FSEventsMustScanSubDirs | FSEventsUserDropped | FSEventsKernelDropped)
|
failure = uint32(FSEventsMustScanSubDirs | FSEventsUserDropped | FSEventsKernelDropped)
|
||||||
filter = uint32(FSEventsCreated | FSEventsRemoved | FSEventsRenamed |
|
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) {
|
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 {
|
if _, ok := fse.watches[path]; ok {
|
||||||
return errAlreadyWatched
|
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) {
|
func (fse *fsevents) unwatch(path string) (err error) {
|
||||||
if path, err = canonical(path); err != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
w, ok := fse.watches[path]
|
w, ok := fse.watches[path]
|
||||||
if !ok {
|
if !ok {
|
||||||
return errNotWatched
|
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,
|
// 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
|
// thanks to it the runloop does not return as it also has at least one source
|
||||||
// registered.
|
// registered.
|
||||||
var source = C.CFRunLoopSourceCreate(nil, 0, &C.CFRunLoopSourceContext{
|
var source = C.CFRunLoopSourceCreate(refZero, 0, &C.CFRunLoopSourceContext{
|
||||||
perform: (C.CFRunLoopPerformCallBack)(C.gosource),
|
perform: (C.CFRunLoopPerformCallBack)(C.gosource),
|
||||||
})
|
})
|
||||||
|
|
||||||
|
@ -159,8 +159,8 @@ func (s *stream) Start() error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
wg.Wait()
|
wg.Wait()
|
||||||
p := C.CFStringCreateWithCStringNoCopy(nil, C.CString(s.path), C.kCFStringEncodingUTF8, nil)
|
p := C.CFStringCreateWithCStringNoCopy(refZero, C.CString(s.path), C.kCFStringEncodingUTF8, refZero)
|
||||||
path := C.CFArrayCreate(nil, (*unsafe.Pointer)(unsafe.Pointer(&p)), 1, nil)
|
path := C.CFArrayCreate(refZero, (*unsafe.Pointer)(unsafe.Pointer(&p)), 1, nil)
|
||||||
ctx := C.FSEventStreamContext{}
|
ctx := C.FSEventStreamContext{}
|
||||||
ref := C.EventStreamCreate(&ctx, C.uintptr_t(s.info), path, C.FSEventStreamEventId(atomic.LoadUint64(&since)), latency, flags)
|
ref := C.EventStreamCreate(&ctx, C.uintptr_t(s.info), path, C.FSEventStreamEventId(atomic.LoadUint64(&since)), latency, flags)
|
||||||
if ref == nilstream {
|
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"
|
"runtime"
|
||||||
"sync"
|
"sync"
|
||||||
"sync/atomic"
|
"sync/atomic"
|
||||||
"syscall"
|
|
||||||
"unsafe"
|
"unsafe"
|
||||||
|
|
||||||
|
"golang.org/x/sys/unix"
|
||||||
)
|
)
|
||||||
|
|
||||||
// eventBufferSize defines the size of the buffer given to read(2) function. One
|
// 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
|
// should not depend on this value, since it was arbitrary chosen and may be
|
||||||
// changed in the future.
|
// 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
|
// consumersCount defines the number of consumers in producer-consumer based
|
||||||
// implementation. Each consumer is run in a separate goroutine and has read
|
// implementation. Each consumer is run in a separate goroutine and has read
|
||||||
|
@ -43,7 +44,7 @@ type inotify struct {
|
||||||
fd int32 // inotify file descriptor
|
fd int32 // inotify file descriptor
|
||||||
pipefd []int // pipe's read and write descriptors
|
pipefd []int // pipe's read and write descriptors
|
||||||
epfd int // epoll descriptor
|
epfd int // epoll descriptor
|
||||||
epes []syscall.EpollEvent // epoll events
|
epes []unix.EpollEvent // epoll events
|
||||||
buffer [eventBufferSize]byte // inotify event buffer
|
buffer [eventBufferSize]byte // inotify event buffer
|
||||||
wg sync.WaitGroup // wait group used to close main loop
|
wg sync.WaitGroup // wait group used to close main loop
|
||||||
c chan<- EventInfo // event dispatcher channel
|
c chan<- EventInfo // event dispatcher channel
|
||||||
|
@ -56,13 +57,13 @@ func newWatcher(c chan<- EventInfo) watcher {
|
||||||
fd: invalidDescriptor,
|
fd: invalidDescriptor,
|
||||||
pipefd: []int{invalidDescriptor, invalidDescriptor},
|
pipefd: []int{invalidDescriptor, invalidDescriptor},
|
||||||
epfd: invalidDescriptor,
|
epfd: invalidDescriptor,
|
||||||
epes: make([]syscall.EpollEvent, 0),
|
epes: make([]unix.EpollEvent, 0),
|
||||||
c: c,
|
c: c,
|
||||||
}
|
}
|
||||||
runtime.SetFinalizer(i, func(i *inotify) {
|
runtime.SetFinalizer(i, func(i *inotify) {
|
||||||
i.epollclose()
|
i.epollclose()
|
||||||
if i.fd != invalidDescriptor {
|
if i.fd != invalidDescriptor {
|
||||||
syscall.Close(int(i.fd))
|
unix.Close(int(i.fd))
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
return i
|
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
|
// one. If called for the first time, this function initializes inotify filesystem
|
||||||
// monitor and starts producer-consumers goroutines.
|
// monitor and starts producer-consumers goroutines.
|
||||||
func (i *inotify) watch(path string, e Event) (err error) {
|
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")
|
return errors.New("notify: unknown event")
|
||||||
}
|
}
|
||||||
if err = i.lazyinit(); err != nil {
|
if err = i.lazyinit(); err != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
iwd, err := syscall.InotifyAddWatch(int(i.fd), path, encode(e))
|
iwd, err := unix.InotifyAddWatch(int(i.fd), path, encode(e))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
@ -119,13 +120,13 @@ func (i *inotify) lazyinit() error {
|
||||||
i.Lock()
|
i.Lock()
|
||||||
defer i.Unlock()
|
defer i.Unlock()
|
||||||
if atomic.LoadInt32(&i.fd) == invalidDescriptor {
|
if atomic.LoadInt32(&i.fd) == invalidDescriptor {
|
||||||
fd, err := syscall.InotifyInit()
|
fd, err := unix.InotifyInit1(unix.IN_CLOEXEC)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
i.fd = int32(fd)
|
i.fd = int32(fd)
|
||||||
if err = i.epollinit(); err != nil {
|
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
|
i.fd = invalidDescriptor
|
||||||
return err
|
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.
|
// 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.
|
// Note that `fd` member must be set before this function is called.
|
||||||
func (i *inotify) epollinit() (err error) {
|
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
|
return
|
||||||
}
|
}
|
||||||
if err = syscall.Pipe(i.pipefd); err != nil {
|
if err = unix.Pipe(i.pipefd); err != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
i.epes = []syscall.EpollEvent{
|
i.epes = []unix.EpollEvent{
|
||||||
{Events: syscall.EPOLLIN, Fd: i.fd},
|
{Events: unix.EPOLLIN, Fd: i.fd},
|
||||||
{Events: syscall.EPOLLIN, Fd: int32(i.pipefd[0])},
|
{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
|
||||||
}
|
}
|
||||||
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)
|
// epollclose closes the file descriptor created by the call to epoll_create(2)
|
||||||
// and two file descriptors opened by pipe(2) function.
|
// and two file descriptors opened by pipe(2) function.
|
||||||
func (i *inotify) epollclose() (err error) {
|
func (i *inotify) epollclose() (err error) {
|
||||||
if i.epfd != invalidDescriptor {
|
if i.epfd != invalidDescriptor {
|
||||||
if err = syscall.Close(i.epfd); err == nil {
|
if err = unix.Close(i.epfd); err == nil {
|
||||||
i.epfd = invalidDescriptor
|
i.epfd = invalidDescriptor
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
for n, fd := range i.pipefd {
|
for n, fd := range i.pipefd {
|
||||||
if fd != invalidDescriptor {
|
if fd != invalidDescriptor {
|
||||||
switch e := syscall.Close(fd); {
|
switch e := unix.Close(fd); {
|
||||||
case e != nil && err == nil:
|
case e != nil && err == nil:
|
||||||
err = e
|
err = e
|
||||||
case e == nil:
|
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
|
// one of the event's consumers. If pipe fd became ready, loop function closes
|
||||||
// all file descriptors opened by lazyinit method and returns afterwards.
|
// all file descriptors opened by lazyinit method and returns afterwards.
|
||||||
func (i *inotify) loop(esch chan<- []*event) {
|
func (i *inotify) loop(esch chan<- []*event) {
|
||||||
epes := make([]syscall.EpollEvent, 1)
|
epes := make([]unix.EpollEvent, 1)
|
||||||
fd := atomic.LoadInt32(&i.fd)
|
fd := atomic.LoadInt32(&i.fd)
|
||||||
for {
|
for {
|
||||||
switch _, err := syscall.EpollWait(i.epfd, epes, -1); err {
|
switch _, err := unix.EpollWait(i.epfd, epes, -1); err {
|
||||||
case nil:
|
case nil:
|
||||||
switch epes[0].Fd {
|
switch epes[0].Fd {
|
||||||
case fd:
|
case fd:
|
||||||
|
@ -199,17 +200,17 @@ func (i *inotify) loop(esch chan<- []*event) {
|
||||||
case int32(i.pipefd[0]):
|
case int32(i.pipefd[0]):
|
||||||
i.Lock()
|
i.Lock()
|
||||||
defer i.Unlock()
|
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())
|
panic("notify: close(2) error " + err.Error())
|
||||||
}
|
}
|
||||||
atomic.StoreInt32(&i.fd, invalidDescriptor)
|
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())
|
panic("notify: epollclose error " + err.Error())
|
||||||
}
|
}
|
||||||
close(esch)
|
close(esch)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
case syscall.EINTR:
|
case unix.EINTR:
|
||||||
continue
|
continue
|
||||||
default: // We should never reach this line.
|
default: // We should never reach this line.
|
||||||
panic("notify: epoll_wait(2) error " + err.Error())
|
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
|
// 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.
|
// returned from read(2) function since they are not critical to watcher logic.
|
||||||
func (i *inotify) read() (es []*event) {
|
func (i *inotify) read() (es []*event) {
|
||||||
n, err := syscall.Read(int(i.fd), i.buffer[:])
|
n, err := unix.Read(int(i.fd), i.buffer[:])
|
||||||
if err != nil || n < syscall.SizeofInotifyEvent {
|
if err != nil || n < unix.SizeofInotifyEvent {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
var sys *syscall.InotifyEvent
|
var sys *unix.InotifyEvent
|
||||||
nmin := n - syscall.SizeofInotifyEvent
|
nmin := n - unix.SizeofInotifyEvent
|
||||||
for pos, path := 0, ""; pos <= nmin; {
|
for pos, path := 0, ""; pos <= nmin; {
|
||||||
sys = (*syscall.InotifyEvent)(unsafe.Pointer(&i.buffer[pos]))
|
sys = (*unix.InotifyEvent)(unsafe.Pointer(&i.buffer[pos]))
|
||||||
pos += syscall.SizeofInotifyEvent
|
pos += unix.SizeofInotifyEvent
|
||||||
if path = ""; sys.Len > 0 {
|
if path = ""; sys.Len > 0 {
|
||||||
endpos := pos + int(sys.Len)
|
endpos := pos + int(sys.Len)
|
||||||
path = string(bytes.TrimRight(i.buffer[pos:endpos], "\x00"))
|
path = string(bytes.TrimRight(i.buffer[pos:endpos], "\x00"))
|
||||||
pos = endpos
|
pos = endpos
|
||||||
}
|
}
|
||||||
es = append(es, &event{
|
es = append(es, &event{
|
||||||
sys: syscall.InotifyEvent{
|
sys: unix.InotifyEvent{
|
||||||
Wd: sys.Wd,
|
Wd: sys.Wd,
|
||||||
Mask: sys.Mask,
|
Mask: sys.Mask,
|
||||||
Cookie: sys.Cookie,
|
Cookie: sys.Cookie,
|
||||||
|
@ -268,7 +269,7 @@ func (i *inotify) transform(es []*event) []*event {
|
||||||
var multi []*event
|
var multi []*event
|
||||||
i.RLock()
|
i.RLock()
|
||||||
for idx, e := range es {
|
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
|
es[idx] = nil
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
@ -317,7 +318,7 @@ func encode(e Event) uint32 {
|
||||||
// can be nil when the event should not be passed on.
|
// can be nil when the event should not be passed on.
|
||||||
func decode(mask Event, e *event) (syse *event) {
|
func decode(mask Event, e *event) (syse *event) {
|
||||||
if sysmask := uint32(mask) & e.sys.Mask; sysmask != 0 {
|
if sysmask := uint32(mask) & e.sys.Mask; sysmask != 0 {
|
||||||
syse = &event{sys: syscall.InotifyEvent{
|
syse = &event{sys: unix.InotifyEvent{
|
||||||
Wd: e.sys.Wd,
|
Wd: e.sys.Wd,
|
||||||
Mask: e.sys.Mask,
|
Mask: e.sys.Mask,
|
||||||
Cookie: e.sys.Cookie,
|
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")
|
return errors.New("notify: path " + path + " is already watched")
|
||||||
}
|
}
|
||||||
fd := atomic.LoadInt32(&i.fd)
|
fd := atomic.LoadInt32(&i.fd)
|
||||||
if _, err = syscall.InotifyRmWatch(int(fd), uint32(iwd)); err != nil {
|
if err = removeInotifyWatch(fd, iwd); err != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
i.Lock()
|
i.Lock()
|
||||||
|
@ -377,12 +378,12 @@ func (i *inotify) Close() (err error) {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
for iwd := range i.m {
|
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
|
err = e
|
||||||
}
|
}
|
||||||
delete(i.m, iwd)
|
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:
|
case errwrite != nil && err == nil:
|
||||||
err = errwrite
|
err = errwrite
|
||||||
fallthrough
|
fallthrough
|
||||||
|
@ -394,3 +395,11 @@ func (i *inotify) Close() (err error) {
|
||||||
}
|
}
|
||||||
return
|
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.
|
// watched is a data structure representing watched file/directory.
|
||||||
type watched struct {
|
type watched struct {
|
||||||
// p is a path to watched file/directory.
|
trgWatched
|
||||||
p string
|
|
||||||
// fd is a file descriptor for watched file/directory.
|
// fd is a file descriptor for watched file/directory.
|
||||||
fd int
|
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.
|
// Stop implements trigger.
|
||||||
|
@ -66,7 +59,10 @@ func (*kq) NewWatched(p string, fi os.FileInfo) (*watched, error) {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
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.
|
// Record implements trigger.
|
||||||
|
|
|
@ -284,16 +284,18 @@ func (r *readdcw) watch(path string, event Event, recursive bool) (err error) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
r.Lock()
|
r.Lock()
|
||||||
|
defer r.Unlock()
|
||||||
if wd, ok = r.m[path]; ok {
|
if wd, ok = r.m[path]; ok {
|
||||||
r.Unlock()
|
dbgprint("watch: exists already")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if wd, err = newWatched(r.cph, uint32(event), recursive, path); err != nil {
|
if wd, err = newWatched(r.cph, uint32(event), recursive, path); err != nil {
|
||||||
r.Unlock()
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
r.m[path] = wd
|
r.m[path] = wd
|
||||||
r.Unlock()
|
dbgprint("watch: new watch added")
|
||||||
|
} else {
|
||||||
|
dbgprint("watch: exists already")
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
@ -337,33 +339,32 @@ func (r *readdcw) loop() {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
overEx := (*overlappedEx)(unsafe.Pointer(overlapped))
|
overEx := (*overlappedEx)(unsafe.Pointer(overlapped))
|
||||||
if n == 0 {
|
if n != 0 {
|
||||||
r.loopstate(overEx)
|
|
||||||
} else {
|
|
||||||
r.loopevent(n, overEx)
|
r.loopevent(n, overEx)
|
||||||
if err = overEx.parent.readDirChanges(); err != nil {
|
if err = overEx.parent.readDirChanges(); err != nil {
|
||||||
// TODO: error handling
|
// TODO: error handling
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
r.loopstate(overEx)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO(pknap) : doc
|
// TODO(pknap) : doc
|
||||||
func (r *readdcw) loopstate(overEx *overlappedEx) {
|
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 {
|
if filter&onlyMachineStates == 0 {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if overEx.parent.parent.count--; overEx.parent.parent.count == 0 {
|
if overEx.parent.parent.count--; overEx.parent.parent.count == 0 {
|
||||||
switch filter & onlyMachineStates {
|
switch filter & onlyMachineStates {
|
||||||
case stateRewatch:
|
case stateRewatch:
|
||||||
r.Lock()
|
dbgprint("loopstate rewatch")
|
||||||
overEx.parent.parent.recreate(r.cph)
|
overEx.parent.parent.recreate(r.cph)
|
||||||
r.Unlock()
|
|
||||||
case stateUnwatch:
|
case stateUnwatch:
|
||||||
r.Lock()
|
dbgprint("loopstate unwatch")
|
||||||
delete(r.m, syscall.UTF16ToString(overEx.parent.pathw))
|
delete(r.m, syscall.UTF16ToString(overEx.parent.pathw))
|
||||||
r.Unlock()
|
|
||||||
case stateCPClose:
|
case stateCPClose:
|
||||||
default:
|
default:
|
||||||
panic(`notify: windows loopstate logic error`)
|
panic(`notify: windows loopstate logic error`)
|
||||||
|
@ -450,8 +451,8 @@ func (r *readdcw) rewatch(path string, oldevent, newevent uint32, recursive bool
|
||||||
}
|
}
|
||||||
var wd *watched
|
var wd *watched
|
||||||
r.Lock()
|
r.Lock()
|
||||||
if wd, err = r.nonStateWatched(path); err != nil {
|
defer r.Unlock()
|
||||||
r.Unlock()
|
if wd, err = r.nonStateWatchedLocked(path); err != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if wd.filter&(onlyNotifyChanges|onlyNGlobalEvents) != oldevent {
|
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 {
|
if err = wd.closeHandle(); err != nil {
|
||||||
wd.filter = oldevent
|
wd.filter = oldevent
|
||||||
wd.recursive = recursive
|
wd.recursive = recursive
|
||||||
r.Unlock()
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
r.Unlock()
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO : pknap
|
// 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]
|
wd, ok := r.m[path]
|
||||||
if !ok || wd == nil {
|
if !ok || wd == nil {
|
||||||
err = errors.New(`notify: ` + path + ` path is unwatched`)
|
err = errors.New(`notify: ` + path + ` path is unwatched`)
|
||||||
return
|
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`)
|
err = errors.New(`notify: another re/unwatching operation in progress`)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
@ -497,17 +496,26 @@ func (r *readdcw) RecursiveUnwatch(path string) error {
|
||||||
func (r *readdcw) unwatch(path string) (err error) {
|
func (r *readdcw) unwatch(path string) (err error) {
|
||||||
var wd *watched
|
var wd *watched
|
||||||
r.Lock()
|
r.Lock()
|
||||||
if wd, err = r.nonStateWatched(path); err != nil {
|
defer r.Unlock()
|
||||||
r.Unlock()
|
if wd, err = r.nonStateWatchedLocked(path); err != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
wd.filter |= stateUnwatch
|
wd.filter |= stateUnwatch
|
||||||
if err = wd.closeHandle(); err != nil {
|
if err = wd.closeHandle(); err != nil {
|
||||||
wd.filter &^= stateUnwatch
|
wd.filter &^= stateUnwatch
|
||||||
r.Unlock()
|
|
||||||
return
|
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
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -23,6 +23,7 @@
|
||||||
package notify
|
package notify
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"fmt"
|
||||||
"os"
|
"os"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"strings"
|
"strings"
|
||||||
|
@ -56,6 +57,19 @@ type trigger interface {
|
||||||
IsStop(n interface{}, err error) bool
|
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
|
// encode Event to native representation. Implementation is to be provided by
|
||||||
// platform specific implementation.
|
// platform specific implementation.
|
||||||
var encode func(Event, bool) int64
|
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)
|
dbgprintf("trg: closing native watch failed: %q\n", e)
|
||||||
err = nonil(err, 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()
|
t.Unlock()
|
||||||
return
|
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 {
|
func (t *trg) watch(p string, e Event, fi os.FileInfo) error {
|
||||||
if err := t.singlewatch(p, e, dir, fi); err != nil {
|
if err := t.singlewatch(p, e, dir, fi); err != nil {
|
||||||
if err != errAlreadyWatched {
|
if err != errAlreadyWatched {
|
||||||
return nil
|
return err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if fi.IsDir() {
|
if fi.IsDir() {
|
||||||
|
@ -361,7 +378,7 @@ func (t *trg) singleunwatch(p string, direct mode) error {
|
||||||
}
|
}
|
||||||
if w.eNonDir|w.eDir != 0 {
|
if w.eNonDir|w.eDir != 0 {
|
||||||
mod := dir
|
mod := dir
|
||||||
if w.eNonDir == 0 {
|
if w.eNonDir != 0 {
|
||||||
mod = ndir
|
mod = ndir
|
||||||
}
|
}
|
||||||
if err := t.singlewatch(p, w.eNonDir|w.eDir, mod,
|
if err := t.singlewatch(p, w.eNonDir|w.eDir, mod,
|
||||||
|
|
|
@ -286,10 +286,10 @@
|
||||||
"revisionTime": "2016-11-28T21:05:44Z"
|
"revisionTime": "2016-11-28T21:05:44Z"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"checksumSHA1": "yOMpVYuaPAtsMIo9DvQP8WZqxQs=",
|
"checksumSHA1": "tnQdt7bxmueZFl0EPrW9YrWiqGg=",
|
||||||
"path": "github.com/rjeczalik/notify",
|
"path": "github.com/rjeczalik/notify",
|
||||||
"revision": "9d5aa0c3b735c3340018a4627446c3ea5a04a097",
|
"revision": "e1801ee34d54c4bf45126ef51fe9750b4e42bee8",
|
||||||
"revisionTime": "2017-01-28T20:05:44Z"
|
"revisionTime": "2017-12-10T15:45:11Z"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"checksumSHA1": "5uqO4ITTDMklKi3uNaE/D9LQ5nM=",
|
"checksumSHA1": "5uqO4ITTDMklKi3uNaE/D9LQ5nM=",
|
||||||
|
|
Loading…
Reference in New Issue