diff --git a/changelog/unreleased/issue-4375 b/changelog/unreleased/issue-4375 new file mode 100644 index 000000000..6ce68c2ba --- /dev/null +++ b/changelog/unreleased/issue-4375 @@ -0,0 +1,8 @@ +Enhancement: Add support for extended attributes on symlinks + +Restic now supports extended attributes on symlinks when backing up, +restoring, or FUSE-mounting snapshots. This includes, for example, the +`security.selinux` xattr on Linux distributions that use SELinux. + +https://github.com/restic/restic/issues/4375 +https://github.com/restic/restic/pull/4379 diff --git a/internal/fuse/link.go b/internal/fuse/link.go index c89451602..43b00a855 100644 --- a/internal/fuse/link.go +++ b/internal/fuse/link.go @@ -6,6 +6,8 @@ package fuse import ( "context" + "github.com/restic/restic/internal/debug" + "github.com/anacrolix/fuse" "github.com/anacrolix/fuse/fs" "github.com/restic/restic/internal/restic" @@ -46,3 +48,21 @@ func (l *link) Attr(_ context.Context, a *fuse.Attr) error { return nil } + +func (l *link) Listxattr(_ context.Context, req *fuse.ListxattrRequest, resp *fuse.ListxattrResponse) error { + debug.Log("Listxattr(%v, %v)", l.node.Name, req.Size) + for _, attr := range l.node.ExtendedAttributes { + resp.Append(attr.Name) + } + return nil +} + +func (l *link) Getxattr(_ context.Context, req *fuse.GetxattrRequest, resp *fuse.GetxattrResponse) error { + debug.Log("Getxattr(%v, %v, %v)", l.node.Name, req.Name, req.Size) + attrval := l.node.GetExtendedAttribute(req.Name) + if attrval != nil { + resp.Xattr = attrval + return nil + } + return fuse.ErrNoXattr +} diff --git a/internal/restic/node.go b/internal/restic/node.go index 7d2a1434e..f2d9f2315 100644 --- a/internal/restic/node.go +++ b/internal/restic/node.go @@ -609,10 +609,6 @@ func (node *Node) fillExtra(path string, fi os.FileInfo) error { } func (node *Node) fillExtendedAttributes(path string) error { - if node.Type == "symlink" { - return nil - } - xattrs, err := Listxattr(path) debug.Log("fillExtendedAttributes(%v) %v %v", path, xattrs, err) if err != nil { diff --git a/internal/restic/node_xattr.go b/internal/restic/node_xattr.go index a2eed39c0..ea9eafe94 100644 --- a/internal/restic/node_xattr.go +++ b/internal/restic/node_xattr.go @@ -13,20 +13,20 @@ import ( // Getxattr retrieves extended attribute data associated with path. func Getxattr(path, name string) ([]byte, error) { - b, err := xattr.Get(path, name) + b, err := xattr.LGet(path, name) return b, handleXattrErr(err) } // Listxattr retrieves a list of names of extended attributes associated with the // given path in the file system. func Listxattr(path string) ([]string, error) { - l, err := xattr.List(path) + l, err := xattr.LList(path) return l, handleXattrErr(err) } // Setxattr associates name and data together as an attribute of path. func Setxattr(path, name string, data []byte) error { - return handleXattrErr(xattr.Set(path, name, data)) + return handleXattrErr(xattr.LSet(path, name, data)) } func handleXattrErr(err error) error {