unix: add bindings for setattrlist() on macOS

The setattrlist() function can be used to mutate the attributes of files through a single call. For example, one can perform a chmod(), chown(), chflags(), [...] all at once.

This change also adds bindings for the UF_* and SF_* flags that are accepted by chflags(). This makes it possible to use setattrlist() to perform the equivalent of lchflags(), for which we currently have no binding.

Change-Id: Ib5a604503a984b95a02b65ad1a437246cd170584
GitHub-Last-Rev: 45dd9d475aa72d628eaa4d06221adba6afd60278
GitHub-Pull-Request: golang/sys#155
Reviewed-on: https://go-review.googlesource.com/c/sys/+/481815
Reviewed-by: Ian Lance Taylor <iant@google.com>
Reviewed-by: Tobias Klauser <tobias.klauser@gmail.com>
Reviewed-by: Michael Knyszek <mknyszek@google.com>
Run-TryBot: Ian Lance Taylor <iant@google.com>
Auto-Submit: Ian Lance Taylor <iant@google.com>
TryBot-Result: Gopher Robot <gobot@golang.org>
Run-TryBot: Ian Lance Taylor <iant@golang.org>
diff --git a/unix/darwin_amd64_test.go b/unix/darwin_amd64_test.go
index 5360144..1b42017 100644
--- a/unix/darwin_amd64_test.go
+++ b/unix/darwin_amd64_test.go
@@ -119,6 +119,7 @@
 	{"sendfile", libc_sendfile_trampoline_addr},
 	{"sendmsg", libc_sendmsg_trampoline_addr},
 	{"sendto", libc_sendto_trampoline_addr},
+	{"setattrlist", libc_setattrlist_trampoline_addr},
 	{"setegid", libc_setegid_trampoline_addr},
 	{"seteuid", libc_seteuid_trampoline_addr},
 	{"setgid", libc_setgid_trampoline_addr},
diff --git a/unix/darwin_arm64_test.go b/unix/darwin_arm64_test.go
index fae08af..d168bfc 100644
--- a/unix/darwin_arm64_test.go
+++ b/unix/darwin_arm64_test.go
@@ -119,6 +119,7 @@
 	{"sendfile", libc_sendfile_trampoline_addr},
 	{"sendmsg", libc_sendmsg_trampoline_addr},
 	{"sendto", libc_sendto_trampoline_addr},
+	{"setattrlist", libc_setattrlist_trampoline_addr},
 	{"setegid", libc_setegid_trampoline_addr},
 	{"seteuid", libc_seteuid_trampoline_addr},
 	{"setgid", libc_setgid_trampoline_addr},
diff --git a/unix/mkerrors.sh b/unix/mkerrors.sh
index 7456d9d..2045d3d 100755
--- a/unix/mkerrors.sh
+++ b/unix/mkerrors.sh
@@ -66,6 +66,7 @@
 #include <sys/ptrace.h>
 #include <sys/select.h>
 #include <sys/socket.h>
+#include <sys/stat.h>
 #include <sys/un.h>
 #include <sys/sockio.h>
 #include <sys/sys_domain.h>
@@ -521,6 +522,7 @@
 		$2 ~ /^NFC_(GENL|PROTO|COMM|RF|SE|DIRECTION|LLCP|SOCKPROTO)_/ ||
 		$2 ~ /^NFC_.*_(MAX)?SIZE$/ ||
 		$2 ~ /^RAW_PAYLOAD_/ ||
+		$2 ~ /^[US]F_/ ||
 		$2 ~ /^TP_STATUS_/ ||
 		$2 ~ /^FALLOC_/ ||
 		$2 ~ /^ICMPV?6?_(FILTER|SEC)/ ||
diff --git a/unix/syscall_darwin.go b/unix/syscall_darwin.go
index 25eab4f..2069215 100644
--- a/unix/syscall_darwin.go
+++ b/unix/syscall_darwin.go
@@ -613,6 +613,7 @@
 //sys	Rmdir(path string) (err error)
 //sys	Seek(fd int, offset int64, whence int) (newoffset int64, err error) = SYS_LSEEK
 //sys	Select(nfd int, r *FdSet, w *FdSet, e *FdSet, timeout *Timeval) (n int, err error)
+//sys	Setattrlist(path string, attrlist *Attrlist, attrBuf []byte, options int) (err error)
 //sys	Setegid(egid int) (err error)
 //sysnb	Seteuid(euid int) (err error)
 //sysnb	Setgid(gid int) (err error)
@@ -675,7 +676,6 @@
 // Kqueue_from_portset_np
 // Kqueue_portset
 // Getattrlist
-// Setattrlist
 // Getdirentriesattr
 // Searchfs
 // Delete
diff --git a/unix/types_darwin.go b/unix/types_darwin.go
index bfffc62..0e8ebe5 100644
--- a/unix/types_darwin.go
+++ b/unix/types_darwin.go
@@ -140,6 +140,8 @@
 
 type Dirent C.struct_dirent
 
+type Attrlist C.struct_attrlist
+
 // File system limits
 
 const (
diff --git a/unix/zerrors_darwin_amd64.go b/unix/zerrors_darwin_amd64.go
index 476a1c7..1430076 100644
--- a/unix/zerrors_darwin_amd64.go
+++ b/unix/zerrors_darwin_amd64.go
@@ -1270,6 +1270,16 @@
 	SEEK_END                                = 0x2
 	SEEK_HOLE                               = 0x3
 	SEEK_SET                                = 0x0
+	SF_APPEND                               = 0x40000
+	SF_ARCHIVED                             = 0x10000
+	SF_DATALESS                             = 0x40000000
+	SF_FIRMLINK                             = 0x800000
+	SF_IMMUTABLE                            = 0x20000
+	SF_NOUNLINK                             = 0x100000
+	SF_RESTRICTED                           = 0x80000
+	SF_SETTABLE                             = 0x3fff0000
+	SF_SUPPORTED                            = 0x9f0000
+	SF_SYNTHETIC                            = 0xc0000000
 	SHUT_RD                                 = 0x0
 	SHUT_RDWR                               = 0x2
 	SHUT_WR                                 = 0x1
@@ -1543,6 +1553,15 @@
 	TIOCTIMESTAMP                           = 0x40107459
 	TIOCUCNTL                               = 0x80047466
 	TOSTOP                                  = 0x400000
+	UF_APPEND                               = 0x4
+	UF_COMPRESSED                           = 0x20
+	UF_DATAVAULT                            = 0x80
+	UF_HIDDEN                               = 0x8000
+	UF_IMMUTABLE                            = 0x2
+	UF_NODUMP                               = 0x1
+	UF_OPAQUE                               = 0x8
+	UF_SETTABLE                             = 0xffff
+	UF_TRACKED                              = 0x40
 	VDISCARD                                = 0xf
 	VDSUSP                                  = 0xb
 	VEOF                                    = 0x0
diff --git a/unix/zerrors_darwin_arm64.go b/unix/zerrors_darwin_arm64.go
index e36f517..ab044a7 100644
--- a/unix/zerrors_darwin_arm64.go
+++ b/unix/zerrors_darwin_arm64.go
@@ -1270,6 +1270,16 @@
 	SEEK_END                                = 0x2
 	SEEK_HOLE                               = 0x3
 	SEEK_SET                                = 0x0
+	SF_APPEND                               = 0x40000
+	SF_ARCHIVED                             = 0x10000
+	SF_DATALESS                             = 0x40000000
+	SF_FIRMLINK                             = 0x800000
+	SF_IMMUTABLE                            = 0x20000
+	SF_NOUNLINK                             = 0x100000
+	SF_RESTRICTED                           = 0x80000
+	SF_SETTABLE                             = 0x3fff0000
+	SF_SUPPORTED                            = 0x9f0000
+	SF_SYNTHETIC                            = 0xc0000000
 	SHUT_RD                                 = 0x0
 	SHUT_RDWR                               = 0x2
 	SHUT_WR                                 = 0x1
@@ -1543,6 +1553,15 @@
 	TIOCTIMESTAMP                           = 0x40107459
 	TIOCUCNTL                               = 0x80047466
 	TOSTOP                                  = 0x400000
+	UF_APPEND                               = 0x4
+	UF_COMPRESSED                           = 0x20
+	UF_DATAVAULT                            = 0x80
+	UF_HIDDEN                               = 0x8000
+	UF_IMMUTABLE                            = 0x2
+	UF_NODUMP                               = 0x1
+	UF_OPAQUE                               = 0x8
+	UF_SETTABLE                             = 0xffff
+	UF_TRACKED                              = 0x40
 	VDISCARD                                = 0xf
 	VDSUSP                                  = 0xb
 	VEOF                                    = 0x0
diff --git a/unix/zsyscall_darwin_amd64.go b/unix/zsyscall_darwin_amd64.go
index a5e3743..4037ccf 100644
--- a/unix/zsyscall_darwin_amd64.go
+++ b/unix/zsyscall_darwin_amd64.go
@@ -1992,6 +1992,31 @@
 
 // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
 
+func Setattrlist(path string, attrlist *Attrlist, attrBuf []byte, options int) (err error) {
+	var _p0 *byte
+	_p0, err = BytePtrFromString(path)
+	if err != nil {
+		return
+	}
+	var _p1 unsafe.Pointer
+	if len(attrBuf) > 0 {
+		_p1 = unsafe.Pointer(&attrBuf[0])
+	} else {
+		_p1 = unsafe.Pointer(&_zero)
+	}
+	_, _, e1 := syscall_syscall6(libc_setattrlist_trampoline_addr, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(attrlist)), uintptr(_p1), uintptr(len(attrBuf)), uintptr(options), 0)
+	if e1 != 0 {
+		err = errnoErr(e1)
+	}
+	return
+}
+
+var libc_setattrlist_trampoline_addr uintptr
+
+//go:cgo_import_dynamic libc_setattrlist setattrlist "/usr/lib/libSystem.B.dylib"
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
 func Setegid(egid int) (err error) {
 	_, _, e1 := syscall_syscall(libc_setegid_trampoline_addr, uintptr(egid), 0, 0)
 	if e1 != 0 {
diff --git a/unix/zsyscall_darwin_amd64.s b/unix/zsyscall_darwin_amd64.s
index afbdd7f..4baaed0 100644
--- a/unix/zsyscall_darwin_amd64.s
+++ b/unix/zsyscall_darwin_amd64.s
@@ -705,6 +705,11 @@
 GLOBL	·libc_select_trampoline_addr(SB), RODATA, $8
 DATA	·libc_select_trampoline_addr(SB)/8, $libc_select_trampoline<>(SB)
 
+TEXT libc_setattrlist_trampoline<>(SB),NOSPLIT,$0-0
+	JMP	libc_setattrlist(SB)
+GLOBL	·libc_setattrlist_trampoline_addr(SB), RODATA, $8
+DATA	·libc_setattrlist_trampoline_addr(SB)/8, $libc_setattrlist_trampoline<>(SB)
+
 TEXT libc_setegid_trampoline<>(SB),NOSPLIT,$0-0
 	JMP	libc_setegid(SB)
 
diff --git a/unix/zsyscall_darwin_arm64.go b/unix/zsyscall_darwin_arm64.go
index e94b6ae..51d6f3f 100644
--- a/unix/zsyscall_darwin_arm64.go
+++ b/unix/zsyscall_darwin_arm64.go
@@ -1992,6 +1992,31 @@
 
 // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
 
+func Setattrlist(path string, attrlist *Attrlist, attrBuf []byte, options int) (err error) {
+	var _p0 *byte
+	_p0, err = BytePtrFromString(path)
+	if err != nil {
+		return
+	}
+	var _p1 unsafe.Pointer
+	if len(attrBuf) > 0 {
+		_p1 = unsafe.Pointer(&attrBuf[0])
+	} else {
+		_p1 = unsafe.Pointer(&_zero)
+	}
+	_, _, e1 := syscall_syscall6(libc_setattrlist_trampoline_addr, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(attrlist)), uintptr(_p1), uintptr(len(attrBuf)), uintptr(options), 0)
+	if e1 != 0 {
+		err = errnoErr(e1)
+	}
+	return
+}
+
+var libc_setattrlist_trampoline_addr uintptr
+
+//go:cgo_import_dynamic libc_setattrlist setattrlist "/usr/lib/libSystem.B.dylib"
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
 func Setegid(egid int) (err error) {
 	_, _, e1 := syscall_syscall(libc_setegid_trampoline_addr, uintptr(egid), 0, 0)
 	if e1 != 0 {
diff --git a/unix/zsyscall_darwin_arm64.s b/unix/zsyscall_darwin_arm64.s
index 0d177a0..c3b82c0 100644
--- a/unix/zsyscall_darwin_arm64.s
+++ b/unix/zsyscall_darwin_arm64.s
@@ -705,6 +705,11 @@
 GLOBL	·libc_select_trampoline_addr(SB), RODATA, $8
 DATA	·libc_select_trampoline_addr(SB)/8, $libc_select_trampoline<>(SB)
 
+TEXT libc_setattrlist_trampoline<>(SB),NOSPLIT,$0-0
+	JMP	libc_setattrlist(SB)
+GLOBL	·libc_setattrlist_trampoline_addr(SB), RODATA, $8
+DATA	·libc_setattrlist_trampoline_addr(SB)/8, $libc_setattrlist_trampoline<>(SB)
+
 TEXT libc_setegid_trampoline<>(SB),NOSPLIT,$0-0
 	JMP	libc_setegid(SB)
 
diff --git a/unix/ztypes_darwin_amd64.go b/unix/ztypes_darwin_amd64.go
index 06cb446..690cefc 100644
--- a/unix/ztypes_darwin_amd64.go
+++ b/unix/ztypes_darwin_amd64.go
@@ -151,6 +151,16 @@
 	_       [3]byte
 }
 
+type Attrlist struct {
+	Bitmapcount uint16
+	Reserved    uint16
+	Commonattr  uint32
+	Volattr     uint32
+	Dirattr     uint32
+	Fileattr    uint32
+	Forkattr    uint32
+}
+
 const (
 	PathMax = 0x400
 )
diff --git a/unix/ztypes_darwin_arm64.go b/unix/ztypes_darwin_arm64.go
index 3b9dd1d..5bffc10 100644
--- a/unix/ztypes_darwin_arm64.go
+++ b/unix/ztypes_darwin_arm64.go
@@ -151,6 +151,16 @@
 	_       [3]byte
 }
 
+type Attrlist struct {
+	Bitmapcount uint16
+	Reserved    uint16
+	Commonattr  uint32
+	Volattr     uint32
+	Dirattr     uint32
+	Fileattr    uint32
+	Forkattr    uint32
+}
+
 const (
 	PathMax = 0x400
 )