mirror of
https://github.com/restic/restic.git
synced 2025-08-25 20:37:35 +00:00
restore: exclude/include xattrs
For: https://github.com/restic/restic/issues/5089 Signed-off-by: Tesshu Flower <tflower@redhat.com>
This commit is contained in:
@@ -230,8 +230,8 @@ func mkfifo(path string, mode uint32) (err error) {
|
||||
}
|
||||
|
||||
// NodeRestoreMetadata restores node metadata
|
||||
func NodeRestoreMetadata(node *restic.Node, path string, warn func(msg string)) error {
|
||||
err := nodeRestoreMetadata(node, path, warn)
|
||||
func NodeRestoreMetadata(node *restic.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
|
||||
// unless you're running as root, so ignore those.
|
||||
@@ -246,14 +246,14 @@ func NodeRestoreMetadata(node *restic.Node, path string, warn func(msg string))
|
||||
return err
|
||||
}
|
||||
|
||||
func nodeRestoreMetadata(node *restic.Node, path string, warn func(msg string)) error {
|
||||
func nodeRestoreMetadata(node *restic.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 {
|
||||
firsterr = errors.WithStack(err)
|
||||
}
|
||||
|
||||
if err := nodeRestoreExtendedAttributes(node, path); err != nil {
|
||||
if err := nodeRestoreExtendedAttributes(node, path, xattrSelectFilter); err != nil {
|
||||
debug.Log("error restoring extended attributes for %v: %v", path, err)
|
||||
if firsterr == nil {
|
||||
firsterr = err
|
||||
|
@@ -13,6 +13,7 @@ import (
|
||||
"github.com/google/go-cmp/cmp"
|
||||
"github.com/restic/restic/internal/errors"
|
||||
"github.com/restic/restic/internal/restic"
|
||||
"github.com/restic/restic/internal/test"
|
||||
rtest "github.com/restic/restic/internal/test"
|
||||
)
|
||||
|
||||
@@ -216,7 +217,8 @@ func TestNodeRestoreAt(t *testing.T) {
|
||||
nodePath = filepath.Join(tempdir, test.Name)
|
||||
}
|
||||
rtest.OK(t, NodeCreateAt(&test, nodePath))
|
||||
rtest.OK(t, NodeRestoreMetadata(&test, nodePath, func(msg string) { rtest.OK(t, fmt.Errorf("Warning triggered for path: %s: %s", nodePath, msg)) }))
|
||||
rtest.OK(t, NodeRestoreMetadata(&test, nodePath, func(msg string) { rtest.OK(t, fmt.Errorf("Warning triggered for path: %s: %s", nodePath, msg)) },
|
||||
func(_ string) bool { return true } /* restore all xattrs */))
|
||||
|
||||
fs := &Local{}
|
||||
meta, err := fs.OpenFile(nodePath, O_NOFOLLOW, true)
|
||||
@@ -291,6 +293,7 @@ func TestNodeRestoreMetadataError(t *testing.T) {
|
||||
nodePath := filepath.Join(tempdir, node.Name)
|
||||
|
||||
// This will fail because the target file does not exist
|
||||
err := NodeRestoreMetadata(node, nodePath, func(msg string) { rtest.OK(t, fmt.Errorf("Warning triggered for path: %s: %s", nodePath, msg)) })
|
||||
rtest.Assert(t, errors.Is(err, os.ErrNotExist), "failed for an unexpected reason")
|
||||
err := NodeRestoreMetadata(node, nodePath, func(msg string) { rtest.OK(t, fmt.Errorf("Warning triggered for path: %s: %s", nodePath, msg)) },
|
||||
func(_ string) bool { return true })
|
||||
test.Assert(t, errors.Is(err, os.ErrNotExist), "failed for an unexpected reason")
|
||||
}
|
||||
|
@@ -65,14 +65,17 @@ func handleXattrErr(err error) error {
|
||||
}
|
||||
}
|
||||
|
||||
func nodeRestoreExtendedAttributes(node *restic.Node, path string) error {
|
||||
func nodeRestoreExtendedAttributes(node *restic.Node, path string, xattrSelectFilter func(xattrName string) bool) error {
|
||||
expectedAttrs := map[string]struct{}{}
|
||||
for _, attr := range node.ExtendedAttributes {
|
||||
err := setxattr(path, attr.Name, attr.Value)
|
||||
if err != nil {
|
||||
return err
|
||||
// Only restore xattrs that match the filter
|
||||
if xattrSelectFilter(attr.Name) {
|
||||
err := setxattr(path, attr.Name, attr.Value)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
expectedAttrs[attr.Name] = struct{}{}
|
||||
}
|
||||
expectedAttrs[attr.Name] = struct{}{}
|
||||
}
|
||||
|
||||
// remove unexpected xattrs
|
||||
@@ -84,8 +87,11 @@ func nodeRestoreExtendedAttributes(node *restic.Node, path string) error {
|
||||
if _, ok := expectedAttrs[name]; ok {
|
||||
continue
|
||||
}
|
||||
if err := removexattr(path, name); err != nil {
|
||||
return err
|
||||
// Only attempt to remove xattrs that match the filter
|
||||
if xattrSelectFilter(name) {
|
||||
if err := removexattr(path, name); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -26,7 +26,7 @@ func setAndVerifyXattr(t *testing.T, file string, attrs []restic.ExtendedAttribu
|
||||
Type: restic.NodeTypeFile,
|
||||
ExtendedAttributes: attrs,
|
||||
}
|
||||
rtest.OK(t, nodeRestoreExtendedAttributes(node, file))
|
||||
rtest.OK(t, nodeRestoreExtendedAttributes(node, file, func(_ string) bool { return true } /*restore all xattrs*/))
|
||||
|
||||
nodeActual := &restic.Node{
|
||||
Type: restic.NodeTypeFile,
|
||||
|
Reference in New Issue
Block a user