data: split node and snapshot code from restic package

This commit is contained in:
Michael Eischer
2025-09-23 20:01:09 +02:00
parent c85b157e0e
commit 56ac8360c7
166 changed files with 1170 additions and 1107 deletions

View File

@@ -8,7 +8,7 @@ import (
"strings"
"time"
"github.com/restic/restic/internal/restic"
"github.com/restic/restic/internal/data"
"golang.org/x/sys/windows"
)
@@ -115,7 +115,7 @@ func clearAttribute(path string, attribute uint32) error {
}
// openHandleForEA return a file handle for file or dir for setting/getting EAs
func openHandleForEA(nodeType restic.NodeType, path string, writeAccess bool) (handle windows.Handle, err error) {
func openHandleForEA(nodeType data.NodeType, path string, writeAccess bool) (handle windows.Handle, err error) {
path = fixpath(path)
fileAccess := windows.FILE_READ_EA
if writeAccess {
@@ -123,10 +123,10 @@ func openHandleForEA(nodeType restic.NodeType, path string, writeAccess bool) (h
}
switch nodeType {
case restic.NodeTypeFile:
case data.NodeTypeFile:
utf16Path := windows.StringToUTF16Ptr(path)
handle, err = windows.CreateFile(utf16Path, uint32(fileAccess), 0, nil, windows.OPEN_EXISTING, windows.FILE_ATTRIBUTE_NORMAL, 0)
case restic.NodeTypeDir:
case data.NodeTypeDir:
utf16Path := windows.StringToUTF16Ptr(path)
handle, err = windows.CreateFile(utf16Path, uint32(fileAccess), 0, nil, windows.OPEN_EXISTING, windows.FILE_ATTRIBUTE_NORMAL|windows.FILE_FLAG_BACKUP_SEMANTICS, 0)
default:

View File

@@ -4,7 +4,7 @@ import (
"os"
"path/filepath"
"github.com/restic/restic/internal/restic"
"github.com/restic/restic/internal/data"
)
// Local is the local file system. Most methods are just passed on to the stdlib.
@@ -152,7 +152,7 @@ func (f *localFile) Stat() (*ExtendedFileInfo, error) {
return f.fi, err
}
func (f *localFile) ToNode(ignoreXattrListError bool, warnf func(format string, args ...any)) (*restic.Node, error) {
func (f *localFile) ToNode(ignoreXattrListError bool, warnf func(format string, args ...any)) (*data.Node, error) {
if err := f.cacheFI(); err != nil {
return nil, err
}

View File

@@ -7,7 +7,7 @@ import (
"slices"
"testing"
"github.com/restic/restic/internal/restic"
"github.com/restic/restic/internal/data"
rtest "github.com/restic/restic/internal/test"
)
@@ -15,7 +15,7 @@ type fsLocalMetadataTestcase struct {
name string
follow bool
setup func(t *testing.T, path string)
nodeType restic.NodeType
nodeType data.NodeType
}
func TestFSLocalMetadata(t *testing.T) {
@@ -25,21 +25,21 @@ func TestFSLocalMetadata(t *testing.T) {
setup: func(t *testing.T, path string) {
rtest.OK(t, os.WriteFile(path, []byte("example"), 0o600))
},
nodeType: restic.NodeTypeFile,
nodeType: data.NodeTypeFile,
},
{
name: "directory",
setup: func(t *testing.T, path string) {
rtest.OK(t, os.Mkdir(path, 0o600))
},
nodeType: restic.NodeTypeDir,
nodeType: data.NodeTypeDir,
},
{
name: "symlink",
setup: func(t *testing.T, path string) {
rtest.OK(t, os.Symlink(path+"old", path))
},
nodeType: restic.NodeTypeSymlink,
nodeType: data.NodeTypeSymlink,
},
{
name: "symlink file",
@@ -48,7 +48,7 @@ func TestFSLocalMetadata(t *testing.T) {
rtest.OK(t, os.WriteFile(path+"file", []byte("example"), 0o600))
rtest.OK(t, os.Symlink(path+"file", path))
},
nodeType: restic.NodeTypeFile,
nodeType: data.NodeTypeFile,
},
} {
runFSLocalTestcase(t, test)
@@ -74,7 +74,7 @@ func runFSLocalTestcase(t *testing.T, test fsLocalMetadataTestcase) {
}
func checkMetadata(t *testing.T, f File, path string, follow bool, nodeType restic.NodeType) {
func checkMetadata(t *testing.T, f File, path string, follow bool, nodeType data.NodeType) {
fi, err := f.Stat()
rtest.OK(t, err)
var fi2 os.FileInfo
@@ -114,7 +114,7 @@ func testFSLocalRead(t *testing.T, makeReadable bool) {
rtest.OK(t, os.WriteFile(path, []byte(testdata), 0o600))
f := openReadable(t, path, makeReadable)
checkMetadata(t, f, path, false, restic.NodeTypeFile)
checkMetadata(t, f, path, false, data.NodeTypeFile)
data, err := io.ReadAll(f)
rtest.OK(t, err)
@@ -147,7 +147,7 @@ func testFSLocalReaddir(t *testing.T, makeReadable bool) {
rtest.OK(t, os.WriteFile(filepath.Join(path, entries[0]), []byte("example"), 0o600))
f := openReadable(t, path, makeReadable)
checkMetadata(t, f, path, false, restic.NodeTypeDir)
checkMetadata(t, f, path, false, data.NodeTypeDir)
names, err := f.Readdirnames(-1)
rtest.OK(t, err)
@@ -173,7 +173,7 @@ func TestFSLocalReadableRace(t *testing.T) {
err = f.MakeReadable()
if err == nil {
// a file handle based implementation should still work
checkMetadata(t, f, pathNew, false, restic.NodeTypeFile)
checkMetadata(t, f, pathNew, false, data.NodeTypeFile)
data, err := io.ReadAll(f)
rtest.OK(t, err)
@@ -207,7 +207,7 @@ func TestFSLocalTypeChange(t *testing.T) {
rtest.OK(t, err)
if !fi.Mode.IsDir() {
// a file handle based implementation should still reference the file
checkMetadata(t, f, pathNew, false, restic.NodeTypeFile)
checkMetadata(t, f, pathNew, false, data.NodeTypeFile)
data, err := io.ReadAll(f)
rtest.OK(t, err)

View File

@@ -6,7 +6,7 @@ import (
"syscall"
"testing"
"github.com/restic/restic/internal/restic"
"github.com/restic/restic/internal/data"
rtest "github.com/restic/restic/internal/test"
)
@@ -24,14 +24,14 @@ func TestFSLocalMetadataUnix(t *testing.T) {
addr := &syscall.SockaddrUnix{Name: path}
rtest.OK(t, syscall.Bind(fd, addr))
},
nodeType: restic.NodeTypeSocket,
nodeType: data.NodeTypeSocket,
},
{
name: "fifo",
setup: func(t *testing.T, path string) {
rtest.OK(t, mkfifo(path, 0o600))
},
nodeType: restic.NodeTypeFifo,
nodeType: data.NodeTypeFifo,
},
// device files can only be created as root
} {

View File

@@ -10,8 +10,8 @@ import (
"syscall"
"time"
"github.com/restic/restic/internal/data"
"github.com/restic/restic/internal/errors"
"github.com/restic/restic/internal/restic"
)
// Reader is a file system which provides a directory with a single file. When
@@ -267,7 +267,7 @@ func (f fakeFile) Stat() (*ExtendedFileInfo, error) {
return f.fi, nil
}
func (f fakeFile) ToNode(_ bool, _ func(format string, args ...any)) (*restic.Node, error) {
func (f fakeFile) ToNode(_ bool, _ func(format string, args ...any)) (*data.Node, error) {
node := buildBasicNode(f.name, f.fi)
// fill minimal info with current values for uid, gid

View File

@@ -3,7 +3,7 @@ package fs
import (
"io"
"github.com/restic/restic/internal/restic"
"github.com/restic/restic/internal/data"
)
// FS bundles all methods needed for a file system.
@@ -45,8 +45,8 @@ type File interface {
Readdirnames(n int) ([]string, error)
Stat() (*ExtendedFileInfo, error)
// ToNode returns a restic.Node for the File. The internally used os.FileInfo
// ToNode returns a data.Node for the File. The internally used os.FileInfo
// must be consistent with that returned by Stat(). In particular, the metadata
// returned by consecutive calls to Stat() and ToNode() must match.
ToNode(ignoreXattrListError bool, warnf func(format string, args ...any)) (*restic.Node, error)
ToNode(ignoreXattrListError bool, warnf func(format string, args ...any)) (*data.Node, error)
}

View File

@@ -8,14 +8,14 @@ import (
"sync"
"syscall"
"github.com/restic/restic/internal/data"
"github.com/restic/restic/internal/debug"
"github.com/restic/restic/internal/errors"
"github.com/restic/restic/internal/restic"
)
// 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, warnf func(format string, args ...any)) (*restic.Node, error) {
func nodeFromFileInfo(path string, fi *ExtendedFileInfo, ignoreXattrListError bool, warnf func(format string, args ...any)) (*data.Node, error) {
node := buildBasicNode(path, fi)
if err := nodeFillExtendedStat(node, path, fi); err != nil {
@@ -27,9 +27,9 @@ func nodeFromFileInfo(path string, fi *ExtendedFileInfo, ignoreXattrListError bo
return node, err
}
func buildBasicNode(path string, fi *ExtendedFileInfo) *restic.Node {
func buildBasicNode(path string, fi *ExtendedFileInfo) *data.Node {
mask := os.ModePerm | os.ModeType | os.ModeSetuid | os.ModeSetgid | os.ModeSticky
node := &restic.Node{
node := &data.Node{
Path: path,
Name: fi.Name,
Mode: fi.Mode & mask,
@@ -37,36 +37,36 @@ func buildBasicNode(path string, fi *ExtendedFileInfo) *restic.Node {
}
node.Type = nodeTypeFromFileInfo(fi.Mode)
if node.Type == restic.NodeTypeFile {
if node.Type == data.NodeTypeFile {
node.Size = uint64(fi.Size)
}
return node
}
func nodeTypeFromFileInfo(mode os.FileMode) restic.NodeType {
func nodeTypeFromFileInfo(mode os.FileMode) data.NodeType {
switch mode & os.ModeType {
case 0:
return restic.NodeTypeFile
return data.NodeTypeFile
case os.ModeDir:
return restic.NodeTypeDir
return data.NodeTypeDir
case os.ModeSymlink:
return restic.NodeTypeSymlink
return data.NodeTypeSymlink
case os.ModeDevice | os.ModeCharDevice:
return restic.NodeTypeCharDev
return data.NodeTypeCharDev
case os.ModeDevice:
return restic.NodeTypeDev
return data.NodeTypeDev
case os.ModeNamedPipe:
return restic.NodeTypeFifo
return data.NodeTypeFifo
case os.ModeSocket:
return restic.NodeTypeSocket
return data.NodeTypeSocket
case os.ModeIrregular:
return restic.NodeTypeIrregular
return data.NodeTypeIrregular
}
return restic.NodeTypeInvalid
return data.NodeTypeInvalid
}
func nodeFillExtendedStat(node *restic.Node, path string, stat *ExtendedFileInfo) error {
func nodeFillExtendedStat(node *data.Node, path string, stat *ExtendedFileInfo) error {
node.Inode = stat.Inode
node.DeviceID = stat.DeviceID
node.ChangeTime = stat.ChangeTime
@@ -78,25 +78,25 @@ func nodeFillExtendedStat(node *restic.Node, path string, stat *ExtendedFileInfo
node.Group = lookupGroup(stat.GID)
switch node.Type {
case restic.NodeTypeFile:
case data.NodeTypeFile:
node.Size = uint64(stat.Size)
node.Links = stat.Links
case restic.NodeTypeDir:
case restic.NodeTypeSymlink:
case data.NodeTypeDir:
case data.NodeTypeSymlink:
var err error
node.LinkTarget, err = os.Readlink(fixpath(path))
node.Links = stat.Links
if err != nil {
return errors.WithStack(err)
}
case restic.NodeTypeDev:
case data.NodeTypeDev:
node.Device = stat.Device
node.Links = stat.Links
case restic.NodeTypeCharDev:
case data.NodeTypeCharDev:
node.Device = stat.Device
node.Links = stat.Links
case restic.NodeTypeFifo:
case restic.NodeTypeSocket:
case data.NodeTypeFifo:
case data.NodeTypeSocket:
default:
return errors.Errorf("unsupported file type %q", node.Type)
}
@@ -158,23 +158,23 @@ func lookupGroup(gid uint32) string {
}
// NodeCreateAt creates the node at the given path but does NOT restore node meta data.
func NodeCreateAt(node *restic.Node, path string) (err error) {
func NodeCreateAt(node *data.Node, path string) (err error) {
debug.Log("create node %v at %v", node.Name, path)
switch node.Type {
case restic.NodeTypeDir:
case data.NodeTypeDir:
err = nodeCreateDirAt(node, path)
case restic.NodeTypeFile:
case data.NodeTypeFile:
err = nodeCreateFileAt(path)
case restic.NodeTypeSymlink:
case data.NodeTypeSymlink:
err = nodeCreateSymlinkAt(node, path)
case restic.NodeTypeDev:
case data.NodeTypeDev:
err = nodeCreateDevAt(node, path)
case restic.NodeTypeCharDev:
case data.NodeTypeCharDev:
err = nodeCreateCharDevAt(node, path)
case restic.NodeTypeFifo:
case data.NodeTypeFifo:
err = nodeCreateFifoAt(path)
case restic.NodeTypeSocket:
case data.NodeTypeSocket:
err = nil
default:
err = errors.Errorf("filetype %q not implemented", node.Type)
@@ -183,7 +183,7 @@ func NodeCreateAt(node *restic.Node, path string) (err error) {
return err
}
func nodeCreateDirAt(node *restic.Node, path string) error {
func nodeCreateDirAt(node *data.Node, path string) error {
err := os.Mkdir(fixpath(path), node.Mode)
if err != nil && !os.IsExist(err) {
return errors.WithStack(err)
@@ -205,7 +205,7 @@ func nodeCreateFileAt(path string) error {
return nil
}
func nodeCreateSymlinkAt(node *restic.Node, path string) error {
func nodeCreateSymlinkAt(node *data.Node, path string) error {
if err := os.Symlink(node.LinkTarget, fixpath(path)); err != nil {
return errors.WithStack(err)
}
@@ -213,11 +213,11 @@ func nodeCreateSymlinkAt(node *restic.Node, path string) error {
return nil
}
func nodeCreateDevAt(node *restic.Node, path string) error {
func nodeCreateDevAt(node *data.Node, path string) error {
return mknod(path, syscall.S_IFBLK|0600, node.Device)
}
func nodeCreateCharDevAt(node *restic.Node, path string) error {
func nodeCreateCharDevAt(node *data.Node, path string) error {
return mknod(path, syscall.S_IFCHR|0600, node.Device)
}
@@ -230,7 +230,7 @@ func mkfifo(path string, mode uint32) (err error) {
}
// NodeRestoreMetadata restores node metadata
func NodeRestoreMetadata(node *restic.Node, path string, warn func(msg string), xattrSelectFilter func(xattrName string) bool) error {
func NodeRestoreMetadata(node *data.Node, path string, warn func(msg string), xattrSelectFilter func(xattrName string) bool) error {
err := nodeRestoreMetadata(node, path, warn, xattrSelectFilter)
if err != nil {
// It is common to have permission errors for folders like /home
@@ -246,7 +246,7 @@ func NodeRestoreMetadata(node *restic.Node, path string, warn func(msg string),
return err
}
func nodeRestoreMetadata(node *restic.Node, path string, warn func(msg string), xattrSelectFilter func(xattrName string) bool) error {
func nodeRestoreMetadata(node *data.Node, path string, warn func(msg string), xattrSelectFilter func(xattrName string) bool) error {
var firsterr error
if err := lchown(path, int(node.UID), int(node.GID)); err != nil {
@@ -277,7 +277,7 @@ func nodeRestoreMetadata(node *restic.Node, path string, warn func(msg string),
// Moving RestoreTimestamps and restoreExtendedAttributes calls above as for readonly files in windows
// calling Chmod below will no longer allow any modifications to be made on the file and the
// calls above would fail.
if node.Type != restic.NodeTypeSymlink {
if node.Type != data.NodeTypeSymlink {
if err := chmod(path, node.Mode); err != nil {
if firsterr == nil {
firsterr = errors.WithStack(err)
@@ -288,7 +288,7 @@ func nodeRestoreMetadata(node *restic.Node, path string, warn func(msg string),
return firsterr
}
func nodeRestoreTimestamps(node *restic.Node, path string) error {
func nodeRestoreTimestamps(node *data.Node, path string) error {
atime := node.AccessTime.UnixNano()
mtime := node.ModTime.UnixNano()

View File

@@ -1,12 +1,12 @@
package fs
import (
"github.com/restic/restic/internal/restic"
"github.com/restic/restic/internal/data"
"golang.org/x/sys/unix"
)
// utimesNano is like syscall.UtimesNano, except that it does not follow symlinks.
func utimesNano(path string, atime, mtime int64, _ restic.NodeType) error {
func utimesNano(path string, atime, mtime int64, _ data.NodeType) error {
times := []unix.Timespec{
unix.NsecToTimespec(atime),
unix.NsecToTimespec(mtime),

View File

@@ -5,14 +5,14 @@ import (
"strings"
"testing"
"github.com/restic/restic/internal/data"
"github.com/restic/restic/internal/errors"
"github.com/restic/restic/internal/restic"
rtest "github.com/restic/restic/internal/test"
)
func TestRestoreSymlinkTimestampsError(t *testing.T) {
d := t.TempDir()
node := restic.Node{Type: restic.NodeTypeSymlink}
node := data.Node{Type: data.NodeTypeSymlink}
err := nodeRestoreTimestamps(&node, d+"/nosuchfile")
rtest.Assert(t, errors.Is(err, fs.ErrNotExist), "want ErrNotExist, got %q", err)
rtest.Assert(t, strings.Contains(err.Error(), d), "filename not in %q", err)

View File

@@ -3,16 +3,14 @@
package fs
import (
"github.com/restic/restic/internal/restic"
)
import "github.com/restic/restic/internal/data"
// nodeRestoreExtendedAttributes is a no-op
func nodeRestoreExtendedAttributes(_ *restic.Node, _ string, _ func(xattrName string) bool) error {
func nodeRestoreExtendedAttributes(_ *data.Node, _ string, _ func(xattrName string) bool) error {
return nil
}
// nodeFillExtendedAttributes is a no-op
func nodeFillExtendedAttributes(_ *restic.Node, _ string, _ bool, _ func(format string, args ...any)) error {
func nodeFillExtendedAttributes(_ *data.Node, _ string, _ bool, _ func(format string, args ...any)) error {
return nil
}

View File

@@ -11,6 +11,7 @@ import (
"time"
"github.com/google/go-cmp/cmp"
"github.com/restic/restic/internal/data"
"github.com/restic/restic/internal/errors"
"github.com/restic/restic/internal/restic"
rtest "github.com/restic/restic/internal/test"
@@ -47,10 +48,10 @@ func parseTime(s string) time.Time {
return t.Local()
}
var nodeTests = []restic.Node{
var nodeTests = []data.Node{
{
Name: "testFile",
Type: restic.NodeTypeFile,
Type: data.NodeTypeFile,
Content: restic.IDs{},
UID: uint32(os.Getuid()),
GID: uint32(os.Getgid()),
@@ -61,7 +62,7 @@ var nodeTests = []restic.Node{
},
{
Name: "testSuidFile",
Type: restic.NodeTypeFile,
Type: data.NodeTypeFile,
Content: restic.IDs{},
UID: uint32(os.Getuid()),
GID: uint32(os.Getgid()),
@@ -72,7 +73,7 @@ var nodeTests = []restic.Node{
},
{
Name: "testSuidFile2",
Type: restic.NodeTypeFile,
Type: data.NodeTypeFile,
Content: restic.IDs{},
UID: uint32(os.Getuid()),
GID: uint32(os.Getgid()),
@@ -83,7 +84,7 @@ var nodeTests = []restic.Node{
},
{
Name: "testSticky",
Type: restic.NodeTypeFile,
Type: data.NodeTypeFile,
Content: restic.IDs{},
UID: uint32(os.Getuid()),
GID: uint32(os.Getgid()),
@@ -94,7 +95,7 @@ var nodeTests = []restic.Node{
},
{
Name: "testDir",
Type: restic.NodeTypeDir,
Type: data.NodeTypeDir,
Subtree: nil,
UID: uint32(os.Getuid()),
GID: uint32(os.Getgid()),
@@ -105,7 +106,7 @@ var nodeTests = []restic.Node{
},
{
Name: "testSymlink",
Type: restic.NodeTypeSymlink,
Type: data.NodeTypeSymlink,
LinkTarget: "invalid",
UID: uint32(os.Getuid()),
GID: uint32(os.Getgid()),
@@ -119,7 +120,7 @@ var nodeTests = []restic.Node{
// metadata, so we can test if CreateAt works with pre-existing files.
{
Name: "testFile",
Type: restic.NodeTypeFile,
Type: data.NodeTypeFile,
Content: restic.IDs{},
UID: uint32(os.Getuid()),
GID: uint32(os.Getgid()),
@@ -130,7 +131,7 @@ var nodeTests = []restic.Node{
},
{
Name: "testDir",
Type: restic.NodeTypeDir,
Type: data.NodeTypeDir,
Subtree: nil,
UID: uint32(os.Getuid()),
GID: uint32(os.Getgid()),
@@ -141,7 +142,7 @@ var nodeTests = []restic.Node{
},
{
Name: "testXattrFile",
Type: restic.NodeTypeFile,
Type: data.NodeTypeFile,
Content: restic.IDs{},
UID: uint32(os.Getuid()),
GID: uint32(os.Getgid()),
@@ -149,13 +150,13 @@ var nodeTests = []restic.Node{
ModTime: parseTime("2005-05-14 21:07:03.111"),
AccessTime: parseTime("2005-05-14 21:07:04.222"),
ChangeTime: parseTime("2005-05-14 21:07:05.333"),
ExtendedAttributes: []restic.ExtendedAttribute{
ExtendedAttributes: []data.ExtendedAttribute{
{Name: "user.foo", Value: []byte("bar")},
},
},
{
Name: "testXattrDir",
Type: restic.NodeTypeDir,
Type: data.NodeTypeDir,
Subtree: nil,
UID: uint32(os.Getuid()),
GID: uint32(os.Getgid()),
@@ -163,13 +164,13 @@ var nodeTests = []restic.Node{
ModTime: parseTime("2005-05-14 21:07:03.111"),
AccessTime: parseTime("2005-05-14 21:07:04.222"),
ChangeTime: parseTime("2005-05-14 21:07:05.333"),
ExtendedAttributes: []restic.ExtendedAttribute{
ExtendedAttributes: []data.ExtendedAttribute{
{Name: "user.foo", Value: []byte("bar")},
},
},
{
Name: "testXattrFileMacOSResourceFork",
Type: restic.NodeTypeFile,
Type: data.NodeTypeFile,
Content: restic.IDs{},
UID: uint32(os.Getuid()),
GID: uint32(os.Getgid()),
@@ -177,7 +178,7 @@ var nodeTests = []restic.Node{
ModTime: parseTime("2005-05-14 21:07:03.111"),
AccessTime: parseTime("2005-05-14 21:07:04.222"),
ChangeTime: parseTime("2005-05-14 21:07:05.333"),
ExtendedAttributes: []restic.ExtendedAttribute{
ExtendedAttributes: []data.ExtendedAttribute{
{Name: "com.apple.ResourceFork", Value: []byte("bar")},
},
},
@@ -242,7 +243,7 @@ func TestNodeRestoreAt(t *testing.T) {
"%v: UID doesn't match (%v != %v)", test.Type, test.UID, n2.UID)
rtest.Assert(t, test.GID == n2.GID,
"%v: GID doesn't match (%v != %v)", test.Type, test.GID, n2.GID)
if test.Type != restic.NodeTypeSymlink {
if test.Type != data.NodeTypeSymlink {
// On OpenBSD only root can set sticky bit (see sticky(8)).
if runtime.GOOS != "openbsd" && runtime.GOOS != "netbsd" && runtime.GOOS != "solaris" && test.Name == "testSticky" {
rtest.Assert(t, test.Mode == n2.Mode,
@@ -262,11 +263,11 @@ func TestNodeRestoreAt(t *testing.T) {
}
}
func AssertFsTimeEqual(t *testing.T, label string, nodeType restic.NodeType, t1 time.Time, t2 time.Time) {
func AssertFsTimeEqual(t *testing.T, label string, nodeType data.NodeType, t1 time.Time, t2 time.Time) {
var equal bool
// Go currently doesn't support setting timestamps of symbolic links on darwin and bsd
if nodeType == restic.NodeTypeSymlink {
if nodeType == data.NodeTypeSymlink {
switch runtime.GOOS {
case "darwin", "freebsd", "openbsd", "netbsd", "solaris":
return

View File

@@ -6,7 +6,7 @@ package fs
import (
"os"
"github.com/restic/restic/internal/restic"
"github.com/restic/restic/internal/data"
)
func lchown(name string, uid, gid int) error {
@@ -14,11 +14,11 @@ func lchown(name string, uid, gid int) error {
}
// nodeRestoreGenericAttributes is no-op.
func nodeRestoreGenericAttributes(node *restic.Node, _ string, warn func(msg string)) error {
return restic.HandleAllUnknownGenericAttributesFound(node.GenericAttributes, warn)
func nodeRestoreGenericAttributes(node *data.Node, _ string, warn func(msg string)) error {
return data.HandleAllUnknownGenericAttributesFound(node.GenericAttributes, warn)
}
// nodeFillGenericAttributes is a no-op.
func nodeFillGenericAttributes(_ *restic.Node, _ string, _ *ExtendedFileInfo) error {
func nodeFillGenericAttributes(_ *data.Node, _ string, _ *ExtendedFileInfo) error {
return nil
}

View File

@@ -5,12 +5,12 @@ package fs
import (
"syscall"
"github.com/restic/restic/internal/restic"
"github.com/restic/restic/internal/data"
)
// utimesNano is like syscall.UtimesNano, except that it skips symlinks.
func utimesNano(path string, atime, mtime int64, typ restic.NodeType) error {
if typ == restic.NodeTypeSymlink {
func utimesNano(path string, atime, mtime int64, typ data.NodeType) error {
if typ == data.NodeTypeSymlink {
return nil
}

View File

@@ -12,8 +12,8 @@ import (
"syscall"
"testing"
"github.com/restic/restic/internal/data"
"github.com/restic/restic/internal/errors"
"github.com/restic/restic/internal/restic"
rtest "github.com/restic/restic/internal/test"
)
@@ -30,7 +30,7 @@ func stat(t testing.TB, filename string) (fi os.FileInfo, ok bool) {
return fi, true
}
func checkFile(t testing.TB, fi fs.FileInfo, node *restic.Node) {
func checkFile(t testing.TB, fi fs.FileInfo, node *data.Node) {
t.Helper()
stat := fi.Sys().(*syscall.Stat_t)
@@ -47,7 +47,7 @@ func checkFile(t testing.TB, fi fs.FileInfo, node *restic.Node) {
t.Errorf("Dev does not match, want %v, got %v", stat.Dev, node.DeviceID)
}
if node.Size != uint64(stat.Size) && node.Type != restic.NodeTypeSymlink {
if node.Size != uint64(stat.Size) && node.Type != data.NodeTypeSymlink {
t.Errorf("Size does not match, want %v, got %v", stat.Size, node.Size)
}
@@ -76,7 +76,7 @@ func checkFile(t testing.TB, fi fs.FileInfo, node *restic.Node) {
}
}
func checkDevice(t testing.TB, fi fs.FileInfo, node *restic.Node) {
func checkDevice(t testing.TB, fi fs.FileInfo, node *data.Node) {
stat := fi.Sys().(*syscall.Stat_t)
if node.Device != uint64(stat.Rdev) {
t.Errorf("Rdev does not match, want %v, got %v", stat.Rdev, node.Device)
@@ -124,9 +124,9 @@ func TestNodeFromFileInfo(t *testing.T) {
rtest.OK(t, err)
switch node.Type {
case restic.NodeTypeFile, restic.NodeTypeSymlink:
case data.NodeTypeFile, data.NodeTypeSymlink:
checkFile(t, fi, node)
case restic.NodeTypeDev, restic.NodeTypeCharDev:
case data.NodeTypeDev, data.NodeTypeCharDev:
checkFile(t, fi, node)
checkDevice(t, fi, node)
default:

View File

@@ -10,9 +10,9 @@ import (
"syscall"
"unsafe"
"github.com/restic/restic/internal/data"
"github.com/restic/restic/internal/debug"
"github.com/restic/restic/internal/errors"
"github.com/restic/restic/internal/restic"
"golang.org/x/sys/windows"
)
@@ -43,7 +43,7 @@ func lchown(_ string, _ int, _ int) (err error) {
}
// utimesNano is like syscall.UtimesNano, except that it sets FILE_FLAG_OPEN_REPARSE_POINT.
func utimesNano(path string, atime, mtime int64, _ restic.NodeType) error {
func utimesNano(path string, atime, mtime int64, _ data.NodeType) error {
// tweaked version of UtimesNano from go/src/syscall/syscall_windows.go
pathp, e := syscall.UTF16PtrFromString(fixpath(path))
if e != nil {
@@ -69,7 +69,7 @@ func utimesNano(path string, atime, mtime int64, _ restic.NodeType) error {
}
// restore extended attributes for windows
func nodeRestoreExtendedAttributes(node *restic.Node, path string, xattrSelectFilter func(xattrName string) bool) error {
func nodeRestoreExtendedAttributes(node *data.Node, path string, xattrSelectFilter func(xattrName string) bool) error {
count := len(node.ExtendedAttributes)
if count > 0 {
eas := []extendedAttribute{}
@@ -91,14 +91,14 @@ func nodeRestoreExtendedAttributes(node *restic.Node, path string, xattrSelectFi
// fill extended attributes in the node
// It also checks if the volume supports extended attributes and stores the result in a map
// so that it does not have to be checked again for subsequent calls for paths in the same volume.
func nodeFillExtendedAttributes(node *restic.Node, path string, _ bool, _ func(format string, args ...any)) (err error) {
func nodeFillExtendedAttributes(node *data.Node, path string, _ bool, _ func(format string, args ...any)) (err error) {
if strings.Contains(filepath.Base(path), ":") {
// Do not process for Alternate Data Streams in Windows
return nil
}
// only capture xattrs for file/dir
if node.Type != restic.NodeTypeFile && node.Type != restic.NodeTypeDir {
if node.Type != data.NodeTypeFile && node.Type != data.NodeTypeDir {
return nil
}
@@ -131,7 +131,7 @@ func nodeFillExtendedAttributes(node *restic.Node, path string, _ bool, _ func(f
//Fill the ExtendedAttributes in the node using the name/value pairs in the windows EA
for _, attr := range extAtts {
extendedAttr := restic.ExtendedAttribute{
extendedAttr := data.ExtendedAttribute{
Name: attr.Name,
Value: attr.Value,
}
@@ -151,7 +151,7 @@ func closeFileHandle(fileHandle windows.Handle, path string) {
// restoreExtendedAttributes handles restore of the Windows Extended Attributes to the specified path.
// The Windows API requires setting of all the Extended Attributes in one call.
func restoreExtendedAttributes(nodeType restic.NodeType, path string, eas []extendedAttribute) (err error) {
func restoreExtendedAttributes(nodeType data.NodeType, path string, eas []extendedAttribute) (err error) {
var fileHandle windows.Handle
if fileHandle, err = openHandleForEA(nodeType, path, true); fileHandle == 0 {
return nil
@@ -188,7 +188,7 @@ func restoreExtendedAttributes(nodeType restic.NodeType, path string, eas []exte
}
// restoreGenericAttributes restores generic attributes for Windows
func nodeRestoreGenericAttributes(node *restic.Node, path string, warn func(msg string)) (err error) {
func nodeRestoreGenericAttributes(node *data.Node, path string, warn func(msg string)) (err error) {
if len(node.GenericAttributes) == 0 {
return nil
}
@@ -213,14 +213,14 @@ func nodeRestoreGenericAttributes(node *restic.Node, path string, warn func(msg
}
}
restic.HandleUnknownGenericAttributesFound(unknownAttribs, warn)
data.HandleUnknownGenericAttributesFound(unknownAttribs, warn)
return errors.Join(errs...)
}
// genericAttributesToWindowsAttrs converts the generic attributes map to a WindowsAttributes and also returns a string of unknown attributes that it could not convert.
func genericAttributesToWindowsAttrs(attrs map[restic.GenericAttributeType]json.RawMessage) (windowsAttributes restic.WindowsAttributes, unknownAttribs []restic.GenericAttributeType, err error) {
func genericAttributesToWindowsAttrs(attrs map[data.GenericAttributeType]json.RawMessage) (windowsAttributes data.WindowsAttributes, unknownAttribs []data.GenericAttributeType, err error) {
waValue := reflect.ValueOf(&windowsAttributes).Elem()
unknownAttribs, err = restic.GenericAttributesToOSAttrs(attrs, reflect.TypeOf(windowsAttributes), &waValue, "windows")
unknownAttribs, err = data.GenericAttributesToOSAttrs(attrs, reflect.TypeOf(windowsAttributes), &waValue, "windows")
return windowsAttributes, unknownAttribs, err
}
@@ -341,7 +341,7 @@ func decryptFile(pathPointer *uint16) error {
// nodeFillGenericAttributes fills in the generic attributes for windows like File Attributes,
// Created time and Security Descriptors.
func nodeFillGenericAttributes(node *restic.Node, path string, stat *ExtendedFileInfo) error {
func nodeFillGenericAttributes(node *data.Node, path string, stat *ExtendedFileInfo) error {
if strings.Contains(filepath.Base(path), ":") {
// Do not process for Alternate Data Streams in Windows
return nil
@@ -360,7 +360,7 @@ func nodeFillGenericAttributes(node *restic.Node, path string, stat *ExtendedFil
}
var sd *[]byte
if node.Type == restic.NodeTypeFile || node.Type == restic.NodeTypeDir {
if node.Type == data.NodeTypeFile || node.Type == data.NodeTypeDir {
if sd, err = getSecurityDescriptor(path); err != nil {
return err
}
@@ -369,7 +369,7 @@ func nodeFillGenericAttributes(node *restic.Node, path string, stat *ExtendedFil
winFI := stat.sys.(*syscall.Win32FileAttributeData)
// Add Windows attributes
node.GenericAttributes, err = restic.WindowsAttrsToGenericAttributes(restic.WindowsAttributes{
node.GenericAttributes, err = data.WindowsAttrsToGenericAttributes(data.WindowsAttributes{
CreationTime: &winFI.CreationTime,
FileAttributes: &winFI.FileAttributes,
SecurityDescriptor: sd,

View File

@@ -14,8 +14,8 @@ import (
"testing"
"time"
"github.com/restic/restic/internal/data"
"github.com/restic/restic/internal/errors"
"github.com/restic/restic/internal/restic"
"github.com/restic/restic/internal/test"
"golang.org/x/sys/windows"
)
@@ -24,19 +24,19 @@ func TestRestoreSecurityDescriptors(t *testing.T) {
t.Parallel()
tempDir := t.TempDir()
for i, sd := range testFileSDs {
testRestoreSecurityDescriptor(t, sd, tempDir, restic.NodeTypeFile, fmt.Sprintf("testfile%d", i))
testRestoreSecurityDescriptor(t, sd, tempDir, data.NodeTypeFile, fmt.Sprintf("testfile%d", i))
}
for i, sd := range testDirSDs {
testRestoreSecurityDescriptor(t, sd, tempDir, restic.NodeTypeDir, fmt.Sprintf("testdir%d", i))
testRestoreSecurityDescriptor(t, sd, tempDir, data.NodeTypeDir, fmt.Sprintf("testdir%d", i))
}
}
func testRestoreSecurityDescriptor(t *testing.T, sd string, tempDir string, fileType restic.NodeType, fileName string) {
func testRestoreSecurityDescriptor(t *testing.T, sd string, tempDir string, fileType data.NodeType, fileName string) {
// Decode the encoded string SD to get the security descriptor input in bytes.
sdInputBytes, err := base64.StdEncoding.DecodeString(sd)
test.OK(t, errors.Wrapf(err, "Error decoding SD for: %s", fileName))
// Wrap the security descriptor bytes in windows attributes and convert to generic attributes.
genericAttributes, err := restic.WindowsAttrsToGenericAttributes(restic.WindowsAttributes{CreationTime: nil, FileAttributes: nil, SecurityDescriptor: &sdInputBytes})
genericAttributes, err := data.WindowsAttrsToGenericAttributes(data.WindowsAttributes{CreationTime: nil, FileAttributes: nil, SecurityDescriptor: &sdInputBytes})
test.OK(t, errors.Wrapf(err, "Error constructing windows attributes for: %s", fileName))
// Construct a Node with the generic attributes.
expectedNode := getNode(fileName, fileType, genericAttributes)
@@ -56,8 +56,8 @@ func testRestoreSecurityDescriptor(t *testing.T, sd string, tempDir string, file
compareSecurityDescriptors(t, testPath, *sdByteFromRestoredNode, *sdBytesFromRestoredPath)
}
func getNode(name string, fileType restic.NodeType, genericAttributes map[restic.GenericAttributeType]json.RawMessage) restic.Node {
return restic.Node{
func getNode(name string, fileType data.NodeType, genericAttributes map[data.GenericAttributeType]json.RawMessage) data.Node {
return data.Node{
Name: name,
Type: fileType,
Mode: 0644,
@@ -68,7 +68,7 @@ func getNode(name string, fileType restic.NodeType, genericAttributes map[restic
}
}
func getWindowsAttr(t *testing.T, testPath string, node *restic.Node) restic.WindowsAttributes {
func getWindowsAttr(t *testing.T, testPath string, node *data.Node) data.WindowsAttributes {
windowsAttributes, unknownAttribs, err := genericAttributesToWindowsAttrs(node.GenericAttributes)
test.OK(t, errors.Wrapf(err, "Error getting windows attr from generic attr: %s", testPath))
test.Assert(t, len(unknownAttribs) == 0, "Unknown attribs found: %s for: %s", unknownAttribs, testPath)
@@ -83,19 +83,19 @@ func TestRestoreCreationTime(t *testing.T) {
attr := fi.Sys().(*syscall.Win32FileAttributeData)
creationTimeAttribute := attr.CreationTime
//Using the temp dir creation time as the test creation time for the test file and folder
runGenericAttributesTest(t, path, restic.TypeCreationTime, restic.WindowsAttributes{CreationTime: &creationTimeAttribute}, false)
runGenericAttributesTest(t, path, data.TypeCreationTime, data.WindowsAttributes{CreationTime: &creationTimeAttribute}, false)
}
func TestRestoreFileAttributes(t *testing.T) {
t.Parallel()
genericAttributeName := restic.TypeFileAttributes
genericAttributeName := data.TypeFileAttributes
tempDir := t.TempDir()
normal := uint32(syscall.FILE_ATTRIBUTE_NORMAL)
hidden := uint32(syscall.FILE_ATTRIBUTE_HIDDEN)
system := uint32(syscall.FILE_ATTRIBUTE_SYSTEM)
archive := uint32(syscall.FILE_ATTRIBUTE_ARCHIVE)
encrypted := uint32(windows.FILE_ATTRIBUTE_ENCRYPTED)
fileAttributes := []restic.WindowsAttributes{
fileAttributes := []data.WindowsAttributes{
//normal
{FileAttributes: &normal},
//hidden
@@ -108,12 +108,12 @@ func TestRestoreFileAttributes(t *testing.T) {
{FileAttributes: &encrypted},
}
for i, fileAttr := range fileAttributes {
genericAttrs, err := restic.WindowsAttrsToGenericAttributes(fileAttr)
genericAttrs, err := data.WindowsAttrsToGenericAttributes(fileAttr)
test.OK(t, err)
expectedNodes := []restic.Node{
expectedNodes := []data.Node{
{
Name: fmt.Sprintf("testfile%d", i),
Type: restic.NodeTypeFile,
Type: data.NodeTypeFile,
Mode: 0655,
ModTime: parseTime("2005-05-14 21:07:03.111"),
AccessTime: parseTime("2005-05-14 21:07:04.222"),
@@ -128,7 +128,7 @@ func TestRestoreFileAttributes(t *testing.T) {
system = uint32(syscall.FILE_ATTRIBUTE_DIRECTORY | windows.FILE_ATTRIBUTE_SYSTEM)
archive = uint32(syscall.FILE_ATTRIBUTE_DIRECTORY | windows.FILE_ATTRIBUTE_ARCHIVE)
encrypted = uint32(syscall.FILE_ATTRIBUTE_DIRECTORY | windows.FILE_ATTRIBUTE_ENCRYPTED)
folderAttributes := []restic.WindowsAttributes{
folderAttributes := []data.WindowsAttributes{
//normal
{FileAttributes: &normal},
//hidden
@@ -141,12 +141,12 @@ func TestRestoreFileAttributes(t *testing.T) {
{FileAttributes: &encrypted},
}
for i, folderAttr := range folderAttributes {
genericAttrs, err := restic.WindowsAttrsToGenericAttributes(folderAttr)
genericAttrs, err := data.WindowsAttrsToGenericAttributes(folderAttr)
test.OK(t, err)
expectedNodes := []restic.Node{
expectedNodes := []data.Node{
{
Name: fmt.Sprintf("testdirectory%d", i),
Type: restic.NodeTypeDir,
Type: data.NodeTypeDir,
Mode: 0755,
ModTime: parseTime("2005-05-14 21:07:03.111"),
AccessTime: parseTime("2005-05-14 21:07:04.222"),
@@ -158,13 +158,13 @@ func TestRestoreFileAttributes(t *testing.T) {
}
}
func runGenericAttributesTest(t *testing.T, tempDir string, genericAttributeName restic.GenericAttributeType, genericAttributeExpected restic.WindowsAttributes, warningExpected bool) {
genericAttributes, err := restic.WindowsAttrsToGenericAttributes(genericAttributeExpected)
func runGenericAttributesTest(t *testing.T, tempDir string, genericAttributeName data.GenericAttributeType, genericAttributeExpected data.WindowsAttributes, warningExpected bool) {
genericAttributes, err := data.WindowsAttrsToGenericAttributes(genericAttributeExpected)
test.OK(t, err)
expectedNodes := []restic.Node{
expectedNodes := []data.Node{
{
Name: "testfile",
Type: restic.NodeTypeFile,
Type: data.NodeTypeFile,
Mode: 0644,
ModTime: parseTime("2005-05-14 21:07:03.111"),
AccessTime: parseTime("2005-05-14 21:07:04.222"),
@@ -173,7 +173,7 @@ func runGenericAttributesTest(t *testing.T, tempDir string, genericAttributeName
},
{
Name: "testdirectory",
Type: restic.NodeTypeDir,
Type: data.NodeTypeDir,
Mode: 0755,
ModTime: parseTime("2005-05-14 21:07:03.111"),
AccessTime: parseTime("2005-05-14 21:07:04.222"),
@@ -183,29 +183,29 @@ func runGenericAttributesTest(t *testing.T, tempDir string, genericAttributeName
}
runGenericAttributesTestForNodes(t, expectedNodes, tempDir, genericAttributeName, genericAttributeExpected, warningExpected)
}
func runGenericAttributesTestForNodes(t *testing.T, expectedNodes []restic.Node, tempDir string, genericAttr restic.GenericAttributeType, genericAttributeExpected restic.WindowsAttributes, warningExpected bool) {
func runGenericAttributesTestForNodes(t *testing.T, expectedNodes []data.Node, tempDir string, genericAttr data.GenericAttributeType, genericAttributeExpected data.WindowsAttributes, warningExpected bool) {
for _, testNode := range expectedNodes {
testPath, node := restoreAndGetNode(t, tempDir, &testNode, warningExpected)
rawMessage := node.GenericAttributes[genericAttr]
genericAttrsExpected, err := restic.WindowsAttrsToGenericAttributes(genericAttributeExpected)
genericAttrsExpected, err := data.WindowsAttrsToGenericAttributes(genericAttributeExpected)
test.OK(t, err)
rawMessageExpected := genericAttrsExpected[genericAttr]
test.Equals(t, rawMessageExpected, rawMessage, "Generic attribute: %s got from NodeFromFileInfo not equal for path: %s", string(genericAttr), testPath)
}
}
func restoreAndGetNode(t *testing.T, tempDir string, testNode *restic.Node, warningExpected bool) (string, *restic.Node) {
func restoreAndGetNode(t *testing.T, tempDir string, testNode *data.Node, warningExpected bool) (string, *data.Node) {
testPath := filepath.Join(tempDir, "001", testNode.Name)
err := os.MkdirAll(filepath.Dir(testPath), testNode.Mode)
test.OK(t, errors.Wrapf(err, "Failed to create parent directories for: %s", testPath))
if testNode.Type == restic.NodeTypeFile {
if testNode.Type == data.NodeTypeFile {
testFile, err := os.Create(testPath)
test.OK(t, errors.Wrapf(err, "Failed to create test file: %s", testPath))
testFile.Close()
} else if testNode.Type == restic.NodeTypeDir {
} else if testNode.Type == data.NodeTypeDir {
err := os.Mkdir(testPath, testNode.Mode)
test.OK(t, errors.Wrapf(err, "Failed to create test directory: %s", testPath))
@@ -231,19 +231,19 @@ func restoreAndGetNode(t *testing.T, tempDir string, testNode *restic.Node, warn
return testPath, nodeFromFileInfo
}
const TypeSomeNewAttribute restic.GenericAttributeType = "MockAttributes.SomeNewAttribute"
const TypeSomeNewAttribute data.GenericAttributeType = "MockAttributes.SomeNewAttribute"
func TestNewGenericAttributeType(t *testing.T) {
t.Parallel()
newGenericAttribute := map[restic.GenericAttributeType]json.RawMessage{}
newGenericAttribute := map[data.GenericAttributeType]json.RawMessage{}
newGenericAttribute[TypeSomeNewAttribute] = []byte("any value")
tempDir := t.TempDir()
expectedNodes := []restic.Node{
expectedNodes := []data.Node{
{
Name: "testfile",
Type: restic.NodeTypeFile,
Type: data.NodeTypeFile,
Mode: 0644,
ModTime: parseTime("2005-05-14 21:07:03.111"),
AccessTime: parseTime("2005-05-14 21:07:04.222"),
@@ -252,7 +252,7 @@ func TestNewGenericAttributeType(t *testing.T) {
},
{
Name: "testdirectory",
Type: restic.NodeTypeDir,
Type: data.NodeTypeDir,
Mode: 0755,
ModTime: parseTime("2005-05-14 21:07:03.111"),
AccessTime: parseTime("2005-05-14 21:07:04.222"),
@@ -272,26 +272,26 @@ func TestNewGenericAttributeType(t *testing.T) {
func TestRestoreExtendedAttributes(t *testing.T) {
t.Parallel()
tempDir := t.TempDir()
expectedNodes := []restic.Node{
expectedNodes := []data.Node{
{
Name: "testfile",
Type: restic.NodeTypeFile,
Type: data.NodeTypeFile,
Mode: 0644,
ModTime: parseTime("2005-05-14 21:07:03.111"),
AccessTime: parseTime("2005-05-14 21:07:04.222"),
ChangeTime: parseTime("2005-05-14 21:07:05.333"),
ExtendedAttributes: []restic.ExtendedAttribute{
ExtendedAttributes: []data.ExtendedAttribute{
{"user.foo", []byte("bar")},
},
},
{
Name: "testdirectory",
Type: restic.NodeTypeDir,
Type: data.NodeTypeDir,
Mode: 0755,
ModTime: parseTime("2005-05-14 21:07:03.111"),
AccessTime: parseTime("2005-05-14 21:07:04.222"),
ChangeTime: parseTime("2005-05-14 21:07:05.333"),
ExtendedAttributes: []restic.ExtendedAttribute{
ExtendedAttributes: []data.ExtendedAttribute{
{"user.foo", []byte("bar")},
},
},
@@ -302,9 +302,9 @@ func TestRestoreExtendedAttributes(t *testing.T) {
var handle windows.Handle
var err error
utf16Path := windows.StringToUTF16Ptr(testPath)
if node.Type == restic.NodeTypeFile {
if node.Type == data.NodeTypeFile {
handle, err = windows.CreateFile(utf16Path, windows.FILE_READ_EA, 0, nil, windows.OPEN_EXISTING, windows.FILE_ATTRIBUTE_NORMAL, 0)
} else if node.Type == restic.NodeTypeDir {
} else if node.Type == data.NodeTypeDir {
handle, err = windows.CreateFile(utf16Path, windows.FILE_READ_EA, 0, nil, windows.OPEN_EXISTING, windows.FILE_ATTRIBUTE_NORMAL|windows.FILE_FLAG_BACKUP_SEMANTICS, 0)
}
test.OK(t, errors.Wrapf(err, "Error opening file/directory for: %s", testPath))

View File

@@ -7,9 +7,9 @@ import (
"os"
"syscall"
"github.com/restic/restic/internal/data"
"github.com/restic/restic/internal/debug"
"github.com/restic/restic/internal/errors"
"github.com/restic/restic/internal/restic"
"github.com/pkg/xattr"
)
@@ -63,7 +63,7 @@ func handleXattrErr(err error) error {
}
}
func nodeRestoreExtendedAttributes(node *restic.Node, path string, xattrSelectFilter func(xattrName string) bool) error {
func nodeRestoreExtendedAttributes(node *data.Node, path string, xattrSelectFilter func(xattrName string) bool) error {
expectedAttrs := map[string]struct{}{}
for _, attr := range node.ExtendedAttributes {
// Only restore xattrs that match the filter
@@ -96,7 +96,7 @@ func nodeRestoreExtendedAttributes(node *restic.Node, path string, xattrSelectFi
return nil
}
func nodeFillExtendedAttributes(node *restic.Node, path string, ignoreListError bool, warnf func(format string, args ...any)) error {
func nodeFillExtendedAttributes(node *data.Node, path string, ignoreListError bool, warnf func(format string, args ...any)) error {
xattrs, err := listxattr(path)
debug.Log("fillExtendedAttributes(%v) %v %v", path, xattrs, err)
if err != nil {
@@ -106,14 +106,14 @@ func nodeFillExtendedAttributes(node *restic.Node, path string, ignoreListError
return err
}
node.ExtendedAttributes = make([]restic.ExtendedAttribute, 0, len(xattrs))
node.ExtendedAttributes = make([]data.ExtendedAttribute, 0, len(xattrs))
for _, attr := range xattrs {
attrVal, err := getxattr(path, attr)
if err != nil {
warnf("can not obtain extended attribute %v for %v:\n", attr, path)
continue
}
attr := restic.ExtendedAttribute{
attr := data.ExtendedAttribute{
Name: attr,
Value: attrVal,
}

View File

@@ -11,12 +11,12 @@ import (
"strings"
"testing"
"github.com/restic/restic/internal/data"
"github.com/restic/restic/internal/filter"
"github.com/restic/restic/internal/restic"
rtest "github.com/restic/restic/internal/test"
)
func setAndVerifyXattr(t *testing.T, file string, attrs []restic.ExtendedAttribute) {
func setAndVerifyXattr(t *testing.T, file string, attrs []data.ExtendedAttribute) {
if runtime.GOOS == "windows" {
// windows seems to convert the xattr name to upper case
for i := range attrs {
@@ -24,15 +24,15 @@ func setAndVerifyXattr(t *testing.T, file string, attrs []restic.ExtendedAttribu
}
}
node := &restic.Node{
Type: restic.NodeTypeFile,
node := &data.Node{
Type: data.NodeTypeFile,
ExtendedAttributes: attrs,
}
/* restore all xattrs */
rtest.OK(t, nodeRestoreExtendedAttributes(node, file, func(_ string) bool { return true }))
nodeActual := &restic.Node{
Type: restic.NodeTypeFile,
nodeActual := &data.Node{
Type: data.NodeTypeFile,
}
rtest.OK(t, nodeFillExtendedAttributes(nodeActual, file, false, t.Logf))
@@ -40,7 +40,7 @@ func setAndVerifyXattr(t *testing.T, file string, attrs []restic.ExtendedAttribu
}
func setAndVerifyXattrWithSelectFilter(t *testing.T, file string, testAttr []testXattrToRestore, xattrSelectFilter func(_ string) bool) {
attrs := make([]restic.ExtendedAttribute, len(testAttr))
attrs := make([]data.ExtendedAttribute, len(testAttr))
for i := range testAttr {
// windows seems to convert the xattr name to upper case
if runtime.GOOS == "windows" {
@@ -49,15 +49,15 @@ func setAndVerifyXattrWithSelectFilter(t *testing.T, file string, testAttr []tes
attrs[i] = testAttr[i].xattr
}
node := &restic.Node{
Type: restic.NodeTypeFile,
node := &data.Node{
Type: data.NodeTypeFile,
ExtendedAttributes: attrs,
}
rtest.OK(t, nodeRestoreExtendedAttributes(node, file, xattrSelectFilter))
nodeActual := &restic.Node{
Type: restic.NodeTypeFile,
nodeActual := &data.Node{
Type: data.NodeTypeFile,
}
rtest.OK(t, nodeFillExtendedAttributes(nodeActual, file, false, t.Logf))
@@ -82,7 +82,7 @@ func setAndVerifyXattrWithSelectFilter(t *testing.T, file string, testAttr []tes
}
type testXattrToRestore struct {
xattr restic.ExtendedAttribute
xattr data.ExtendedAttribute
shouldRestore bool
}
@@ -91,14 +91,14 @@ func TestOverwriteXattr(t *testing.T) {
file := filepath.Join(dir, "file")
rtest.OK(t, os.WriteFile(file, []byte("hello world"), 0o600))
setAndVerifyXattr(t, file, []restic.ExtendedAttribute{
setAndVerifyXattr(t, file, []data.ExtendedAttribute{
{
Name: "user.foo",
Value: []byte("bar"),
},
})
setAndVerifyXattr(t, file, []restic.ExtendedAttribute{
setAndVerifyXattr(t, file, []data.ExtendedAttribute{
{
Name: "user.other",
Value: []byte("some"),
@@ -133,21 +133,21 @@ func TestOverwriteXattrWithSelectFilter(t *testing.T) {
setAndVerifyXattrWithSelectFilter(t, file, []testXattrToRestore{
{
xattr: restic.ExtendedAttribute{
xattr: data.ExtendedAttribute{
Name: "user.foo",
Value: []byte("bar"),
},
shouldRestore: true,
},
{
xattr: restic.ExtendedAttribute{
xattr: data.ExtendedAttribute{
Name: "user.test",
Value: []byte("testxattr"),
},
shouldRestore: true,
},
{
xattr: restic.ExtendedAttribute{
xattr: data.ExtendedAttribute{
Name: "security.other",
Value: []byte("testing"),
},
@@ -163,35 +163,35 @@ func TestOverwriteXattrWithSelectFilter(t *testing.T) {
setAndVerifyXattrWithSelectFilter(t, file, []testXattrToRestore{
{
xattr: restic.ExtendedAttribute{
xattr: data.ExtendedAttribute{
Name: "user.other",
Value: []byte("some"),
},
shouldRestore: true,
},
{
xattr: restic.ExtendedAttribute{
xattr: data.ExtendedAttribute{
Name: "security.other",
Value: []byte("testing"),
},
shouldRestore: false,
},
{
xattr: restic.ExtendedAttribute{
xattr: data.ExtendedAttribute{
Name: "user.open",
Value: []byte("door"),
},
shouldRestore: true,
},
{
xattr: restic.ExtendedAttribute{
xattr: data.ExtendedAttribute{
Name: "user.common",
Value: []byte("testing"),
},
shouldRestore: true,
},
{
xattr: restic.ExtendedAttribute{
xattr: data.ExtendedAttribute{
Name: "user.bad",
Value: []byte("dontincludeme"),
},