fs: remove os.FileInfo from fs.ExtendedFileInfo

Only the `Sys()` value from os.FileInfo is kept as field `sys` to
support Windows. The os.FileInfo removal ensures that for values like
`ModTime` that existed in both data structures there's no more confusion
which value is actually used.
This commit is contained in:
Michael Eischer
2024-11-30 16:58:04 +01:00
parent 847b2efba2
commit 9a99141a5f
17 changed files with 80 additions and 178 deletions

View File

@@ -84,7 +84,7 @@ func checkMetadata(t *testing.T, f File, path string, follow bool, nodeType rest
fi2, err = os.Lstat(path)
}
rtest.OK(t, err)
assertFIEqual(t, fi2, fi.FileInfo)
assertFIEqual(t, fi2, fi)
node, err := f.ToNode(false)
rtest.OK(t, err)
@@ -94,13 +94,12 @@ func checkMetadata(t *testing.T, f File, path string, follow bool, nodeType rest
rtest.Equals(t, nodeType, node.Type, "node Type")
}
func assertFIEqual(t *testing.T, want os.FileInfo, got os.FileInfo) {
func assertFIEqual(t *testing.T, want os.FileInfo, got *ExtendedFileInfo) {
t.Helper()
rtest.Equals(t, want.Name(), got.Name(), "Name")
rtest.Equals(t, want.IsDir(), got.IsDir(), "IsDir")
rtest.Equals(t, want.ModTime(), got.ModTime(), "ModTime")
rtest.Equals(t, want.Mode(), got.Mode(), "Mode")
rtest.Equals(t, want.Size(), got.Size(), "Size")
rtest.Equals(t, want.Name(), got.Name, "Name")
rtest.Equals(t, want.ModTime(), got.ModTime, "ModTime")
rtest.Equals(t, want.Mode(), got.Mode, "Mode")
rtest.Equals(t, want.Size(), got.Size, "Size")
}
func TestFSLocalRead(t *testing.T) {
@@ -206,7 +205,7 @@ func TestFSLocalTypeChange(t *testing.T) {
fi, err := f.Stat()
rtest.OK(t, err)
if !fi.IsDir() {
if !fi.Mode.IsDir() {
// a file handle based implementation should still reference the file
checkMetadata(t, f, pathNew, false, restic.NodeTypeFile)

View File

@@ -325,7 +325,7 @@ func TestVSSFS(t *testing.T) {
lstatFi, err := localVss.Lstat(tempfile)
rtest.OK(t, err)
rtest.Equals(t, origFi.Mode(), lstatFi.Mode())
rtest.Equals(t, origFi.Mode, lstatFi.Mode)
f, err := localVss.OpenFile(tempfile, os.O_RDONLY, false)
rtest.OK(t, err)
@@ -335,7 +335,7 @@ func TestVSSFS(t *testing.T) {
node, err := f.ToNode(false)
rtest.OK(t, err)
rtest.Equals(t, node.Mode, lstatFi.Mode())
rtest.Equals(t, node.Mode, lstatFi.Mode)
rtest.OK(t, f.Close())
}

View File

@@ -43,12 +43,10 @@ func (fs *Reader) VolumeName(_ string) string {
func (fs *Reader) fi() *ExtendedFileInfo {
return &ExtendedFileInfo{
FileInfo: fakeFileInfo{
name: fs.Name,
size: fs.Size,
mode: fs.Mode,
modtime: fs.ModTime,
},
Name: fs.Name,
Mode: fs.Mode,
ModTime: fs.ModTime,
Size: fs.Size,
}
}
@@ -71,7 +69,7 @@ func (fs *Reader) OpenFile(name string, flag int, _ bool) (f File, err error) {
return f, nil
case "/", ".":
f = fakeDir{
entries: []string{fs.fi().Name()},
entries: []string{fs.fi().Name},
}
return f, nil
}
@@ -85,13 +83,12 @@ func (fs *Reader) OpenFile(name string, flag int, _ bool) (f File, err error) {
// If there is an error, it will be of type *os.PathError.
func (fs *Reader) Lstat(name string) (*ExtendedFileInfo, error) {
getDirInfo := func(name string) *ExtendedFileInfo {
fi := fakeFileInfo{
name: fs.Base(name),
size: 0,
mode: os.ModeDir | 0755,
modtime: time.Now(),
return &ExtendedFileInfo{
Name: fs.Base(name),
Size: 0,
Mode: os.ModeDir | 0755,
ModTime: time.Now(),
}
return &ExtendedFileInfo{FileInfo: fi}
}
switch name {
@@ -164,7 +161,7 @@ func newReaderFile(rd io.ReadCloser, fi *ExtendedFileInfo, allowEmptyFile bool)
AllowEmptyFile: allowEmptyFile,
fakeFile: fakeFile{
fi: fi,
name: fi.Name(),
name: fi.Name,
},
}
}
@@ -233,7 +230,7 @@ func (f fakeFile) Stat() (*ExtendedFileInfo, error) {
}
func (f fakeFile) ToNode(_ bool) (*restic.Node, error) {
node := buildBasicNode(f.name, f.fi.FileInfo)
node := buildBasicNode(f.name, f.fi)
// fill minimal info with current values for uid, gid
node.UID = uint32(os.Getuid())
@@ -256,38 +253,6 @@ func (d fakeDir) Readdirnames(n int) ([]string, error) {
return slices.Clone(d.entries), nil
}
// fakeFileInfo implements the bare minimum of os.FileInfo.
type fakeFileInfo struct {
name string
size int64
mode os.FileMode
modtime time.Time
}
func (fi fakeFileInfo) Name() string {
return fi.name
}
func (fi fakeFileInfo) Size() int64 {
return fi.size
}
func (fi fakeFileInfo) Mode() os.FileMode {
return fi.mode
}
func (fi fakeFileInfo) ModTime() time.Time {
return fi.modtime
}
func (fi fakeFileInfo) IsDir() bool {
return fi.mode&os.ModeDir > 0
}
func (fi fakeFileInfo) Sys() interface{} {
return nil
}
func pathError(op, name string, err error) *os.PathError {
return &os.PathError{Op: op, Path: name, Err: err}
}

View File

@@ -61,24 +61,24 @@ func verifyDirectoryContents(t testing.TB, fs FS, dir string, want []string) {
}
func checkFileInfo(t testing.TB, fi *ExtendedFileInfo, filename string, modtime time.Time, mode os.FileMode, isdir bool) {
if fi.IsDir() != isdir {
t.Errorf("IsDir returned %t, want %t", fi.IsDir(), isdir)
if fi.Mode.IsDir() != isdir {
t.Errorf("IsDir returned %t, want %t", fi.Mode.IsDir(), isdir)
}
if fi.Mode() != mode {
t.Errorf("Mode() returned wrong value, want 0%o, got 0%o", mode, fi.Mode())
if fi.Mode != mode {
t.Errorf("Mode has wrong value, want 0%o, got 0%o", mode, fi.Mode)
}
if !modtime.Equal(time.Time{}) && !fi.FileInfo.ModTime().Equal(modtime) {
t.Errorf("ModTime() returned wrong value, want %v, got %v", modtime, fi.FileInfo.ModTime())
if !modtime.Equal(time.Time{}) && !fi.ModTime.Equal(modtime) {
t.Errorf("ModTime has wrong value, want %v, got %v", modtime, fi.ModTime)
}
if path.Base(fi.Name()) != fi.Name() {
t.Errorf("Name() returned is not base, want %q, got %q", path.Base(fi.Name()), fi.Name())
if path.Base(fi.Name) != fi.Name {
t.Errorf("Name is not base, want %q, got %q", path.Base(fi.Name), fi.Name)
}
if fi.Name() != path.Base(filename) {
t.Errorf("Name() returned wrong value, want %q, got %q", path.Base(filename), fi.Name())
if fi.Name != path.Base(filename) {
t.Errorf("Name has wrong value, want %q, got %q", path.Base(filename), fi.Name)
}
}

View File

@@ -16,7 +16,7 @@ import (
// nodeFromFileInfo returns a new node from the given path and FileInfo. It
// returns the first error that is encountered, together with a node.
func nodeFromFileInfo(path string, fi *ExtendedFileInfo, ignoreXattrListError bool) (*restic.Node, error) {
node := buildBasicNode(path, fi.FileInfo)
node := buildBasicNode(path, fi)
if err := nodeFillExtendedStat(node, path, fi); err != nil {
return node, err
@@ -27,18 +27,18 @@ func nodeFromFileInfo(path string, fi *ExtendedFileInfo, ignoreXattrListError bo
return node, err
}
func buildBasicNode(path string, fi os.FileInfo) *restic.Node {
func buildBasicNode(path string, fi *ExtendedFileInfo) *restic.Node {
mask := os.ModePerm | os.ModeType | os.ModeSetuid | os.ModeSetgid | os.ModeSticky
node := &restic.Node{
Path: path,
Name: fi.Name(),
Mode: fi.Mode() & mask,
ModTime: fi.ModTime(),
Name: fi.Name,
Mode: fi.Mode & mask,
ModTime: fi.ModTime,
}
node.Type = nodeTypeFromFileInfo(fi.Mode())
node.Type = nodeTypeFromFileInfo(fi.Mode)
if node.Type == restic.NodeTypeFile {
node.Size = uint64(fi.Size())
node.Size = uint64(fi.Size)
}
return node
}

View File

@@ -361,7 +361,7 @@ func nodeFillGenericAttributes(node *restic.Node, path string, stat *ExtendedFil
}
}
winFI := stat.Sys().(*syscall.Win32FileAttributeData)
winFI := stat.sys.(*syscall.Win32FileAttributeData)
// Add Windows attributes
node.GenericAttributes, err = restic.WindowsAttrsToGenericAttributes(restic.WindowsAttributes{

View File

@@ -8,7 +8,8 @@ import (
// ExtendedFileInfo is an extended stat_t, filled with attributes that are
// supported by most operating systems. The original FileInfo is embedded.
type ExtendedFileInfo struct {
os.FileInfo
Name string
Mode os.FileMode
DeviceID uint64 // ID of device containing the file
Inode uint64 // Inode number
@@ -23,6 +24,9 @@ type ExtendedFileInfo struct {
AccessTime time.Time // last access time stamp
ModTime time.Time // last (content) modification time stamp
ChangeTime time.Time // last status change time stamp
// nolint:unused // only used on Windows
sys any // Value returned by os.FileInfo.Sys()
}
// ExtendedStat returns an ExtendedFileInfo constructed from the os.FileInfo.

View File

@@ -14,7 +14,9 @@ func extendedStat(fi os.FileInfo) *ExtendedFileInfo {
s := fi.Sys().(*syscall.Stat_t)
return &ExtendedFileInfo{
FileInfo: fi,
Name: fi.Name(),
Mode: fi.Mode(),
DeviceID: uint64(s.Dev),
Inode: uint64(s.Ino),
Links: uint64(s.Nlink),

View File

@@ -14,7 +14,9 @@ func extendedStat(fi os.FileInfo) *ExtendedFileInfo {
s := fi.Sys().(*syscall.Stat_t)
return &ExtendedFileInfo{
FileInfo: fi,
Name: fi.Name(),
Mode: fi.Mode(),
DeviceID: uint64(s.Dev),
Inode: s.Ino,
Links: uint64(s.Nlink),

View File

@@ -18,8 +18,11 @@ func extendedStat(fi os.FileInfo) *ExtendedFileInfo {
}
extFI := ExtendedFileInfo{
FileInfo: fi,
Size: int64(s.FileSizeLow) | (int64(s.FileSizeHigh) << 32),
Name: fi.Name(),
Mode: fi.Mode(),
Size: int64(s.FileSizeLow) | (int64(s.FileSizeHigh) << 32),
sys: fi.Sys(),
}
atime := syscall.NsecToTimespec(s.LastAccessTime.Nanoseconds())