1
0
Fork 0
mirror of https://github.com/restic/restic.git synced 2024-12-21 23:33:03 +00:00

archiver: fix file type change test

The test did not test the case that the type of a file changed
unexpectedly.
This commit is contained in:
Michael Eischer 2024-11-15 21:21:04 +01:00
parent d7f4b9db60
commit 6cb19e0190
2 changed files with 66 additions and 35 deletions

View file

@ -369,7 +369,7 @@ func (arch *Archiver) dirToNodeAndEntries(snPath, dir string, meta fs.File) (nod
return nil, nil, err return nil, nil, err
} }
if node.Type != restic.NodeTypeDir { if node.Type != restic.NodeTypeDir {
return nil, nil, fmt.Errorf("directory %v changed type, refusing to archive", snPath) return nil, nil, fmt.Errorf("directory %q changed type, refusing to archive", snPath)
} }
names, err = meta.Readdirnames(-1) names, err = meta.Readdirnames(-1)
@ -548,7 +548,7 @@ func (arch *Archiver) save(ctx context.Context, snPath, target string, previous
// make sure it's still a file // make sure it's still a file
if !fi.Mode().IsRegular() { if !fi.Mode().IsRegular() {
err = errors.Errorf("file %v changed type, refusing to archive", target) err = errors.Errorf("file %q changed type, refusing to archive", target)
return filterError(err) return filterError(err)
} }

View file

@ -2202,9 +2202,10 @@ func snapshot(t testing.TB, repo archiverRepo, fs fs.FS, parent *restic.Snapshot
type overrideFS struct { type overrideFS struct {
fs.FS fs.FS
overrideFI os.FileInfo overrideFI os.FileInfo
overrideNode *restic.Node resetFIOnRead bool
overrideErr error overrideNode *restic.Node
overrideErr error
} }
func (m *overrideFS) OpenFile(name string, flag int, metadataOnly bool) (fs.File, error) { func (m *overrideFS) OpenFile(name string, flag int, metadataOnly bool) (fs.File, error) {
@ -2213,7 +2214,7 @@ func (m *overrideFS) OpenFile(name string, flag int, metadataOnly bool) (fs.File
return f, err return f, err
} }
if filepath.Base(name) == "testfile" { if filepath.Base(name) == "testfile" || filepath.Base(name) == "testdir" {
return &overrideFile{f, m}, nil return &overrideFile{f, m}, nil
} }
return f, nil return f, nil
@ -2225,7 +2226,18 @@ type overrideFile struct {
} }
func (f overrideFile) Stat() (os.FileInfo, error) { func (f overrideFile) Stat() (os.FileInfo, error) {
if f.ofs.overrideFI == nil {
return f.File.Stat()
}
return f.ofs.overrideFI, nil return f.ofs.overrideFI, nil
}
func (f overrideFile) MakeReadable() error {
if f.ofs.resetFIOnRead {
f.ofs.overrideFI = nil
}
return f.File.MakeReadable()
} }
func (f overrideFile) ToNode(ignoreXattrListError bool) (*restic.Node, error) { func (f overrideFile) ToNode(ignoreXattrListError bool) (*restic.Node, error) {
@ -2320,48 +2332,67 @@ func TestMetadataChanged(t *testing.T) {
checker.TestCheckRepo(t, repo, false) checker.TestCheckRepo(t, repo, false)
} }
func TestRacyFileSwap(t *testing.T) { func TestRacyFileTypeSwap(t *testing.T) {
files := TestDir{ files := TestDir{
"testfile": TestFile{ "testfile": TestFile{
Content: "foo bar test file", Content: "foo bar test file",
}, },
"testdir": TestDir{},
} }
tempdir, repo := prepareTempdirRepoSrc(t, files) for _, dirError := range []bool{false, true} {
desc := "file changed type"
if dirError {
desc = "dir changed type"
}
t.Run(desc, func(t *testing.T) {
tempdir, repo := prepareTempdirRepoSrc(t, files)
back := rtest.Chdir(t, tempdir) back := rtest.Chdir(t, tempdir)
defer back() defer back()
// get metadata of current folder // get metadata of current folder
fi := lstat(t, ".") var fakeName, realName string
tempfile := filepath.Join(tempdir, "testfile") if dirError {
// lstat claims this is a directory, but it's actually a file
fakeName = "testdir"
realName = "testfile"
} else {
fakeName = "testfile"
realName = "testdir"
}
fakeFI := lstat(t, fakeName)
tempfile := filepath.Join(tempdir, realName)
statfs := &overrideFS{ statfs := &overrideFS{
FS: fs.Local{}, FS: fs.Local{},
overrideFI: fi, overrideFI: fakeFI,
} resetFIOnRead: true,
}
ctx, cancel := context.WithCancel(context.Background()) ctx, cancel := context.WithCancel(context.Background())
defer cancel() defer cancel()
wg, ctx := errgroup.WithContext(ctx) wg, ctx := errgroup.WithContext(ctx)
repo.StartPackUploader(ctx, wg) repo.StartPackUploader(ctx, wg)
arch := New(repo, fs.Track{FS: statfs}, Options{}) arch := New(repo, fs.Track{FS: statfs}, Options{})
arch.Error = func(item string, err error) error { arch.Error = func(item string, err error) error {
t.Logf("archiver error as expected for %v: %v", item, err) t.Logf("archiver error as expected for %v: %v", item, err)
return err return err
} }
arch.runWorkers(ctx, wg) arch.runWorkers(ctx, wg)
// fs.Track will panic if the file was not closed // fs.Track will panic if the file was not closed
_, excluded, err := arch.save(ctx, "/", tempfile, nil) _, excluded, err := arch.save(ctx, "/", tempfile, nil)
if err == nil { rtest.Assert(t, err != nil && strings.Contains(err.Error(), "changed type, refusing to archive"), "save() returned wrong error: %v", err)
t.Errorf("Save() should have failed") tpe := "file"
} if dirError {
tpe = "directory"
if excluded { }
t.Errorf("Save() excluded the node, that's unexpected") rtest.Assert(t, strings.Contains(err.Error(), tpe+" "), "unexpected item type in error: %v", err)
rtest.Assert(t, !excluded, "Save() excluded the node, that's unexpected")
})
} }
} }