mirror of
https://github.com/octoleo/restic.git
synced 2024-11-23 13:17:42 +00:00
bf054c09d2
On FreeBSD, limited users may not be able to even list xattrs for the parent directories above the snapshot source paths. As this can cause the backup to fail, just ignore those errors.
148 lines
3.4 KiB
Go
148 lines
3.4 KiB
Go
//go:build !windows
|
|
// +build !windows
|
|
|
|
package restic
|
|
|
|
import (
|
|
"os"
|
|
"path/filepath"
|
|
"runtime"
|
|
"syscall"
|
|
"testing"
|
|
"time"
|
|
|
|
rtest "github.com/restic/restic/internal/test"
|
|
)
|
|
|
|
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, stat *syscall.Stat_t, node *Node) {
|
|
t.Helper()
|
|
if uint32(node.Mode.Perm()) != uint32(stat.Mode&0777) {
|
|
t.Errorf("Mode does not match, want %v, got %v", stat.Mode&0777, node.Mode)
|
|
}
|
|
|
|
if node.Inode != uint64(stat.Ino) {
|
|
t.Errorf("Inode does not match, want %v, got %v", stat.Ino, node.Inode)
|
|
}
|
|
|
|
if node.DeviceID != uint64(stat.Dev) {
|
|
t.Errorf("Dev does not match, want %v, got %v", stat.Dev, node.DeviceID)
|
|
}
|
|
|
|
if node.Size != uint64(stat.Size) && node.Type != "symlink" {
|
|
t.Errorf("Size does not match, want %v, got %v", stat.Size, node.Size)
|
|
}
|
|
|
|
if node.Links != uint64(stat.Nlink) {
|
|
t.Errorf("Links does not match, want %v, got %v", stat.Nlink, node.Links)
|
|
}
|
|
|
|
if node.UID != stat.Uid {
|
|
t.Errorf("UID does not match, want %v, got %v", stat.Uid, node.UID)
|
|
}
|
|
|
|
if node.GID != stat.Gid {
|
|
t.Errorf("UID does not match, want %v, got %v", stat.Gid, node.GID)
|
|
}
|
|
|
|
// use the os dependent function to compare the timestamps
|
|
s, ok := toStatT(stat)
|
|
if !ok {
|
|
return
|
|
}
|
|
|
|
mtime := s.mtim()
|
|
if node.ModTime != time.Unix(mtime.Unix()) {
|
|
t.Errorf("ModTime does not match, want %v, got %v", time.Unix(mtime.Unix()), node.ModTime)
|
|
}
|
|
|
|
ctime := s.ctim()
|
|
if node.ChangeTime != time.Unix(ctime.Unix()) {
|
|
t.Errorf("ChangeTime does not match, want %v, got %v", time.Unix(ctime.Unix()), node.ChangeTime)
|
|
}
|
|
|
|
atime := s.atim()
|
|
if node.AccessTime != time.Unix(atime.Unix()) {
|
|
t.Errorf("AccessTime does not match, want %v, got %v", time.Unix(atime.Unix()), node.AccessTime)
|
|
}
|
|
|
|
}
|
|
|
|
func checkDevice(t testing.TB, stat *syscall.Stat_t, node *Node) {
|
|
if node.Device != uint64(stat.Rdev) {
|
|
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))
|
|
|
|
type Test struct {
|
|
filename string
|
|
canSkip bool
|
|
}
|
|
var tests = []Test{
|
|
{"node_test.go", false},
|
|
{"/dev/sda", true},
|
|
{symlink, false},
|
|
}
|
|
|
|
// 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" {
|
|
tests = append(tests, Test{"/dev/null", true})
|
|
}
|
|
|
|
for _, test := range tests {
|
|
t.Run("", func(t *testing.T) {
|
|
fi, found := stat(t, test.filename)
|
|
if !found && test.canSkip {
|
|
t.Skipf("%v not found in filesystem", test.filename)
|
|
return
|
|
}
|
|
|
|
if fi.Sys() == nil {
|
|
t.Skip("fi.Sys() is nil")
|
|
return
|
|
}
|
|
|
|
s, ok := fi.Sys().(*syscall.Stat_t)
|
|
if !ok {
|
|
t.Skipf("fi type is %T, not stat_t", fi.Sys())
|
|
return
|
|
}
|
|
|
|
node, err := NodeFromFileInfo(test.filename, fi, false)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
switch node.Type {
|
|
case "file", "symlink":
|
|
checkFile(t, s, node)
|
|
case "dev", "chardev":
|
|
checkFile(t, s, node)
|
|
checkDevice(t, s, node)
|
|
default:
|
|
t.Fatalf("invalid node type %q", node.Type)
|
|
}
|
|
})
|
|
}
|
|
}
|