archiver: ignore files removed in the meantime

This commit is contained in:
Michael Eischer
2024-11-02 22:55:16 +01:00
parent 8642049532
commit c5fb46da53
3 changed files with 71 additions and 2 deletions

View File

@@ -464,6 +464,12 @@ func (arch *Archiver) save(ctx context.Context, snPath, target string, previous
}
return futureNode{}, true, nil
}
filterNotExist := func(err error) error {
if errors.Is(err, os.ErrNotExist) {
return nil
}
return err
}
// exclude files by path before running Lstat to reduce number of lstat calls
if !arch.SelectByName(abstarget) {
debug.Log("%v is excluded by path", target)
@@ -473,7 +479,8 @@ func (arch *Archiver) save(ctx context.Context, snPath, target string, previous
meta, err := arch.FS.OpenFile(target, fs.O_NOFOLLOW, true)
if err != nil {
debug.Log("open metadata for %v returned error: %v", target, err)
return filterError(err)
// ignore if file disappeared since it was returned by readdir
return filterError(filterNotExist(err))
}
closeFile := true
defer func() {
@@ -489,7 +496,8 @@ func (arch *Archiver) save(ctx context.Context, snPath, target string, previous
fi, err := meta.Stat()
if err != nil {
debug.Log("lstat() for %v returned error: %v", target, err)
return filterError(err)
// ignore if file disappeared since it was returned by readdir
return filterError(filterNotExist(err))
}
if !arch.Select(abstarget, fi, arch.FS) {
debug.Log("%v is excluded", target)

View File

@@ -2479,3 +2479,48 @@ func TestIrregularFile(t *testing.T) {
t.Errorf("Save() excluded the node, that's unexpected")
}
}
type missingFS struct {
fs.FS
errorOnOpen bool
}
func (fs *missingFS) OpenFile(name string, flag int, metadataOnly bool) (fs.File, error) {
if fs.errorOnOpen {
return nil, os.ErrNotExist
}
return &missingFile{}, nil
}
type missingFile struct {
fs.File
}
func (f *missingFile) Stat() (os.FileInfo, error) {
return nil, os.ErrNotExist
}
func (f *missingFile) Close() error {
// prevent segfault in test
return nil
}
func TestDisappearedFile(t *testing.T) {
tempdir, repo := prepareTempdirRepoSrc(t, TestDir{})
back := rtest.Chdir(t, tempdir)
defer back()
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
// depending on the underlying FS implementation a missing file may be detected by OpenFile or
// the subsequent file.Stat() call. Thus test both cases.
for _, errorOnOpen := range []bool{false, true} {
arch := New(repo, fs.Track{FS: &missingFS{FS: &fs.Local{}, errorOnOpen: errorOnOpen}}, Options{})
_, excluded, err := arch.save(ctx, "/", filepath.Join(tempdir, "testdir"), nil)
rtest.OK(t, err)
rtest.Assert(t, excluded, "testfile should have been excluded")
}
}