2022-06-23 11:58:36 +00:00
|
|
|
//go:build solaris
|
|
|
|
// +build solaris
|
|
|
|
|
|
|
|
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 = 0x1
|
|
|
|
XATTR_REPLACE = 0x2
|
|
|
|
|
|
|
|
// 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
|
|
|
|
)
|
|
|
|
|
|
|
|
func getxattr(path string, name string, data []byte) (int, error) {
|
2024-07-22 20:55:31 +00:00
|
|
|
f, err := openNonblock(path)
|
2022-06-23 11:58:36 +00:00
|
|
|
if err != nil {
|
|
|
|
return 0, err
|
|
|
|
}
|
|
|
|
defer func() {
|
|
|
|
_ = f.Close()
|
|
|
|
}()
|
|
|
|
return fgetxattr(f, name, data)
|
|
|
|
}
|
|
|
|
|
|
|
|
func lgetxattr(path string, name string, data []byte) (int, error) {
|
|
|
|
return 0, unix.ENOTSUP
|
|
|
|
}
|
|
|
|
|
|
|
|
func fgetxattr(f *os.File, name string, data []byte) (int, error) {
|
|
|
|
fd, err := unix.Openat(int(f.Fd()), name, unix.O_RDONLY|unix.O_XATTR, 0)
|
|
|
|
if err != nil {
|
|
|
|
return 0, err
|
|
|
|
}
|
|
|
|
defer func() {
|
|
|
|
_ = unix.Close(fd)
|
|
|
|
}()
|
|
|
|
return unix.Read(fd, data)
|
|
|
|
}
|
|
|
|
|
|
|
|
func setxattr(path string, name string, data []byte, flags int) error {
|
2024-07-22 20:55:31 +00:00
|
|
|
f, err := openNonblock(path)
|
2022-06-23 11:58:36 +00:00
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
err = fsetxattr(f, name, data, flags)
|
|
|
|
if err != nil {
|
|
|
|
_ = f.Close()
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
return f.Close()
|
|
|
|
}
|
|
|
|
|
|
|
|
func lsetxattr(path string, name string, data []byte, flags int) error {
|
|
|
|
return unix.ENOTSUP
|
|
|
|
}
|
|
|
|
|
|
|
|
func fsetxattr(f *os.File, name string, data []byte, flags int) error {
|
|
|
|
mode := unix.O_WRONLY | unix.O_XATTR
|
|
|
|
if flags&XATTR_REPLACE != 0 {
|
|
|
|
mode |= unix.O_TRUNC
|
|
|
|
} else if flags&XATTR_CREATE != 0 {
|
|
|
|
mode |= unix.O_CREAT | unix.O_EXCL
|
|
|
|
} else {
|
|
|
|
mode |= unix.O_CREAT | unix.O_TRUNC
|
|
|
|
}
|
|
|
|
fd, err := unix.Openat(int(f.Fd()), name, mode, 0666)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
if _, err = unix.Write(fd, data); err != nil {
|
|
|
|
_ = unix.Close(fd)
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
return unix.Close(fd)
|
|
|
|
}
|
|
|
|
|
|
|
|
func removexattr(path string, name string) error {
|
2024-07-22 20:55:31 +00:00
|
|
|
mode := unix.O_RDONLY | unix.O_XATTR | unix.O_NONBLOCK | unix.O_CLOEXEC
|
|
|
|
fd, err := unix.Open(path, mode, 0)
|
2022-06-23 11:58:36 +00:00
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
f := os.NewFile(uintptr(fd), path)
|
|
|
|
defer func() {
|
|
|
|
_ = f.Close()
|
|
|
|
}()
|
|
|
|
return fremovexattr(f, name)
|
|
|
|
}
|
|
|
|
|
|
|
|
func lremovexattr(path string, name string) error {
|
|
|
|
return unix.ENOTSUP
|
|
|
|
}
|
|
|
|
|
|
|
|
func fremovexattr(f *os.File, name string) error {
|
|
|
|
fd, err := unix.Openat(int(f.Fd()), ".", unix.O_XATTR, 0)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
defer func() {
|
|
|
|
_ = unix.Close(fd)
|
|
|
|
}()
|
|
|
|
return unix.Unlinkat(fd, name, 0)
|
|
|
|
}
|
|
|
|
|
|
|
|
func listxattr(path string, data []byte) (int, error) {
|
2024-07-22 20:55:31 +00:00
|
|
|
f, err := openNonblock(path)
|
2022-06-23 11:58:36 +00:00
|
|
|
if err != nil {
|
|
|
|
return 0, err
|
|
|
|
}
|
|
|
|
defer func() {
|
|
|
|
_ = f.Close()
|
|
|
|
}()
|
|
|
|
return flistxattr(f, data)
|
|
|
|
}
|
|
|
|
|
|
|
|
func llistxattr(path string, data []byte) (int, error) {
|
|
|
|
return 0, unix.ENOTSUP
|
|
|
|
}
|
|
|
|
|
|
|
|
func flistxattr(f *os.File, data []byte) (int, error) {
|
|
|
|
fd, err := unix.Openat(int(f.Fd()), ".", unix.O_RDONLY|unix.O_XATTR, 0)
|
|
|
|
if err != nil {
|
2022-11-08 13:59:04 +00:00
|
|
|
return 0, unix.ENOTSUP
|
2022-06-23 11:58:36 +00:00
|
|
|
}
|
|
|
|
xf := os.NewFile(uintptr(fd), f.Name())
|
|
|
|
defer func() {
|
|
|
|
_ = xf.Close()
|
|
|
|
}()
|
|
|
|
names, err := xf.Readdirnames(-1)
|
|
|
|
if err != nil {
|
|
|
|
return 0, err
|
|
|
|
}
|
|
|
|
var buf []byte
|
|
|
|
for _, name := range names {
|
|
|
|
buf = append(buf, append([]byte(name), '\000')...)
|
|
|
|
}
|
|
|
|
if data == nil {
|
|
|
|
return len(buf), nil
|
|
|
|
}
|
|
|
|
return copy(data, buf), nil
|
|
|
|
}
|
|
|
|
|
2024-07-22 20:55:31 +00:00
|
|
|
// Like os.Open, but passes O_NONBLOCK to the open(2) syscall.
|
|
|
|
func openNonblock(path string) (*os.File, error) {
|
|
|
|
fd, err := unix.Open(path, unix.O_RDONLY|unix.O_CLOEXEC|unix.O_NONBLOCK, 0)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
return os.NewFile(uintptr(fd), path), err
|
|
|
|
}
|
|
|
|
|
2022-06-23 11:58:36 +00:00
|
|
|
// stringsFromByteSlice converts a sequence of attributes to a []string.
|
2024-07-22 20:55:31 +00:00
|
|
|
// We simulate Linux/Darwin, where each entry is a NULL-terminated string.
|
2022-06-23 11:58:36 +00:00
|
|
|
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
|
|
|
|
}
|