fs: remove Stat from FS interface

This commit is contained in:
Michael Eischer 2024-11-02 18:09:39 +01:00
parent 623ba92b98
commit 2f2ce9add2
6 changed files with 37 additions and 51 deletions

View file

@ -605,22 +605,6 @@ func join(elem ...string) string {
return path.Join(elem...) return path.Join(elem...)
} }
// statDir returns the file info for the directory. Symbolic links are
// resolved. If the target directory is not a directory, an error is returned.
func (arch *Archiver) statDir(dir string) (os.FileInfo, error) {
fi, err := arch.FS.Stat(dir)
if err != nil {
return nil, errors.WithStack(err)
}
tpe := fi.Mode() & (os.ModeType | os.ModeCharDevice)
if tpe != os.ModeDir {
return fi, errors.Errorf("path is not a directory: %v", dir)
}
return fi, nil
}
// saveTree stores a Tree in the repo, returned is the tree. snPath is the path // saveTree stores a Tree in the repo, returned is the tree. snPath is the path
// within the current snapshot. // within the current snapshot.
func (arch *Archiver) saveTree(ctx context.Context, snPath string, atree *tree, previous *restic.Tree, complete fileCompleteFunc) (futureNode, int, error) { func (arch *Archiver) saveTree(ctx context.Context, snPath string, atree *tree, previous *restic.Tree, complete fileCompleteFunc) (futureNode, int, error) {
@ -631,15 +615,8 @@ func (arch *Archiver) saveTree(ctx context.Context, snPath string, atree *tree,
return futureNode{}, 0, errors.Errorf("FileInfoPath for %v is empty", snPath) return futureNode{}, 0, errors.Errorf("FileInfoPath for %v is empty", snPath)
} }
fi, err := arch.statDir(atree.FileInfoPath) var err error
if err != nil { node, err = arch.dirPathToNode(snPath, atree.FileInfoPath)
return futureNode{}, 0, err
}
debug.Log("%v, dir node data loaded from %v", snPath, atree.FileInfoPath)
// in some cases reading xattrs for directories above the backup source is not allowed
// thus ignore errors for such folders.
node, err = arch.nodeFromFileInfo(snPath, atree.FileInfoPath, fi, true)
if err != nil { if err != nil {
return futureNode{}, 0, err return futureNode{}, 0, err
} }
@ -710,6 +687,36 @@ func (arch *Archiver) saveTree(ctx context.Context, snPath string, atree *tree,
return fn, len(nodes), nil return fn, len(nodes), nil
} }
func (arch *Archiver) dirPathToNode(snPath, target string) (node *restic.Node, err error) {
meta, err := arch.FS.OpenFile(target, fs.O_RDONLY)
if err != nil {
return nil, err
}
defer func() {
cerr := meta.Close()
if err == nil {
err = cerr
}
}()
debug.Log("%v, reading dir node data from %v", snPath, target)
fi, err := meta.Stat()
if err != nil {
return nil, errors.WithStack(err)
}
// in some cases reading xattrs for directories above the backup source is not allowed
// thus ignore errors for such folders.
node, err = arch.nodeFromFileInfo(snPath, target, fi, true)
if err != nil {
return nil, err
}
if node.Type != restic.NodeTypeDir {
return nil, errors.Errorf("path is not a directory: %v", target)
}
return node, err
}
// resolveRelativeTargets replaces targets that only contain relative // resolveRelativeTargets replaces targets that only contain relative
// directories ("." or "../../") with the contents of the directory. Each // directories ("." or "../../") with the contents of the directory. Each
// element of target is processed with fs.Clean(). // element of target is processed with fs.Clean().

View file

@ -34,12 +34,6 @@ func (fs Local) OpenFile(name string, flag int) (File, error) {
return f, nil return f, nil
} }
// Stat returns a FileInfo describing the named file. If there is an error, it
// will be of type *PathError.
func (fs Local) Stat(name string) (os.FileInfo, error) {
return os.Stat(fixpath(name))
}
// Lstat returns the FileInfo structure describing the named file. // Lstat returns the FileInfo structure describing the named file.
// If the file is a symbolic link, the returned FileInfo // If the file is a symbolic link, the returned FileInfo
// describes the symbolic link. Lstat makes no attempt to follow the link. // describes the symbolic link. Lstat makes no attempt to follow the link.

View file

@ -131,11 +131,6 @@ func (fs *LocalVss) OpenFile(name string, flag int) (File, error) {
return fs.FS.OpenFile(fs.snapshotPath(name), flag) return fs.FS.OpenFile(fs.snapshotPath(name), flag)
} }
// Stat wraps the Stat method of the underlying file system.
func (fs *LocalVss) Stat(name string) (os.FileInfo, error) {
return fs.FS.Stat(fs.snapshotPath(name))
}
// Lstat wraps the Lstat method of the underlying file system. // Lstat wraps the Lstat method of the underlying file system.
func (fs *LocalVss) Lstat(name string) (os.FileInfo, error) { func (fs *LocalVss) Lstat(name string) (os.FileInfo, error) {
return fs.FS.Lstat(fs.snapshotPath(name)) return fs.FS.Lstat(fs.snapshotPath(name))

View file

@ -317,16 +317,12 @@ func TestVSSFS(t *testing.T) {
// trigger snapshot creation and // trigger snapshot creation and
// capture FI while file still exists (should already be within the snapshot) // capture FI while file still exists (should already be within the snapshot)
origFi, err := localVss.Stat(tempfile) origFi, err := localVss.Lstat(tempfile)
rtest.OK(t, err) rtest.OK(t, err)
// remove original file // remove original file
rtest.OK(t, os.Remove(tempfile)) rtest.OK(t, os.Remove(tempfile))
statFi, err := localVss.Stat(tempfile)
rtest.OK(t, err)
rtest.Equals(t, origFi.Mode(), statFi.Mode())
lstatFi, err := localVss.Lstat(tempfile) lstatFi, err := localVss.Lstat(tempfile)
rtest.OK(t, err) rtest.OK(t, err)
rtest.Equals(t, origFi.Mode(), lstatFi.Mode()) rtest.Equals(t, origFi.Mode(), lstatFi.Mode())
@ -336,9 +332,10 @@ func TestVSSFS(t *testing.T) {
data, err := io.ReadAll(f) data, err := io.ReadAll(f)
rtest.OK(t, err) rtest.OK(t, err)
rtest.Equals(t, "example", string(data), "unexpected file content") rtest.Equals(t, "example", string(data), "unexpected file content")
rtest.OK(t, f.Close())
node, err := localVss.NodeFromFileInfo(tempfile, statFi, false) node, err := f.ToNode(false)
rtest.OK(t, err) rtest.OK(t, err)
rtest.Equals(t, node.Mode, statFi.Mode()) rtest.Equals(t, node.Mode, lstatFi.Mode())
rtest.OK(t, f.Close())
} }

View file

@ -81,12 +81,6 @@ func (fs *Reader) OpenFile(name string, flag int) (f File, err error) {
return nil, pathError("open", name, syscall.ENOENT) return nil, pathError("open", name, syscall.ENOENT)
} }
// Stat returns a FileInfo describing the named file. If there is an error, it
// will be of type *os.PathError.
func (fs *Reader) Stat(name string) (os.FileInfo, error) {
return fs.Lstat(name)
}
// Lstat returns the FileInfo structure describing the named file. // Lstat returns the FileInfo structure describing the named file.
// If the file is a symbolic link, the returned FileInfo // If the file is a symbolic link, the returned FileInfo
// describes the symbolic link. Lstat makes no attempt to follow the link. // describes the symbolic link. Lstat makes no attempt to follow the link.

View file

@ -10,7 +10,6 @@ import (
// FS bundles all methods needed for a file system. // FS bundles all methods needed for a file system.
type FS interface { type FS interface {
OpenFile(name string, flag int) (File, error) OpenFile(name string, flag int) (File, error)
Stat(name string) (os.FileInfo, error)
Lstat(name string) (os.FileInfo, error) Lstat(name string) (os.FileInfo, error)
DeviceID(fi os.FileInfo) (deviceID uint64, err error) DeviceID(fi os.FileInfo) (deviceID uint64, err error)
ExtendedStat(fi os.FileInfo) ExtendedFileInfo ExtendedStat(fi os.FileInfo) ExtendedFileInfo