vendor: update github.com/rjeczalik/notify for go1.10 (#15785)

This commit is contained in:
Péter Szilágyi 2018-01-02 12:41:47 +02:00 committed by Felix Lange
parent 3e0113fff4
commit d2533d0efb
20 changed files with 229 additions and 158 deletions

View File

@ -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)

View File

@ -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

View File

@ -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 }
}

View File

@ -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

9
vendor/github.com/rjeczalik/notify/debug_nodebug.go generated vendored Normal file
View File

@ -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

View File

@ -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

View File

@ -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 {

View File

@ -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 }

View File

@ -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

View File

@ -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.

View File

@ -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.

View File

@ -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

View File

@ -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 {

View File

@ -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

View File

@ -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)

View File

@ -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
}

View File

@ -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.

View File

@ -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
}

View File

@ -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,

6
vendor/vendor.json vendored
View File

@ -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=",