diff --git a/pipe/pipe.go b/pipe/pipe.go index 4ff380d3e..b301af60d 100644 --- a/pipe/pipe.go +++ b/pipe/pipe.go @@ -4,6 +4,7 @@ import ( "errors" "fmt" "os" + "path" "path/filepath" "sort" @@ -82,13 +83,13 @@ func isFile(fi os.FileInfo) bool { var errCancelled = errors.New("walk cancelled") -func walk(basedir, path string, done chan struct{}, jobs chan<- Job, res chan<- Result) error { - info, err := os.Lstat(path) +func walk(basedir, dir string, done chan struct{}, jobs chan<- Job, res chan<- Result) error { + info, err := os.Lstat(dir) if err != nil { return err } - relpath, _ := filepath.Rel(basedir, path) + relpath, _ := filepath.Rel(basedir, dir) if !info.IsDir() { select { @@ -99,15 +100,29 @@ func walk(basedir, path string, done chan struct{}, jobs chan<- Job, res chan<- return nil } - names, err := readDirNames(path) + names, err := readDirNames(dir) if err != nil { return err } + // Insert breakpoint to allow testing behaviour with vanishing files + // between Readdir() and lstat() + debug.BreakIf("pipe.walk1", func() bool { + match, err := path.Match(os.Getenv("DEBUG_BREAK_PIPE"), relpath) + if err != nil { + panic(err) + } + if match { + debug.Log("break", "break pattern matches for %v\n", relpath) + } + + return match + }) + entries := make([]<-chan Result, 0, len(names)) for _, name := range names { - subpath := filepath.Join(path, name) + subpath := filepath.Join(dir, name) ch := make(chan Result, 1) entries = append(entries, ch) @@ -122,6 +137,22 @@ func walk(basedir, path string, done chan struct{}, jobs chan<- Job, res chan<- continue } + // Insert breakpoint to allow testing behaviour with vanishing files + // between walk and open + debug.BreakIf("pipe.walk2", func() bool { + p := filepath.Join(relpath, name) + + match, err := path.Match(os.Getenv("DEBUG_BREAK_PIPE"), p) + if err != nil { + panic(err) + } + if match { + debug.Log("break", "break pattern matches for %v\n", p) + } + + return match + }) + if isDir(fi) { err = walk(basedir, subpath, done, jobs, ch) if err != nil { diff --git a/testsuite/test-backup-missing-file.sh b/testsuite/test-backup-missing-file.sh deleted file mode 100755 index 996669fdf..000000000 --- a/testsuite/test-backup-missing-file.sh +++ /dev/null @@ -1,16 +0,0 @@ -set -em - -# setup restic -prepare -run restic init - -# start backup, break before saving files -DEBUG_BREAK=Archiver.Snapshot run restic.debug backup "${BASE}/fake-data" && debug "done" - -# remove file -rm -f "${BASE}/fake-data/0/0/9/37" - -# resume backup -fg - -cleanup diff --git a/testsuite/test-backup-missing-file1.sh b/testsuite/test-backup-missing-file1.sh new file mode 100755 index 000000000..87a2dc26c --- /dev/null +++ b/testsuite/test-backup-missing-file1.sh @@ -0,0 +1,16 @@ +set -em + +# setup restic +prepare +run restic init + +# start backup, break between readdir and lstat +DEBUG_BREAK=pipe.walk1 DEBUG_BREAK_PIPE="fake-data/0/0/9" run restic.debug backup "${BASE}/fake-data" && debug "done" + +# remove file +rm -f "${BASE}/fake-data/0/0/9/37" + +# resume backup +fg + +cleanup diff --git a/testsuite/test-backup-missing-file2.sh b/testsuite/test-backup-missing-file2.sh new file mode 100755 index 000000000..c93d84b06 --- /dev/null +++ b/testsuite/test-backup-missing-file2.sh @@ -0,0 +1,16 @@ +set -em + +# setup restic +prepare +run restic init + +# start backup, break between walk and save +DEBUG_BREAK=pipe.walk2 DEBUG_BREAK_PIPE="fake-data/0/0/9/37" run restic.debug backup "${BASE}/fake-data" && debug "done" + +# remove file +rm -f "${BASE}/fake-data/0/0/9/37" + +# resume backup +fg + +cleanup