| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231 | // 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.// +build freebsd netbsdpackage uniximport (	"strings"	"unsafe")// Derive extattr namespace and attribute namefunc 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])	} else {		return unsafe.Pointer(_zero)	}}// FreeBSD and NetBSD implement their own syscalls to handle extended attributesfunc 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 FreeBSDfunc Fsetxattr(fd int, attr string, data []byte, flags int) (err error) {	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) {	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) {	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) {	d := initxattrdest(dest, 0)	destsiz := len(dest)	// FreeBSD won't allow you to list xattrs from multiple namespaces	s := 0	for _, nsid := range [...]int{EXTATTR_NAMESPACE_USER, EXTATTR_NAMESPACE_SYSTEM} {		stmp, e := ExtattrListFile(file, nsid, uintptr(d), destsiz)		/* 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 && e == EPERM && nsid != EXTATTR_NAMESPACE_USER {			continue		} else if e != nil {			return s, e		}		s += stmp		destsiz -= s		if destsiz < 0 {			destsiz = 0		}		d = initxattrdest(dest, s)	}	return s, nil}func Flistxattr(fd int, dest []byte) (sz int, err error) {	d := initxattrdest(dest, 0)	destsiz := len(dest)	s := 0	for _, nsid := range [...]int{EXTATTR_NAMESPACE_USER, EXTATTR_NAMESPACE_SYSTEM} {		stmp, e := ExtattrListFd(fd, nsid, uintptr(d), destsiz)		if e != nil && e == EPERM && nsid != EXTATTR_NAMESPACE_USER {			continue		} else if e != nil {			return s, e		}		s += stmp		destsiz -= s		if destsiz < 0 {			destsiz = 0		}		d = initxattrdest(dest, s)	}	return s, nil}func Llistxattr(link string, dest []byte) (sz int, err error) {	d := initxattrdest(dest, 0)	destsiz := len(dest)	s := 0	for _, nsid := range [...]int{EXTATTR_NAMESPACE_USER, EXTATTR_NAMESPACE_SYSTEM} {		stmp, e := ExtattrListLink(link, nsid, uintptr(d), destsiz)		if e != nil && e == EPERM && nsid != EXTATTR_NAMESPACE_USER {			continue		} else if e != nil {			return s, e		}		s += stmp		destsiz -= s		if destsiz < 0 {			destsiz = 0		}		d = initxattrdest(dest, s)	}	return s, nil}
 |