//go:build linux // +build linux package xattr import ( "os" "syscall" "golang.org/x/sys/unix" ) const ( // XATTR_SUPPORTED will be true if the current platform is supported XATTR_SUPPORTED = true XATTR_CREATE = unix.XATTR_CREATE XATTR_REPLACE = unix.XATTR_REPLACE // ENOATTR is not exported by the syscall package on Linux, because it is // an alias for ENODATA. We export it here so it is available on all // our supported platforms. ENOATTR = syscall.ENODATA ) // On Linux, FUSE and CIFS filesystems can return EINTR for interrupted system // calls. This function works around this by retrying system calls until they // stop returning EINTR. // // See https://github.com/golang/go/commit/6b420169d798c7ebe733487b56ea5c3fa4aab5ce. func ignoringEINTR(fn func() error) (err error) { for { err = fn() if err != unix.EINTR { break } } return err } func getxattr(path string, name string, data []byte) (int, error) { var r int err := ignoringEINTR(func() (err error) { r, err = unix.Getxattr(path, name, data) return err }) return r, err } func lgetxattr(path string, name string, data []byte) (int, error) { var r int err := ignoringEINTR(func() (err error) { r, err = unix.Lgetxattr(path, name, data) return err }) return r, err } func fgetxattr(f *os.File, name string, data []byte) (int, error) { var r int err := ignoringEINTR(func() (err error) { r, err = unix.Fgetxattr(int(f.Fd()), name, data) return err }) return r, err } func setxattr(path string, name string, data []byte, flags int) error { return ignoringEINTR(func() (err error) { return unix.Setxattr(path, name, data, flags) }) } func lsetxattr(path string, name string, data []byte, flags int) error { return ignoringEINTR(func() (err error) { return unix.Lsetxattr(path, name, data, flags) }) } func fsetxattr(f *os.File, name string, data []byte, flags int) error { return ignoringEINTR(func() (err error) { return unix.Fsetxattr(int(f.Fd()), name, data, flags) }) } func removexattr(path string, name string) error { return ignoringEINTR(func() (err error) { return unix.Removexattr(path, name) }) } func lremovexattr(path string, name string) error { return ignoringEINTR(func() (err error) { return unix.Lremovexattr(path, name) }) } func fremovexattr(f *os.File, name string) error { return ignoringEINTR(func() (err error) { return unix.Fremovexattr(int(f.Fd()), name) }) } func listxattr(path string, data []byte) (int, error) { var r int err := ignoringEINTR(func() (err error) { r, err = unix.Listxattr(path, data) return err }) return r, err } func llistxattr(path string, data []byte) (int, error) { var r int err := ignoringEINTR(func() (err error) { r, err = unix.Llistxattr(path, data) return err }) return r, err } func flistxattr(f *os.File, data []byte) (int, error) { var r int err := ignoringEINTR(func() (err error) { r, err = unix.Flistxattr(int(f.Fd()), data) return err }) return r, err } // stringsFromByteSlice converts a sequence of attributes to a []string. // On Darwin and Linux, each entry is a NULL-terminated string. func stringsFromByteSlice(buf []byte) (result []string) { offset := 0 for index, b := range buf { if b == 0 { result = append(result, string(buf[offset:index])) offset = index + 1 } } return }