containerd/vendor/golang.org/x/sys/unix/xattr_bsd.go
Akihiro Suda 52f82acb7b
btrfs: depend on kernel UAPI instead of libbtrfs
See containerd/btrfs PR 40 and moby/moby PR 44761. (Thanks to [@]neersighted.)

The containerd/btrfs library now requires headers from kernel 4.12 or newer:
- https://github.com/torvalds/linux/blob/master/include/uapi/linux/btrfs.h
- https://github.com/torvalds/linux/blob/master/include/uapi/linux/btrfs_tree.h

These files are licensed under the GPL-2.0 WITH Linux-syscall-note, so it should be compatible with the Apache License 2.0.
https://spdx.org/licenses/Linux-syscall-note.html

The dependency on the kernel headers only affects users building from source.
Users on older kernels may opt to not compile this library (`BUILDTAGS=no_btfs`),
or to provide headers from a newer kernel.

Signed-off-by: Akihiro Suda <akihiro.suda.cz@hco.ntt.co.jp>
2023-02-10 10:07:34 +09:00

282 lines
5.7 KiB
Go

// Copyright 2018 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
//go:build freebsd || netbsd
// +build freebsd netbsd
package unix
import (
"strings"
"unsafe"
)
// Derive extattr namespace and attribute name
func xattrnamespace(fullattr string) (ns int, attr string, err error) {
s := strings.IndexByte(fullattr, '.')
if s == -1 {
return -1, "", ENOATTR
}
namespace := fullattr[0:s]
attr = fullattr[s+1:]
switch namespace {
case "user":
return EXTATTR_NAMESPACE_USER, attr, nil
case "system":
return EXTATTR_NAMESPACE_SYSTEM, attr, nil
default:
return -1, "", ENOATTR
}
}
func initxattrdest(dest []byte, idx int) (d unsafe.Pointer) {
if len(dest) > idx {
return unsafe.Pointer(&dest[idx])
}
if dest != nil {
// extattr_get_file and extattr_list_file treat NULL differently from
// a non-NULL pointer of length zero. Preserve the property of nilness,
// even if we can't use dest directly.
return unsafe.Pointer(&_zero)
}
return nil
}
// FreeBSD and NetBSD implement their own syscalls to handle extended attributes
func Getxattr(file string, attr string, dest []byte) (sz int, err error) {
d := initxattrdest(dest, 0)
destsize := len(dest)
nsid, a, err := xattrnamespace(attr)
if err != nil {
return -1, err
}
return ExtattrGetFile(file, nsid, a, uintptr(d), destsize)
}
func Fgetxattr(fd int, attr string, dest []byte) (sz int, err error) {
d := initxattrdest(dest, 0)
destsize := len(dest)
nsid, a, err := xattrnamespace(attr)
if err != nil {
return -1, err
}
return ExtattrGetFd(fd, nsid, a, uintptr(d), destsize)
}
func Lgetxattr(link string, attr string, dest []byte) (sz int, err error) {
d := initxattrdest(dest, 0)
destsize := len(dest)
nsid, a, err := xattrnamespace(attr)
if err != nil {
return -1, err
}
return ExtattrGetLink(link, nsid, a, uintptr(d), destsize)
}
// flags are unused on FreeBSD
func Fsetxattr(fd int, attr string, data []byte, flags int) (err error) {
var d unsafe.Pointer
if len(data) > 0 {
d = unsafe.Pointer(&data[0])
}
datasiz := len(data)
nsid, a, err := xattrnamespace(attr)
if err != nil {
return
}
_, err = ExtattrSetFd(fd, nsid, a, uintptr(d), datasiz)
return
}
func Setxattr(file string, attr string, data []byte, flags int) (err error) {
var d unsafe.Pointer
if len(data) > 0 {
d = unsafe.Pointer(&data[0])
}
datasiz := len(data)
nsid, a, err := xattrnamespace(attr)
if err != nil {
return
}
_, err = ExtattrSetFile(file, nsid, a, uintptr(d), datasiz)
return
}
func Lsetxattr(link string, attr string, data []byte, flags int) (err error) {
var d unsafe.Pointer
if len(data) > 0 {
d = unsafe.Pointer(&data[0])
}
datasiz := len(data)
nsid, a, err := xattrnamespace(attr)
if err != nil {
return
}
_, err = ExtattrSetLink(link, nsid, a, uintptr(d), datasiz)
return
}
func Removexattr(file string, attr string) (err error) {
nsid, a, err := xattrnamespace(attr)
if err != nil {
return
}
err = ExtattrDeleteFile(file, nsid, a)
return
}
func Fremovexattr(fd int, attr string) (err error) {
nsid, a, err := xattrnamespace(attr)
if err != nil {
return
}
err = ExtattrDeleteFd(fd, nsid, a)
return
}
func Lremovexattr(link string, attr string) (err error) {
nsid, a, err := xattrnamespace(attr)
if err != nil {
return
}
err = ExtattrDeleteLink(link, nsid, a)
return
}
func Listxattr(file string, dest []byte) (sz int, err error) {
destsiz := len(dest)
// FreeBSD won't allow you to list xattrs from multiple namespaces
s, pos := 0, 0
for _, nsid := range [...]int{EXTATTR_NAMESPACE_USER, EXTATTR_NAMESPACE_SYSTEM} {
stmp, e := ListxattrNS(file, nsid, dest[pos:])
/* Errors accessing system attrs are ignored so that
* we can implement the Linux-like behavior of omitting errors that
* we don't have read permissions on
*
* Linux will still error if we ask for user attributes on a file that
* we don't have read permissions on, so don't ignore those errors
*/
if e != nil {
if e == EPERM && nsid != EXTATTR_NAMESPACE_USER {
continue
}
return s, e
}
s += stmp
pos = s
if pos > destsiz {
pos = destsiz
}
}
return s, nil
}
func ListxattrNS(file string, nsid int, dest []byte) (sz int, err error) {
d := initxattrdest(dest, 0)
destsiz := len(dest)
s, e := ExtattrListFile(file, nsid, uintptr(d), destsiz)
if e != nil {
return 0, err
}
return s, nil
}
func Flistxattr(fd int, dest []byte) (sz int, err error) {
destsiz := len(dest)
s, pos := 0, 0
for _, nsid := range [...]int{EXTATTR_NAMESPACE_USER, EXTATTR_NAMESPACE_SYSTEM} {
stmp, e := FlistxattrNS(fd, nsid, dest[pos:])
if e != nil {
if e == EPERM && nsid != EXTATTR_NAMESPACE_USER {
continue
}
return s, e
}
s += stmp
pos = s
if pos > destsiz {
pos = destsiz
}
}
return s, nil
}
func FlistxattrNS(fd int, nsid int, dest []byte) (sz int, err error) {
d := initxattrdest(dest, 0)
destsiz := len(dest)
s, e := ExtattrListFd(fd, nsid, uintptr(d), destsiz)
if e != nil {
return 0, err
}
return s, nil
}
func Llistxattr(link string, dest []byte) (sz int, err error) {
destsiz := len(dest)
s, pos := 0, 0
for _, nsid := range [...]int{EXTATTR_NAMESPACE_USER, EXTATTR_NAMESPACE_SYSTEM} {
stmp, e := LlistxattrNS(link, nsid, dest[pos:])
if e != nil {
if e == EPERM && nsid != EXTATTR_NAMESPACE_USER {
continue
}
return s, e
}
s += stmp
pos = s
if pos > destsiz {
pos = destsiz
}
}
return s, nil
}
func LlistxattrNS(link string, nsid int, dest []byte) (sz int, err error) {
d := initxattrdest(dest, 0)
destsiz := len(dest)
s, e := ExtattrListLink(link, nsid, uintptr(d), destsiz)
if e != nil {
return 0, err
}
return s, nil
}