diff --git a/internal/restic/node_xattr.go b/internal/restic/node_xattr.go index 642eb8df4..307cc33e0 100644 --- a/internal/restic/node_xattr.go +++ b/internal/restic/node_xattr.go @@ -13,31 +13,39 @@ import ( // Getxattr retrieves extended attribute data associated with path. func Getxattr(path, name string) ([]byte, error) { - b, e := xattr.Get(path, name) - if err, ok := e.(*xattr.Error); ok && - (err.Err == syscall.ENOTSUP || err.Err == xattr.ENOATTR) { - return nil, nil - } - return b, errors.Wrap(e, "Getxattr") + b, err := xattr.Get(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) { - s, e := xattr.List(path) - if err, ok := e.(*xattr.Error); ok && - (err.Err == syscall.ENOTSUP || err.Err == xattr.ENOATTR) { - return nil, nil - } - return s, errors.Wrap(e, "Listxattr") + l, err := xattr.List(path) + return l, handleXattrErr(err) } // Setxattr associates name and data together as an attribute of path. func Setxattr(path, name string, data []byte) error { - e := xattr.Set(path, name, data) - if err, ok := e.(*xattr.Error); ok && - (err.Err == syscall.ENOTSUP || err.Err == xattr.ENOATTR) { - return nil - } - return errors.Wrap(e, "Setxattr") + return handleXattrErr(xattr.Set(path, name, data)) +} + +func handleXattrErr(err error) error { + switch e := err.(type) { + case nil: + return nil + + case *xattr.Error: + // On Solaris, xattr not being supported on a file is signaled + // by EINVAL (https://github.com/pkg/xattr/issues/67). + // On Linux, xattr calls on files in an SMB/CIFS mount can return + // ENOATTR instead of ENOTSUP. + switch e.Err { + case syscall.EINVAL, syscall.ENOTSUP, xattr.ENOATTR: + return nil + } + return errors.WithStack(e) + + default: + return errors.WithStack(e) + } }