123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280 |
- // 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
- 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
- }
|