1
0
Fork 0
mirror of https://github.com/restic/restic.git synced 2024-12-22 07:43:03 +00:00
restic/internal/fs/node_unix_test.go

147 lines
3.7 KiB
Go
Raw Normal View History

2022-03-28 20:23:47 +00:00
//go:build !windows
2017-04-06 18:36:09 +00:00
// +build !windows
2017-04-05 18:51:26 +00:00
package fs
2017-04-05 18:51:26 +00:00
import (
"io/fs"
2017-04-05 18:51:26 +00:00
"os"
"path/filepath"
2017-04-07 18:37:20 +00:00
"runtime"
2024-10-03 19:17:22 +00:00
"strings"
2017-04-05 18:51:26 +00:00
"syscall"
"testing"
2024-10-03 19:17:22 +00:00
"github.com/restic/restic/internal/errors"
"github.com/restic/restic/internal/restic"
rtest "github.com/restic/restic/internal/test"
2017-04-05 18:51:26 +00:00
)
func stat(t testing.TB, filename string) (fi os.FileInfo, ok bool) {
fi, err := os.Lstat(filename)
if err != nil && os.IsNotExist(err) {
return fi, false
}
if err != nil {
t.Fatal(err)
}
return fi, true
}
func checkFile(t testing.TB, fi fs.FileInfo, node *restic.Node) {
t.Helper()
stat := fi.Sys().(*syscall.Stat_t)
2017-04-06 18:36:09 +00:00
if uint32(node.Mode.Perm()) != uint32(stat.Mode&0777) {
2017-04-05 18:51:26 +00:00
t.Errorf("Mode does not match, want %v, got %v", stat.Mode&0777, node.Mode)
}
2017-04-06 18:36:09 +00:00
if node.Inode != uint64(stat.Ino) {
2017-04-05 18:51:26 +00:00
t.Errorf("Inode does not match, want %v, got %v", stat.Ino, node.Inode)
}
2017-04-06 18:36:09 +00:00
if node.DeviceID != uint64(stat.Dev) {
2017-04-05 18:51:26 +00:00
t.Errorf("Dev does not match, want %v, got %v", stat.Dev, node.DeviceID)
}
2024-07-09 17:51:44 +00:00
if node.Size != uint64(stat.Size) && node.Type != restic.NodeTypeSymlink {
2017-04-05 18:51:26 +00:00
t.Errorf("Size does not match, want %v, got %v", stat.Size, node.Size)
}
2017-04-06 18:36:09 +00:00
if node.Links != uint64(stat.Nlink) {
2017-04-05 18:51:26 +00:00
t.Errorf("Links does not match, want %v, got %v", stat.Nlink, node.Links)
}
2017-04-06 18:36:09 +00:00
if node.UID != stat.Uid {
t.Errorf("UID does not match, want %v, got %v", stat.Uid, node.UID)
2017-04-05 18:51:26 +00:00
}
2017-04-06 18:36:09 +00:00
if node.GID != stat.Gid {
t.Errorf("UID does not match, want %v, got %v", stat.Gid, node.GID)
2017-04-05 18:51:26 +00:00
}
2017-04-06 18:36:09 +00:00
// use the os dependent function to compare the timestamps
s := ExtendedStat(fi)
if node.ModTime != s.ModTime {
t.Errorf("ModTime does not match, want %v, got %v", s.ModTime, node.ModTime)
2017-04-05 18:51:26 +00:00
}
if node.ChangeTime != s.ChangeTime {
t.Errorf("ChangeTime does not match, want %v, got %v", s.ChangeTime, node.ChangeTime)
2017-04-05 18:51:26 +00:00
}
if node.AccessTime != s.AccessTime {
t.Errorf("AccessTime does not match, want %v, got %v", s.AccessTime, node.AccessTime)
2017-04-06 18:36:09 +00:00
}
2017-04-05 18:51:26 +00:00
}
func checkDevice(t testing.TB, fi fs.FileInfo, node *restic.Node) {
stat := fi.Sys().(*syscall.Stat_t)
2017-04-06 18:36:09 +00:00
if node.Device != uint64(stat.Rdev) {
2017-04-05 18:51:26 +00:00
t.Errorf("Rdev does not match, want %v, got %v", stat.Rdev, node.Device)
}
}
func TestNodeFromFileInfo(t *testing.T) {
tmp := t.TempDir()
symlink := filepath.Join(tmp, "symlink")
rtest.OK(t, os.Symlink("target", symlink))
2017-04-07 18:37:20 +00:00
type Test struct {
2017-04-05 18:51:26 +00:00
filename string
canSkip bool
2017-04-07 18:37:20 +00:00
}
var tests = []Test{
2017-04-05 18:51:26 +00:00
{"node_test.go", false},
{"/dev/sda", true},
{symlink, false},
2017-04-05 18:51:26 +00:00
}
2017-04-07 18:37:20 +00:00
// on darwin, users are not permitted to list the extended attributes of
// /dev/null, therefore skip it.
// on solaris, /dev/null is a symlink to a device node in /devices
// which does not support extended attributes, therefore skip it.
if runtime.GOOS != "darwin" && runtime.GOOS != "solaris" {
2017-04-07 18:37:20 +00:00
tests = append(tests, Test{"/dev/null", true})
}
2017-04-05 18:51:26 +00:00
for _, test := range tests {
t.Run("", func(t *testing.T) {
fi, found := stat(t, test.filename)
if !found && test.canSkip {
2018-01-17 22:14:37 +00:00
t.Skipf("%v not found in filesystem", test.filename)
2017-04-05 18:51:26 +00:00
return
}
fs := &Local{}
meta, err := fs.OpenFile(test.filename, O_NOFOLLOW, true)
rtest.OK(t, err)
node, err := meta.ToNode(false)
rtest.OK(t, err)
rtest.OK(t, meta.Close())
rtest.OK(t, err)
2017-04-05 18:51:26 +00:00
switch node.Type {
2024-07-09 17:51:44 +00:00
case restic.NodeTypeFile, restic.NodeTypeSymlink:
checkFile(t, fi, node)
2024-07-09 17:51:44 +00:00
case restic.NodeTypeDev, restic.NodeTypeCharDev:
checkFile(t, fi, node)
checkDevice(t, fi, node)
2017-04-05 18:51:26 +00:00
default:
t.Fatalf("invalid node type %q", node.Type)
}
})
}
}
2024-10-03 19:17:22 +00:00
func TestMknodError(t *testing.T) {
d := t.TempDir()
// Call mkfifo, which calls mknod, as mknod may give
// "operation not permitted" on Mac.
err := mkfifo(d, 0)
rtest.Assert(t, errors.Is(err, os.ErrExist), "want ErrExist, got %q", err)
rtest.Assert(t, strings.Contains(err.Error(), d), "filename not in %q", err)
}