1
0
mirror of https://github.com/lxc/incus.git synced 2026-02-06 12:46:34 +01:00
Files
incus/shared/idmap/internal_linux.go
Stéphane Graber f0e60843f0 shared/idmap: Skip xattrs on EINVAL
When parsing extended attributes, we may be getting EINVAL when run on ZFS.

This appears to be when dealing with ZFS namespaced xattrs and despite
being real root with all capabilities, there appears to be no way to
read or even clear those attributes.

So instead of crashing mid-shift, let's just log them and move on.

Signed-off-by: Stéphane Graber <stgraber@stgraber.org>
Sponsored-by: https://webdock.io
2025-09-24 02:20:17 -04:00

71 lines
1.8 KiB
Go

//go:build linux && cgo
package idmap
import (
"errors"
"fmt"
"os"
"github.com/pkg/xattr"
"golang.org/x/sys/unix"
"github.com/lxc/incus/v6/shared/logger"
)
// The functions below are verbatim copies of the functions found in the internal package.
// They have been copied here due to there not being a good place for
// them in the shared package and because we have a policy not to import
// anything from internal in one of our shared packages.
// getAllXattr retrieves all extended attributes associated with a file, directory or symbolic link.
func getAllXattr(path string) (map[string]string, error) {
xattrNames, err := xattr.LList(path)
if err != nil {
// Some filesystems don't support llistxattr() for various reasons.
// Interpret this as a set of no xattrs, instead of an error.
if errors.Is(err, unix.EOPNOTSUPP) {
return nil, nil
}
return nil, fmt.Errorf("Failed getting extended attributes from %q: %w", path, err)
}
xattrs := make(map[string]string, len(xattrNames))
for _, xattrName := range xattrNames {
value, err := xattr.LGet(path, xattrName)
if err != nil {
if errors.Is(err, unix.EINVAL) {
logger.Warn("Skipping unreadable xattr during shift", logger.Ctx{"path": path, "xattr": xattrName})
continue
}
return nil, fmt.Errorf("Failed getting %q extended attribute from %q: %w", xattrName, path, err)
}
xattrs[xattrName] = string(value)
}
return xattrs, nil
}
// getErrno checks if the Go error is a kernel errno.
func getErrno(err error) (iserrno bool, errno error) {
sysErr, ok := err.(*os.SyscallError)
if ok {
return true, sysErr.Err
}
pathErr, ok := err.(*os.PathError)
if ok {
return true, pathErr.Err
}
tmpErrno, ok := err.(unix.Errno)
if ok {
return true, tmpErrno
}
return false, nil
}