unix: add F*xattr on Darwin
Add Fgetxattr, Flistxattr, Fremovexattr and Fsetxattr on Darwin. Also
add a corresponding test.
Updates golang/go#26832
Change-Id: Id75bfce90ccc024b567a7b066a9188a615b9eec4
Reviewed-on: https://go-review.googlesource.com/128537
Run-TryBot: Tobias Klauser <tobias.klauser@gmail.com>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Brad Fitzpatrick <bradfitz@golang.org>
diff --git a/unix/syscall_darwin.go b/unix/syscall_darwin.go
index 166ac0b..1aabc56 100644
--- a/unix/syscall_darwin.go
+++ b/unix/syscall_darwin.go
@@ -199,7 +199,13 @@
return getxattr(link, attr, xattrPointer(dest), len(dest), 0, XATTR_NOFOLLOW)
}
-//sys setxattr(path string, attr string, data *byte, size int, position uint32, options int) (err error)
+//sys fgetxattr(fd int, attr string, dest *byte, size int, position uint32, options int) (sz int, err error)
+
+func Fgetxattr(fd int, attr string, dest []byte) (sz int, err error) {
+ return fgetxattr(fd, attr, xattrPointer(dest), len(dest), 0, 0)
+}
+
+//sys setxattr(path string, attr string, data *byte, size int, position uint32, options int) (err error)
func Setxattr(path string, attr string, data []byte, flags int) (err error) {
// The parameters for the OS X implementation vary slightly compared to the
@@ -235,7 +241,13 @@
return setxattr(link, attr, xattrPointer(data), len(data), 0, flags|XATTR_NOFOLLOW)
}
-//sys removexattr(path string, attr string, options int) (err error)
+//sys fsetxattr(fd int, attr string, data *byte, size int, position uint32, options int) (err error)
+
+func Fsetxattr(fd int, attr string, data []byte, flags int) (err error) {
+ return fsetxattr(fd, attr, xattrPointer(data), len(data), 0, 0)
+}
+
+//sys removexattr(path string, attr string, options int) (err error)
func Removexattr(path string, attr string) (err error) {
// We wrap around and explicitly zero out the options provided to the OS X
@@ -248,6 +260,12 @@
return removexattr(link, attr, XATTR_NOFOLLOW)
}
+//sys fremovexattr(fd int, attr string, options int) (err error)
+
+func Fremovexattr(fd int, attr string) (err error) {
+ return fremovexattr(fd, attr, 0)
+}
+
//sys listxattr(path string, dest *byte, size int, options int) (sz int, err error)
func Listxattr(path string, dest []byte) (sz int, err error) {
@@ -258,6 +276,12 @@
return listxattr(link, xattrPointer(dest), len(dest), XATTR_NOFOLLOW)
}
+//sys flistxattr(fd int, dest *byte, size int, options int) (sz int, err error)
+
+func Flistxattr(fd int, dest []byte) (sz int, err error) {
+ return flistxattr(fd, xattrPointer(dest), len(dest), 0)
+}
+
func setattrlistTimes(path string, times []Timespec, flags int) error {
_p0, err := BytePtrFromString(path)
if err != nil {
@@ -529,10 +553,6 @@
// Watchevent
// Waitevent
// Modwatch
-// Fgetxattr
-// Fsetxattr
-// Fremovexattr
-// Flistxattr
// Fsctl
// Initgroups
// Posix_spawn
diff --git a/unix/xattr_test.go b/unix/xattr_test.go
index b8b28d0..595492e 100644
--- a/unix/xattr_test.go
+++ b/unix/xattr_test.go
@@ -7,6 +7,7 @@
package unix_test
import (
+ "io/ioutil"
"os"
"runtime"
"strings"
@@ -117,3 +118,84 @@
}
}
}
+
+func TestFdXattr(t *testing.T) {
+ file, err := ioutil.TempFile("", "TestFdXattr")
+ if err != nil {
+ t.Fatal(err)
+ }
+ defer os.Remove(file.Name())
+ defer file.Close()
+
+ fd := int(file.Fd())
+ xattrName := "user.test"
+ xattrDataSet := "gopher"
+
+ err = unix.Fsetxattr(fd, xattrName, []byte(xattrDataSet), 0)
+ if err == unix.ENOTSUP || err == unix.EOPNOTSUPP {
+ t.Skip("filesystem does not support extended attributes, skipping test")
+ } else if err != nil {
+ t.Fatalf("Fsetxattr: %v", err)
+ }
+
+ // find size
+ size, err := unix.Flistxattr(fd, nil)
+ if err != nil {
+ t.Fatalf("Flistxattr: %v", err)
+ }
+
+ if size <= 0 {
+ t.Fatalf("Flistxattr returned an empty list of attributes")
+ }
+
+ buf := make([]byte, size)
+ read, err := unix.Flistxattr(fd, buf)
+ if err != nil {
+ t.Fatalf("Flistxattr: %v", err)
+ }
+
+ xattrs := stringsFromByteSlice(buf[:read])
+
+ xattrWant := xattrName
+ if runtime.GOOS == "freebsd" {
+ // On FreeBSD, the namespace is stored separately from the xattr
+ // name and Listxattr doesn't return the namespace prefix.
+ xattrWant = strings.TrimPrefix(xattrWant, "user.")
+ }
+ found := false
+ for _, name := range xattrs {
+ if name == xattrWant {
+ found = true
+ }
+ }
+
+ if !found {
+ t.Errorf("Flistxattr did not return previously set attribute '%s'", xattrName)
+ }
+
+ // find size
+ size, err = unix.Fgetxattr(fd, xattrName, nil)
+ if err != nil {
+ t.Fatalf("Fgetxattr: %v", err)
+ }
+
+ if size <= 0 {
+ t.Fatalf("Fgetxattr returned an empty attribute")
+ }
+
+ xattrDataGet := make([]byte, size)
+ _, err = unix.Fgetxattr(fd, xattrName, xattrDataGet)
+ if err != nil {
+ t.Fatalf("Fgetxattr: %v", err)
+ }
+
+ got := string(xattrDataGet)
+ if got != xattrDataSet {
+ t.Errorf("Fgetxattr: expected attribute value %s, got %s", xattrDataSet, got)
+ }
+
+ err = unix.Fremovexattr(fd, xattrName)
+ if err != nil {
+ t.Fatalf("Fremovexattr: %v", err)
+ }
+}
diff --git a/unix/zsyscall_darwin_386.go b/unix/zsyscall_darwin_386.go
index ac02d4d..9ce06df 100644
--- a/unix/zsyscall_darwin_386.go
+++ b/unix/zsyscall_darwin_386.go
@@ -420,6 +420,22 @@
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+func fgetxattr(fd int, attr string, dest *byte, size int, position uint32, options int) (sz int, err error) {
+ var _p0 *byte
+ _p0, err = BytePtrFromString(attr)
+ if err != nil {
+ return
+ }
+ r0, _, e1 := Syscall6(SYS_FGETXATTR, uintptr(fd), uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(dest)), uintptr(size), uintptr(position), uintptr(options))
+ sz = int(r0)
+ if e1 != 0 {
+ err = errnoErr(e1)
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
func setxattr(path string, attr string, data *byte, size int, position uint32, options int) (err error) {
var _p0 *byte
_p0, err = BytePtrFromString(path)
@@ -440,6 +456,21 @@
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+func fsetxattr(fd int, attr string, data *byte, size int, position uint32, options int) (err error) {
+ var _p0 *byte
+ _p0, err = BytePtrFromString(attr)
+ if err != nil {
+ return
+ }
+ _, _, e1 := Syscall6(SYS_FSETXATTR, uintptr(fd), uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(data)), uintptr(size), uintptr(position), uintptr(options))
+ if e1 != 0 {
+ err = errnoErr(e1)
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
func removexattr(path string, attr string, options int) (err error) {
var _p0 *byte
_p0, err = BytePtrFromString(path)
@@ -460,6 +491,21 @@
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+func fremovexattr(fd int, attr string, options int) (err error) {
+ var _p0 *byte
+ _p0, err = BytePtrFromString(attr)
+ if err != nil {
+ return
+ }
+ _, _, e1 := Syscall(SYS_FREMOVEXATTR, uintptr(fd), uintptr(unsafe.Pointer(_p0)), uintptr(options))
+ if e1 != 0 {
+ err = errnoErr(e1)
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
func listxattr(path string, dest *byte, size int, options int) (sz int, err error) {
var _p0 *byte
_p0, err = BytePtrFromString(path)
@@ -476,6 +522,17 @@
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+func flistxattr(fd int, dest *byte, size int, options int) (sz int, err error) {
+ r0, _, e1 := Syscall6(SYS_FLISTXATTR, uintptr(fd), uintptr(unsafe.Pointer(dest)), uintptr(size), uintptr(options), 0, 0)
+ sz = int(r0)
+ if e1 != 0 {
+ err = errnoErr(e1)
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
func kill(pid int, signum int, posix int) (err error) {
_, _, e1 := Syscall(SYS_KILL, uintptr(pid), uintptr(signum), uintptr(posix))
if e1 != 0 {
diff --git a/unix/zsyscall_darwin_amd64.go b/unix/zsyscall_darwin_amd64.go
index 1dd3cfa..de99270 100644
--- a/unix/zsyscall_darwin_amd64.go
+++ b/unix/zsyscall_darwin_amd64.go
@@ -420,6 +420,22 @@
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+func fgetxattr(fd int, attr string, dest *byte, size int, position uint32, options int) (sz int, err error) {
+ var _p0 *byte
+ _p0, err = BytePtrFromString(attr)
+ if err != nil {
+ return
+ }
+ r0, _, e1 := Syscall6(SYS_FGETXATTR, uintptr(fd), uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(dest)), uintptr(size), uintptr(position), uintptr(options))
+ sz = int(r0)
+ if e1 != 0 {
+ err = errnoErr(e1)
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
func setxattr(path string, attr string, data *byte, size int, position uint32, options int) (err error) {
var _p0 *byte
_p0, err = BytePtrFromString(path)
@@ -440,6 +456,21 @@
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+func fsetxattr(fd int, attr string, data *byte, size int, position uint32, options int) (err error) {
+ var _p0 *byte
+ _p0, err = BytePtrFromString(attr)
+ if err != nil {
+ return
+ }
+ _, _, e1 := Syscall6(SYS_FSETXATTR, uintptr(fd), uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(data)), uintptr(size), uintptr(position), uintptr(options))
+ if e1 != 0 {
+ err = errnoErr(e1)
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
func removexattr(path string, attr string, options int) (err error) {
var _p0 *byte
_p0, err = BytePtrFromString(path)
@@ -460,6 +491,21 @@
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+func fremovexattr(fd int, attr string, options int) (err error) {
+ var _p0 *byte
+ _p0, err = BytePtrFromString(attr)
+ if err != nil {
+ return
+ }
+ _, _, e1 := Syscall(SYS_FREMOVEXATTR, uintptr(fd), uintptr(unsafe.Pointer(_p0)), uintptr(options))
+ if e1 != 0 {
+ err = errnoErr(e1)
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
func listxattr(path string, dest *byte, size int, options int) (sz int, err error) {
var _p0 *byte
_p0, err = BytePtrFromString(path)
@@ -476,6 +522,17 @@
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+func flistxattr(fd int, dest *byte, size int, options int) (sz int, err error) {
+ r0, _, e1 := Syscall6(SYS_FLISTXATTR, uintptr(fd), uintptr(unsafe.Pointer(dest)), uintptr(size), uintptr(options), 0, 0)
+ sz = int(r0)
+ if e1 != 0 {
+ err = errnoErr(e1)
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
func kill(pid int, signum int, posix int) (err error) {
_, _, e1 := Syscall(SYS_KILL, uintptr(pid), uintptr(signum), uintptr(posix))
if e1 != 0 {
diff --git a/unix/zsyscall_darwin_arm.go b/unix/zsyscall_darwin_arm.go
index cab46e7..81c4f09 100644
--- a/unix/zsyscall_darwin_arm.go
+++ b/unix/zsyscall_darwin_arm.go
@@ -420,6 +420,22 @@
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+func fgetxattr(fd int, attr string, dest *byte, size int, position uint32, options int) (sz int, err error) {
+ var _p0 *byte
+ _p0, err = BytePtrFromString(attr)
+ if err != nil {
+ return
+ }
+ r0, _, e1 := Syscall6(SYS_FGETXATTR, uintptr(fd), uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(dest)), uintptr(size), uintptr(position), uintptr(options))
+ sz = int(r0)
+ if e1 != 0 {
+ err = errnoErr(e1)
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
func setxattr(path string, attr string, data *byte, size int, position uint32, options int) (err error) {
var _p0 *byte
_p0, err = BytePtrFromString(path)
@@ -440,6 +456,21 @@
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+func fsetxattr(fd int, attr string, data *byte, size int, position uint32, options int) (err error) {
+ var _p0 *byte
+ _p0, err = BytePtrFromString(attr)
+ if err != nil {
+ return
+ }
+ _, _, e1 := Syscall6(SYS_FSETXATTR, uintptr(fd), uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(data)), uintptr(size), uintptr(position), uintptr(options))
+ if e1 != 0 {
+ err = errnoErr(e1)
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
func removexattr(path string, attr string, options int) (err error) {
var _p0 *byte
_p0, err = BytePtrFromString(path)
@@ -460,6 +491,21 @@
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+func fremovexattr(fd int, attr string, options int) (err error) {
+ var _p0 *byte
+ _p0, err = BytePtrFromString(attr)
+ if err != nil {
+ return
+ }
+ _, _, e1 := Syscall(SYS_FREMOVEXATTR, uintptr(fd), uintptr(unsafe.Pointer(_p0)), uintptr(options))
+ if e1 != 0 {
+ err = errnoErr(e1)
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
func listxattr(path string, dest *byte, size int, options int) (sz int, err error) {
var _p0 *byte
_p0, err = BytePtrFromString(path)
@@ -476,6 +522,17 @@
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+func flistxattr(fd int, dest *byte, size int, options int) (sz int, err error) {
+ r0, _, e1 := Syscall6(SYS_FLISTXATTR, uintptr(fd), uintptr(unsafe.Pointer(dest)), uintptr(size), uintptr(options), 0, 0)
+ sz = int(r0)
+ if e1 != 0 {
+ err = errnoErr(e1)
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
func kill(pid int, signum int, posix int) (err error) {
_, _, e1 := Syscall(SYS_KILL, uintptr(pid), uintptr(signum), uintptr(posix))
if e1 != 0 {
diff --git a/unix/zsyscall_darwin_arm64.go b/unix/zsyscall_darwin_arm64.go
index 13478dd..338c32d 100644
--- a/unix/zsyscall_darwin_arm64.go
+++ b/unix/zsyscall_darwin_arm64.go
@@ -420,6 +420,22 @@
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+func fgetxattr(fd int, attr string, dest *byte, size int, position uint32, options int) (sz int, err error) {
+ var _p0 *byte
+ _p0, err = BytePtrFromString(attr)
+ if err != nil {
+ return
+ }
+ r0, _, e1 := Syscall6(SYS_FGETXATTR, uintptr(fd), uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(dest)), uintptr(size), uintptr(position), uintptr(options))
+ sz = int(r0)
+ if e1 != 0 {
+ err = errnoErr(e1)
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
func setxattr(path string, attr string, data *byte, size int, position uint32, options int) (err error) {
var _p0 *byte
_p0, err = BytePtrFromString(path)
@@ -440,6 +456,21 @@
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+func fsetxattr(fd int, attr string, data *byte, size int, position uint32, options int) (err error) {
+ var _p0 *byte
+ _p0, err = BytePtrFromString(attr)
+ if err != nil {
+ return
+ }
+ _, _, e1 := Syscall6(SYS_FSETXATTR, uintptr(fd), uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(data)), uintptr(size), uintptr(position), uintptr(options))
+ if e1 != 0 {
+ err = errnoErr(e1)
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
func removexattr(path string, attr string, options int) (err error) {
var _p0 *byte
_p0, err = BytePtrFromString(path)
@@ -460,6 +491,21 @@
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+func fremovexattr(fd int, attr string, options int) (err error) {
+ var _p0 *byte
+ _p0, err = BytePtrFromString(attr)
+ if err != nil {
+ return
+ }
+ _, _, e1 := Syscall(SYS_FREMOVEXATTR, uintptr(fd), uintptr(unsafe.Pointer(_p0)), uintptr(options))
+ if e1 != 0 {
+ err = errnoErr(e1)
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
func listxattr(path string, dest *byte, size int, options int) (sz int, err error) {
var _p0 *byte
_p0, err = BytePtrFromString(path)
@@ -476,6 +522,17 @@
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+func flistxattr(fd int, dest *byte, size int, options int) (sz int, err error) {
+ r0, _, e1 := Syscall6(SYS_FLISTXATTR, uintptr(fd), uintptr(unsafe.Pointer(dest)), uintptr(size), uintptr(options), 0, 0)
+ sz = int(r0)
+ if e1 != 0 {
+ err = errnoErr(e1)
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
func kill(pid int, signum int, posix int) (err error) {
_, _, e1 := Syscall(SYS_KILL, uintptr(pid), uintptr(signum), uintptr(posix))
if e1 != 0 {