lib/fs, lib/model: Add error channel to Watch to avoid panics (fixes #5697) (#5734)

* lib/fs, lib/model: Add error channel to Watch to avoid panics (fixes #5697)

* forgot unsupported watch

* and more non(-standard)-unixy fixes

* and windows test

* review
This commit is contained in:
Simon Frei
2019-05-25 21:08:26 +02:00
committed by Audrius Butkevicius
parent 9e6db72535
commit 486230768e
12 changed files with 158 additions and 105 deletions

View File

@@ -20,10 +20,10 @@ import (
// Not meant to be changed, but must be changeable for tests
var backendBuffer = 500
func (f *BasicFilesystem) Watch(name string, ignore Matcher, ctx context.Context, ignorePerms bool) (<-chan Event, error) {
func (f *BasicFilesystem) Watch(name string, ignore Matcher, ctx context.Context, ignorePerms bool) (<-chan Event, <-chan error, error) {
watchPath, root, err := f.watchPaths(name)
if err != nil {
return nil, err
return nil, nil, err
}
outChan := make(chan Event)
@@ -36,7 +36,11 @@ func (f *BasicFilesystem) Watch(name string, ignore Matcher, ctx context.Context
if ignore.SkipIgnoredDirs() {
absShouldIgnore := func(absPath string) bool {
return ignore.ShouldIgnore(f.unrootedChecked(absPath, root))
rel, err := f.unrootedChecked(absPath, root)
if err != nil {
return true
}
return ignore.ShouldIgnore(rel)
}
err = notify.WatchWithFilter(watchPath, backendChan, absShouldIgnore, eventMask)
} else {
@@ -47,15 +51,16 @@ func (f *BasicFilesystem) Watch(name string, ignore Matcher, ctx context.Context
if reachedMaxUserWatches(err) {
err = errors.New("failed to setup inotify handler. Please increase inotify limits, see https://docs.syncthing.net/users/faq.html#inotify-limits")
}
return nil, err
return nil, nil, err
}
go f.watchLoop(name, root, backendChan, outChan, ignore, ctx)
errChan := make(chan error)
go f.watchLoop(name, root, backendChan, outChan, errChan, ignore, ctx)
return outChan, nil
return outChan, errChan, nil
}
func (f *BasicFilesystem) watchLoop(name, evalRoot string, backendChan chan notify.EventInfo, outChan chan<- Event, ignore Matcher, ctx context.Context) {
func (f *BasicFilesystem) watchLoop(name, evalRoot string, backendChan chan notify.EventInfo, outChan chan<- Event, errChan chan<- error, ignore Matcher, ctx context.Context) {
for {
// Detect channel overflow
if len(backendChan) == backendBuffer {
@@ -74,7 +79,18 @@ func (f *BasicFilesystem) watchLoop(name, evalRoot string, backendChan chan noti
select {
case ev := <-backendChan:
relPath := f.unrootedChecked(ev.Path(), evalRoot)
relPath, err := f.unrootedChecked(ev.Path(), evalRoot)
if err != nil {
select {
case errChan <- err:
l.Debugln(f.Type(), f.URI(), "Watch: Sending error", err)
case <-ctx.Done():
}
notify.Stop(backendChan)
l.Debugln(f.Type(), f.URI(), "Watch: Stopped due to", err)
return
}
if ignore.ShouldIgnore(relPath) {
l.Debugln(f.Type(), f.URI(), "Watch: Ignoring", relPath)
continue