You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
280 lines
5.7 KiB
280 lines
5.7 KiB
// 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 |
|
}
|
|
|