chore(scanner): avoid scan failures and report if they happen (#9888)
This commit is contained in:
+28
-11
@@ -238,17 +238,25 @@ func (w *walker) walkWithoutHashing(ctx context.Context) chan ScanResult {
|
|||||||
return finishedChan
|
return finishedChan
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const walkFailureEventDesc = "Unexpected error while walking the filesystem during scan"
|
||||||
|
|
||||||
func (w *walker) scan(ctx context.Context, toHashChan chan<- protocol.FileInfo, finishedChan chan<- ScanResult) {
|
func (w *walker) scan(ctx context.Context, toHashChan chan<- protocol.FileInfo, finishedChan chan<- ScanResult) {
|
||||||
hashFiles := w.walkAndHashFiles(ctx, toHashChan, finishedChan)
|
hashFiles := w.walkAndHashFiles(ctx, toHashChan, finishedChan)
|
||||||
if len(w.Subs) == 0 {
|
if len(w.Subs) == 0 {
|
||||||
w.Filesystem.Walk(".", hashFiles)
|
if err := w.Filesystem.Walk(".", hashFiles); err != nil {
|
||||||
|
w.EventLogger.Log(events.Failure, walkFailureEventDesc)
|
||||||
|
l.Warnf("Aborted scan due to an unexpected error: %v", err)
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
for _, sub := range w.Subs {
|
for _, sub := range w.Subs {
|
||||||
if err := osutil.TraversesSymlink(w.Filesystem, filepath.Dir(sub)); err != nil {
|
if err := osutil.TraversesSymlink(w.Filesystem, filepath.Dir(sub)); err != nil {
|
||||||
l.Debugf("%v: Skip walking %v as it is below a symlink", w, sub)
|
l.Debugf("%v: Skip walking %v as it is below a symlink", w, sub)
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
w.Filesystem.Walk(sub, hashFiles)
|
if err := w.Filesystem.Walk(sub, hashFiles); err != nil {
|
||||||
|
w.EventLogger.Log(events.Failure, walkFailureEventDesc)
|
||||||
|
l.Warnf("Aborted scan of path '%v' due to an unexpected error: %v", sub, err)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
close(toHashChan)
|
close(toHashChan)
|
||||||
@@ -341,7 +349,11 @@ func (w *walker) walkAndHashFiles(ctx context.Context, toHashChan chan<- protoco
|
|||||||
|
|
||||||
if ignoredParent == "" {
|
if ignoredParent == "" {
|
||||||
// parent isn't ignored, nothing special
|
// parent isn't ignored, nothing special
|
||||||
return w.handleItem(ctx, path, info, toHashChan, finishedChan)
|
if err := w.handleItem(ctx, path, info, toHashChan, finishedChan); err != nil {
|
||||||
|
handleError(ctx, "scan", path, err, finishedChan)
|
||||||
|
return skip
|
||||||
|
}
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// Part of current path below the ignored (potential) parent
|
// Part of current path below the ignored (potential) parent
|
||||||
@@ -350,7 +362,11 @@ func (w *walker) walkAndHashFiles(ctx context.Context, toHashChan chan<- protoco
|
|||||||
// ignored path isn't actually a parent of the current path
|
// ignored path isn't actually a parent of the current path
|
||||||
if rel == path {
|
if rel == path {
|
||||||
ignoredParent = ""
|
ignoredParent = ""
|
||||||
return w.handleItem(ctx, path, info, toHashChan, finishedChan)
|
if err := w.handleItem(ctx, path, info, toHashChan, finishedChan); err != nil {
|
||||||
|
handleError(ctx, "scan", path, err, finishedChan)
|
||||||
|
return skip
|
||||||
|
}
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// The previously ignored parent directories of the current, not
|
// The previously ignored parent directories of the current, not
|
||||||
@@ -366,7 +382,8 @@ func (w *walker) walkAndHashFiles(ctx context.Context, toHashChan chan<- protoco
|
|||||||
return skip
|
return skip
|
||||||
}
|
}
|
||||||
if err = w.handleItem(ctx, ignoredParent, info, toHashChan, finishedChan); err != nil {
|
if err = w.handleItem(ctx, ignoredParent, info, toHashChan, finishedChan); err != nil {
|
||||||
return err
|
handleError(ctx, "scan", path, err, finishedChan)
|
||||||
|
return skip
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
ignoredParent = ""
|
ignoredParent = ""
|
||||||
@@ -375,6 +392,9 @@ func (w *walker) walkAndHashFiles(ctx context.Context, toHashChan chan<- protoco
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Returning an error does not indicate that the walk should be aborted - it
|
||||||
|
// will simply report the error for that path to the user (same for walk...
|
||||||
|
// functions called from here).
|
||||||
func (w *walker) handleItem(ctx context.Context, path string, info fs.FileInfo, toHashChan chan<- protocol.FileInfo, finishedChan chan<- ScanResult) error {
|
func (w *walker) handleItem(ctx context.Context, path string, info fs.FileInfo, toHashChan chan<- protocol.FileInfo, finishedChan chan<- ScanResult) error {
|
||||||
switch {
|
switch {
|
||||||
case info.IsSymlink():
|
case info.IsSymlink():
|
||||||
@@ -394,8 +414,7 @@ func (w *walker) handleItem(ctx context.Context, path string, info fs.FileInfo,
|
|||||||
return w.walkRegular(ctx, path, info, toHashChan)
|
return w.walkRegular(ctx, path, info, toHashChan)
|
||||||
|
|
||||||
default:
|
default:
|
||||||
// A special file, socket, fifo, etc. -- do nothing but return
|
// A special file, socket, fifo, etc. -- do nothing, just skip and continue scanning.
|
||||||
// success so we continue the walk.
|
|
||||||
l.Debugf("Skipping non-regular file %s (%s)", path, info.Mode())
|
l.Debugf("Skipping non-regular file %s (%s)", path, info.Mode())
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
@@ -512,8 +531,6 @@ func (w *walker) walkDir(ctx context.Context, relPath string, info fs.FileInfo,
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// walkSymlink returns nil or an error, if the error is of the nature that
|
|
||||||
// it should stop the entire walk.
|
|
||||||
func (w *walker) walkSymlink(ctx context.Context, relPath string, info fs.FileInfo, finishedChan chan<- ScanResult) error {
|
func (w *walker) walkSymlink(ctx context.Context, relPath string, info fs.FileInfo, finishedChan chan<- ScanResult) error {
|
||||||
// Symlinks are not supported on Windows. We ignore instead of returning
|
// Symlinks are not supported on Windows. We ignore instead of returning
|
||||||
// an error.
|
// an error.
|
||||||
@@ -523,8 +540,7 @@ func (w *walker) walkSymlink(ctx context.Context, relPath string, info fs.FileIn
|
|||||||
|
|
||||||
f, err := CreateFileInfo(info, relPath, w.Filesystem, w.ScanOwnership, w.ScanXattrs, w.XattrFilter)
|
f, err := CreateFileInfo(info, relPath, w.Filesystem, w.ScanOwnership, w.ScanXattrs, w.XattrFilter)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
handleError(ctx, "reading link", relPath, err, finishedChan)
|
return err
|
||||||
return nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
curFile, hasCurFile := w.CurrentFiler.CurrentFile(relPath)
|
curFile, hasCurFile := w.CurrentFiler.CurrentFile(relPath)
|
||||||
@@ -637,6 +653,7 @@ func (w *walker) updateFileInfo(dst, src protocol.FileInfo) protocol.FileInfo {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func handleError(ctx context.Context, context, path string, err error, finishedChan chan<- ScanResult) {
|
func handleError(ctx context.Context, context, path string, err error, finishedChan chan<- ScanResult) {
|
||||||
|
l.Debugf("handle error on '%v': %v: %v", path, context, err)
|
||||||
select {
|
select {
|
||||||
case finishedChan <- ScanResult{
|
case finishedChan <- ScanResult{
|
||||||
Err: fmt.Errorf("%s: %w", context, err),
|
Err: fmt.Errorf("%s: %w", context, err),
|
||||||
|
|||||||
@@ -239,8 +239,12 @@ func TestNormalization(t *testing.T) {
|
|||||||
if fd, err := testFs.OpenFile(filepath.Join("normalization", s1, s2), os.O_CREATE|os.O_EXCL, 0o644); err != nil {
|
if fd, err := testFs.OpenFile(filepath.Join("normalization", s1, s2), os.O_CREATE|os.O_EXCL, 0o644); err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
} else {
|
} else {
|
||||||
fd.Write([]byte("test"))
|
if _, err := fd.Write([]byte("test")); err != nil {
|
||||||
fd.Close()
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
if err := fd.Close(); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user