backup: convert reject funcs to use FS interface

Depending on parameters the paths in a snapshot do not directly
correspond to real paths on the filesystem. Therefore, reject funcs must
use the FS interface to work correctly.
This commit is contained in:
Michael Eischer
2024-08-27 12:07:26 +02:00
parent c6fae0320e
commit f9dbcd2531
10 changed files with 98 additions and 88 deletions

View File

@@ -25,7 +25,7 @@ type SelectByNameFunc func(item string) bool
// SelectFunc returns true for all items that should be included (files and
// dirs). If false is returned, files are ignored and dirs are not even walked.
type SelectFunc func(item string, fi os.FileInfo) bool
type SelectFunc func(item string, fi os.FileInfo, fs fs.FS) bool
// ErrorFunc is called when an error during archiving occurs. When nil is
// returned, the archiver continues, otherwise it aborts and passes the error
@@ -178,12 +178,12 @@ func (o Options) ApplyDefaults() Options {
}
// New initializes a new archiver.
func New(repo archiverRepo, fs fs.FS, opts Options) *Archiver {
func New(repo archiverRepo, filesystem fs.FS, opts Options) *Archiver {
arch := &Archiver{
Repo: repo,
SelectByName: func(_ string) bool { return true },
Select: func(_ string, _ os.FileInfo) bool { return true },
FS: fs,
Select: func(_ string, _ os.FileInfo, _ fs.FS) bool { return true },
FS: filesystem,
Options: opts.ApplyDefaults(),
CompleteItem: func(string, *restic.Node, *restic.Node, ItemStats, time.Duration) {},
@@ -448,7 +448,7 @@ func (arch *Archiver) save(ctx context.Context, snPath, target string, previous
}
return futureNode{}, true, nil
}
if !arch.Select(abstarget, fi) {
if !arch.Select(abstarget, fi, arch.FS) {
debug.Log("%v is excluded", target)
return futureNode{}, true, nil
}

View File

@@ -1529,7 +1529,7 @@ func TestArchiverSnapshotSelect(t *testing.T) {
},
"other": TestFile{Content: "another file"},
},
selFn: func(item string, fi os.FileInfo) bool {
selFn: func(item string, fi os.FileInfo, _ fs.FS) bool {
return true
},
},
@@ -1546,7 +1546,7 @@ func TestArchiverSnapshotSelect(t *testing.T) {
},
"other": TestFile{Content: "another file"},
},
selFn: func(item string, fi os.FileInfo) bool {
selFn: func(item string, fi os.FileInfo, _ fs.FS) bool {
return false
},
err: "snapshot is empty",
@@ -1573,7 +1573,7 @@ func TestArchiverSnapshotSelect(t *testing.T) {
},
"other": TestFile{Content: "another file"},
},
selFn: func(item string, fi os.FileInfo) bool {
selFn: func(item string, fi os.FileInfo, _ fs.FS) bool {
return filepath.Ext(item) != ".txt"
},
},
@@ -1597,8 +1597,8 @@ func TestArchiverSnapshotSelect(t *testing.T) {
},
"other": TestFile{Content: "another file"},
},
selFn: func(item string, fi os.FileInfo) bool {
return filepath.Base(item) != "subdir"
selFn: func(item string, fi os.FileInfo, fs fs.FS) bool {
return fs.Base(item) != "subdir"
},
},
{
@@ -1606,8 +1606,8 @@ func TestArchiverSnapshotSelect(t *testing.T) {
src: TestDir{
"foo": TestFile{Content: "foo"},
},
selFn: func(item string, fi os.FileInfo) bool {
return filepath.IsAbs(item)
selFn: func(item string, fi os.FileInfo, fs fs.FS) bool {
return fs.IsAbs(item)
},
},
}

View File

@@ -22,11 +22,11 @@ type Scanner struct {
}
// NewScanner initializes a new Scanner.
func NewScanner(fs fs.FS) *Scanner {
func NewScanner(filesystem fs.FS) *Scanner {
return &Scanner{
FS: fs,
FS: filesystem,
SelectByName: func(_ string) bool { return true },
Select: func(_ string, _ os.FileInfo) bool { return true },
Select: func(_ string, _ os.FileInfo, _ fs.FS) bool { return true },
Error: func(_ string, err error) error { return err },
Result: func(_ string, _ ScanStats) {},
}
@@ -115,7 +115,7 @@ func (s *Scanner) scan(ctx context.Context, stats ScanStats, target string) (Sca
}
// run remaining select functions that require file information
if !s.Select(target, fi) {
if !s.Select(target, fi, s.FS) {
return stats, nil
}

View File

@@ -56,7 +56,7 @@ func TestScanner(t *testing.T) {
},
},
},
selFn: func(item string, fi os.FileInfo) bool {
selFn: func(item string, fi os.FileInfo, fs fs.FS) bool {
if fi.IsDir() {
return true
}

View File

@@ -46,6 +46,12 @@ func (fs Local) Lstat(name string) (os.FileInfo, error) {
return os.Lstat(fixpath(name))
}
// DeviceID extracts the DeviceID from the given FileInfo. If the fs does
// not support a DeviceID, it returns an error instead
func (fs Local) DeviceID(fi os.FileInfo) (deviceID uint64, err error) {
return DeviceID(fi)
}
// Join joins any number of path elements into a single path, adding a
// Separator if necessary. Join calls Clean on the result; in particular, all
// empty strings are ignored. On Windows, the result is a UNC path if and only

View File

@@ -122,6 +122,10 @@ func (fs *Reader) Lstat(name string) (os.FileInfo, error) {
return nil, pathError("lstat", name, os.ErrNotExist)
}
func (fs *Reader) DeviceID(_ os.FileInfo) (deviceID uint64, err error) {
return 0, errors.New("Device IDs are not supported")
}
// Join joins any number of path elements into a single path, adding a
// Separator if necessary. Join calls Clean on the result; in particular, all
// empty strings are ignored. On Windows, the result is a UNC path if and only

View File

@@ -10,6 +10,7 @@ type FS interface {
OpenFile(name string, flag int, perm os.FileMode) (File, error)
Stat(name string) (os.FileInfo, error)
Lstat(name string) (os.FileInfo, error)
DeviceID(fi os.FileInfo) (deviceID uint64, err error)
Join(elem ...string) string
Separator() string