Browse Source

unix: add symlink-safe *xattr functions on darwin

Updates golang/go#14456

Change-Id: I04632ef1d302e938a2cc373eb90f600f01404380
Reviewed-on: https://go-review.googlesource.com/114198
Run-TryBot: Tobias Klauser <tobias.klauser@gmail.com>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Brad Fitzpatrick <bradfitz@golang.org>
Tobias Klauser 7 years ago
parent
commit
77b0e43150

+ 2 - 1
unix/mkerrors.sh

@@ -50,6 +50,7 @@ includes_Darwin='
 #include <sys/mount.h>
 #include <sys/utsname.h>
 #include <sys/wait.h>
+#include <sys/xattr.h>
 #include <net/bpf.h>
 #include <net/if.h>
 #include <net/if_types.h>
@@ -437,7 +438,7 @@ ccflags="$@"
 		$2 ~ /^GENL_/ ||
 		$2 ~ /^STATX_/ ||
 		$2 ~ /^UTIME_/ ||
-		$2 ~ /^XATTR_(CREATE|REPLACE)/ ||
+		$2 ~ /^XATTR_(CREATE|REPLACE|NO(DEFAULT|FOLLOW|SECURITY)|SHOWCOMPRESSION)/ ||
 		$2 ~ /^ATTR_(BIT_MAP_COUNT|(CMN|VOL|FILE)_)/ ||
 		$2 ~ /^FSOPT_/ ||
 		$2 ~ /^WDIOC_/ ||

+ 26 - 15
unix/syscall_darwin.go

@@ -176,9 +176,7 @@ func Getfsstat(buf []Statfs_t, flags int) (n int, err error) {
 	return
 }
 
-//sys	getxattr(path string, attr string, dest *byte, size int, position uint32, options int) (sz int, err error)
-
-func Getxattr(path string, attr string, dest []byte) (sz int, err error) {
+func xattrPointer(dest []byte) *byte {
 	// It's only when dest is set to NULL that the OS X implementations of
 	// getxattr() and listxattr() return the current sizes of the named attributes.
 	// An empty byte array is not sufficient. To maintain the same behaviour as the
@@ -188,7 +186,17 @@ func Getxattr(path string, attr string, dest []byte) (sz int, err error) {
 	if len(dest) > 0 {
 		destp = &dest[0]
 	}
-	return getxattr(path, attr, destp, len(dest), 0, 0)
+	return destp
+}
+
+//sys	getxattr(path string, attr string, dest *byte, size int, position uint32, options int) (sz int, err error)
+
+func Getxattr(path string, attr string, dest []byte) (sz int, err error) {
+	return getxattr(path, attr, xattrPointer(dest), len(dest), 0, 0)
+}
+
+func Lgetxattr(link string, attr string, dest []byte) (sz int, err error) {
+	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)
@@ -220,11 +228,11 @@ func Setxattr(path string, attr string, data []byte, flags int) (err error) {
 	// current implementation, only the resource fork extended attribute makes
 	// use of this argument. For all others, position is reserved. We simply
 	// default to setting it to zero.
-	var datap *byte
-	if len(data) > 0 {
-		datap = &data[0]
-	}
-	return setxattr(path, attr, datap, len(data), 0, flags)
+	return setxattr(path, attr, xattrPointer(data), len(data), 0, flags)
+}
+
+func Lsetxattr(link string, attr string, data []byte, flags int) (err error) {
+	return setxattr(link, attr, xattrPointer(data), len(data), 0, flags|XATTR_NOFOLLOW)
 }
 
 //sys removexattr(path string, attr string, options int) (err error)
@@ -236,15 +244,18 @@ func Removexattr(path string, attr string) (err error) {
 	return removexattr(path, attr, 0)
 }
 
+func Lremovexattr(link string, attr string) (err error) {
+	return removexattr(link, attr, XATTR_NOFOLLOW)
+}
+
 //sys	listxattr(path string, dest *byte, size int, options int) (sz int, err error)
 
 func Listxattr(path string, dest []byte) (sz int, err error) {
-	// See comment in Getxattr for as to why Listxattr is implemented as such.
-	var destp *byte
-	if len(dest) > 0 {
-		destp = &dest[0]
-	}
-	return listxattr(path, destp, len(dest), 0)
+	return listxattr(path, xattrPointer(dest), len(dest), 0)
+}
+
+func Llistxattr(link string, dest []byte) (sz int, err error) {
+	return listxattr(link, xattrPointer(dest), len(dest), XATTR_NOFOLLOW)
 }
 
 func setattrlistTimes(path string, times []Timespec, flags int) error {

+ 26 - 0
unix/xattr_test.go

@@ -7,6 +7,7 @@
 package unix_test
 
 import (
+	"os"
 	"runtime"
 	"strings"
 	"testing"
@@ -89,4 +90,29 @@ func TestXattr(t *testing.T) {
 	if err != nil {
 		t.Fatalf("Removexattr: %v", err)
 	}
+
+	n := "nonexistent"
+	err = unix.Lsetxattr(n, xattrName, []byte(xattrDataSet), 0)
+	if err != unix.ENOENT {
+		t.Errorf("Lsetxattr: expected %v on non-existent file, got %v", unix.ENOENT, err)
+	}
+
+	_, err = unix.Lgetxattr(n, xattrName, nil)
+	if err != unix.ENOENT {
+		t.Errorf("Lgetxattr: %v", err)
+	}
+
+	s := "symlink1"
+	err = os.Symlink(n, s)
+	if err != nil {
+		t.Fatal(err)
+	}
+
+	// Linux doesn't support xattrs on symlink according to xattr(7), so
+	// just test that we get the proper errors.
+
+	err = unix.Lsetxattr(s, xattrName, []byte(xattrDataSet), 0)
+	if err != nil && (runtime.GOOS != "linux" || err != unix.EPERM) {
+		t.Fatalf("Lsetxattr: %v", err)
+	}
 }

+ 6 - 0
unix/zerrors_darwin_386.go

@@ -1473,6 +1473,12 @@ const (
 	WORDSIZE                          = 0x20
 	WSTOPPED                          = 0x8
 	WUNTRACED                         = 0x2
+	XATTR_CREATE                      = 0x2
+	XATTR_NODEFAULT                   = 0x10
+	XATTR_NOFOLLOW                    = 0x1
+	XATTR_NOSECURITY                  = 0x8
+	XATTR_REPLACE                     = 0x4
+	XATTR_SHOWCOMPRESSION             = 0x20
 )
 
 // Errors

+ 6 - 0
unix/zerrors_darwin_amd64.go

@@ -1473,6 +1473,12 @@ const (
 	WORDSIZE                          = 0x40
 	WSTOPPED                          = 0x8
 	WUNTRACED                         = 0x2
+	XATTR_CREATE                      = 0x2
+	XATTR_NODEFAULT                   = 0x10
+	XATTR_NOFOLLOW                    = 0x1
+	XATTR_NOSECURITY                  = 0x8
+	XATTR_REPLACE                     = 0x4
+	XATTR_SHOWCOMPRESSION             = 0x20
 )
 
 // Errors

+ 6 - 0
unix/zerrors_darwin_arm.go

@@ -1473,6 +1473,12 @@ const (
 	WORDSIZE                          = 0x40
 	WSTOPPED                          = 0x8
 	WUNTRACED                         = 0x2
+	XATTR_CREATE                      = 0x2
+	XATTR_NODEFAULT                   = 0x10
+	XATTR_NOFOLLOW                    = 0x1
+	XATTR_NOSECURITY                  = 0x8
+	XATTR_REPLACE                     = 0x4
+	XATTR_SHOWCOMPRESSION             = 0x20
 )
 
 // Errors

+ 6 - 0
unix/zerrors_darwin_arm64.go

@@ -1473,6 +1473,12 @@ const (
 	WORDSIZE                          = 0x40
 	WSTOPPED                          = 0x8
 	WUNTRACED                         = 0x2
+	XATTR_CREATE                      = 0x2
+	XATTR_NODEFAULT                   = 0x10
+	XATTR_NOFOLLOW                    = 0x1
+	XATTR_NOSECURITY                  = 0x8
+	XATTR_REPLACE                     = 0x4
+	XATTR_SHOWCOMPRESSION             = 0x20
 )
 
 // Errors