unix: add utimensat libc wrapper on darwin

Direct syscalls are no longer supported on darwin (CL 250437), so
utimensat can be implemented as a wrapper around the libc function.
The utimensat function was added in macOS 10.13 and Go 1.17 dropped
support for macOS 10.12.

This also allows to drop the fallback to setattrlistTimes which was
used to set timestamps with nanosecond resolution before utimensat could
be used, see golang/go#22528 and CL 74952.

Change-Id: I206291277e6f7200ca7a659e29075968647779a6
Reviewed-on: https://go-review.googlesource.com/c/sys/+/251737
Trust: Tobias Klauser <tobias.klauser@gmail.com>
Reviewed-by: Keith Randall <khr@golang.org>
Run-TryBot: Tobias Klauser <tobias.klauser@gmail.com>
TryBot-Result: Gopher Robot <gobot@golang.org>
Reviewed-by: Matt Layher <mdlayher@gmail.com>
diff --git a/unix/darwin_amd64_test.go b/unix/darwin_amd64_test.go
index 71d0ef6..3ecb05f 100644
--- a/unix/darwin_amd64_test.go
+++ b/unix/darwin_amd64_test.go
@@ -118,7 +118,6 @@
 	{"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},
@@ -154,6 +153,7 @@
 	{"unlink", libc_unlink_trampoline_addr},
 	{"unlinkat", libc_unlinkat_trampoline_addr},
 	{"unmount", libc_unmount_trampoline_addr},
+	{"utimensat", libc_utimensat_trampoline_addr},
 	{"utimes", libc_utimes_trampoline_addr},
 	{"wait4", libc_wait4_trampoline_addr},
 	{"write", libc_write_trampoline_addr},
diff --git a/unix/darwin_arm64_test.go b/unix/darwin_arm64_test.go
index 52116f0..1a13994 100644
--- a/unix/darwin_arm64_test.go
+++ b/unix/darwin_arm64_test.go
@@ -118,7 +118,6 @@
 	{"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},
@@ -154,6 +153,7 @@
 	{"unlink", libc_unlink_trampoline_addr},
 	{"unlinkat", libc_unlinkat_trampoline_addr},
 	{"unmount", libc_unmount_trampoline_addr},
+	{"utimensat", libc_utimensat_trampoline_addr},
 	{"utimes", libc_utimes_trampoline_addr},
 	{"wait4", libc_wait4_trampoline_addr},
 	{"write", libc_write_trampoline_addr},
diff --git a/unix/syscall_bsd.go b/unix/syscall_bsd.go
index a801b1b..9c87c5f 100644
--- a/unix/syscall_bsd.go
+++ b/unix/syscall_bsd.go
@@ -553,12 +553,7 @@
 	if len(ts) != 2 {
 		return EINVAL
 	}
-	// Darwin setattrlist can set nanosecond timestamps
-	err := setattrlistTimes(path, ts, 0)
-	if err != ENOSYS {
-		return err
-	}
-	err = utimensat(AT_FDCWD, path, (*[2]Timespec)(unsafe.Pointer(&ts[0])), 0)
+	err := utimensat(AT_FDCWD, path, (*[2]Timespec)(unsafe.Pointer(&ts[0])), 0)
 	if err != ENOSYS {
 		return err
 	}
@@ -578,10 +573,6 @@
 	if len(ts) != 2 {
 		return EINVAL
 	}
-	err := setattrlistTimes(path, ts, flags)
-	if err != ENOSYS {
-		return err
-	}
 	return utimensat(dirfd, path, (*[2]Timespec)(unsafe.Pointer(&ts[0])), flags)
 }
 
diff --git a/unix/syscall_darwin.go b/unix/syscall_darwin.go
index ca2ae35..09a25c6 100644
--- a/unix/syscall_darwin.go
+++ b/unix/syscall_darwin.go
@@ -141,16 +141,6 @@
 func PtraceAttach(pid int) (err error) { return ptrace(PT_ATTACH, pid, 0, 0) }
 func PtraceDetach(pid int) (err error) { return ptrace(PT_DETACH, pid, 0, 0) }
 
-type attrList struct {
-	bitmapCount uint16
-	_           uint16
-	CommonAttr  uint32
-	VolAttr     uint32
-	DirAttr     uint32
-	FileAttr    uint32
-	Forkattr    uint32
-}
-
 //sysnb	pipe(p *[2]int32) (err error)
 
 func Pipe(p []int) (err error) {
@@ -282,36 +272,7 @@
 	return flistxattr(fd, xattrPointer(dest), len(dest), 0)
 }
 
-func setattrlistTimes(path string, times []Timespec, flags int) error {
-	_p0, err := BytePtrFromString(path)
-	if err != nil {
-		return err
-	}
-
-	var attrList attrList
-	attrList.bitmapCount = ATTR_BIT_MAP_COUNT
-	attrList.CommonAttr = ATTR_CMN_MODTIME | ATTR_CMN_ACCTIME
-
-	// order is mtime, atime: the opposite of Chtimes
-	attributes := [2]Timespec{times[1], times[0]}
-	options := 0
-	if flags&AT_SYMLINK_NOFOLLOW != 0 {
-		options |= FSOPT_NOFOLLOW
-	}
-	return setattrlist(
-		_p0,
-		unsafe.Pointer(&attrList),
-		unsafe.Pointer(&attributes),
-		unsafe.Sizeof(attributes),
-		options)
-}
-
-//sys	setattrlist(path *byte, list unsafe.Pointer, buf unsafe.Pointer, size uintptr, options int) (err error)
-
-func utimensat(dirfd int, path string, times *[2]Timespec, flags int) error {
-	// Darwin doesn't support SYS_UTIMENSAT
-	return ENOSYS
-}
+//sys	utimensat(dirfd int, path string, times *[2]Timespec, flags int) (err error)
 
 /*
  * Wrapped
diff --git a/unix/syscall_dragonfly.go b/unix/syscall_dragonfly.go
index 36c268b..c61e274 100644
--- a/unix/syscall_dragonfly.go
+++ b/unix/syscall_dragonfly.go
@@ -169,11 +169,6 @@
 	return
 }
 
-func setattrlistTimes(path string, times []Timespec, flags int) error {
-	// used on Darwin for UtimesNano
-	return ENOSYS
-}
-
 //sys	ioctl(fd int, req uint, arg uintptr) (err error)
 
 //sys	sysctl(mib []_C_int, old *byte, oldlen *uintptr, new *byte, newlen uintptr) (err error) = SYS___SYSCTL
diff --git a/unix/syscall_freebsd.go b/unix/syscall_freebsd.go
index ac3db01..6f6c510 100644
--- a/unix/syscall_freebsd.go
+++ b/unix/syscall_freebsd.go
@@ -194,11 +194,6 @@
 	return
 }
 
-func setattrlistTimes(path string, times []Timespec, flags int) error {
-	// used on Darwin for UtimesNano
-	return ENOSYS
-}
-
 //sys	ioctl(fd int, req uint, arg uintptr) (err error)
 
 //sys	sysctl(mib []_C_int, old *byte, oldlen *uintptr, new *byte, newlen uintptr) (err error) = SYS___SYSCTL
diff --git a/unix/syscall_netbsd.go b/unix/syscall_netbsd.go
index d9946e5..666f0a1 100644
--- a/unix/syscall_netbsd.go
+++ b/unix/syscall_netbsd.go
@@ -163,11 +163,6 @@
 	return -1, ENOSYS
 }
 
-func setattrlistTimes(path string, times []Timespec, flags int) error {
-	// used on Darwin for UtimesNano
-	return ENOSYS
-}
-
 //sys	ioctl(fd int, req uint, arg uintptr) (err error)
 
 //sys	sysctl(mib []_C_int, old *byte, oldlen *uintptr, new *byte, newlen uintptr) (err error) = SYS___SYSCTL
diff --git a/unix/syscall_openbsd.go b/unix/syscall_openbsd.go
index 0d94765..15d637d 100644
--- a/unix/syscall_openbsd.go
+++ b/unix/syscall_openbsd.go
@@ -149,11 +149,6 @@
 	return
 }
 
-func setattrlistTimes(path string, times []Timespec, flags int) error {
-	// used on Darwin for UtimesNano
-	return ENOSYS
-}
-
 //sys	ioctl(fd int, req uint, arg uintptr) (err error)
 
 //sys	sysctl(mib []_C_int, old *byte, oldlen *uintptr, new *byte, newlen uintptr) (err error) = SYS___SYSCTL
diff --git a/unix/zsyscall_darwin_amd64.go b/unix/zsyscall_darwin_amd64.go
index fbfce02..8793765 100644
--- a/unix/zsyscall_darwin_amd64.go
+++ b/unix/zsyscall_darwin_amd64.go
@@ -643,17 +643,22 @@
 
 // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
 
-func setattrlist(path *byte, list unsafe.Pointer, buf unsafe.Pointer, size uintptr, options int) (err error) {
-	_, _, e1 := syscall_syscall6(libc_setattrlist_trampoline_addr, uintptr(unsafe.Pointer(path)), uintptr(list), uintptr(buf), uintptr(size), uintptr(options), 0)
+func utimensat(dirfd int, path string, times *[2]Timespec, flags int) (err error) {
+	var _p0 *byte
+	_p0, err = BytePtrFromString(path)
+	if err != nil {
+		return
+	}
+	_, _, e1 := syscall_syscall6(libc_utimensat_trampoline_addr, uintptr(dirfd), uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(times)), uintptr(flags), 0, 0)
 	if e1 != 0 {
 		err = errnoErr(e1)
 	}
 	return
 }
 
-var libc_setattrlist_trampoline_addr uintptr
+var libc_utimensat_trampoline_addr uintptr
 
-//go:cgo_import_dynamic libc_setattrlist setattrlist "/usr/lib/libSystem.B.dylib"
+//go:cgo_import_dynamic libc_utimensat utimensat "/usr/lib/libSystem.B.dylib"
 
 // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
 
diff --git a/unix/zsyscall_darwin_amd64.s b/unix/zsyscall_darwin_amd64.s
index eac6ca8..8da90cf 100644
--- a/unix/zsyscall_darwin_amd64.s
+++ b/unix/zsyscall_darwin_amd64.s
@@ -228,11 +228,11 @@
 GLOBL	·libc_flistxattr_trampoline_addr(SB), RODATA, $8
 DATA	·libc_flistxattr_trampoline_addr(SB)/8, $libc_flistxattr_trampoline<>(SB)
 
-TEXT libc_setattrlist_trampoline<>(SB),NOSPLIT,$0-0
-	JMP	libc_setattrlist(SB)
+TEXT libc_utimensat_trampoline<>(SB),NOSPLIT,$0-0
+	JMP	libc_utimensat(SB)
 
-GLOBL	·libc_setattrlist_trampoline_addr(SB), RODATA, $8
-DATA	·libc_setattrlist_trampoline_addr(SB)/8, $libc_setattrlist_trampoline<>(SB)
+GLOBL	·libc_utimensat_trampoline_addr(SB), RODATA, $8
+DATA	·libc_utimensat_trampoline_addr(SB)/8, $libc_utimensat_trampoline<>(SB)
 
 TEXT libc_fcntl_trampoline<>(SB),NOSPLIT,$0-0
 	JMP	libc_fcntl(SB)
diff --git a/unix/zsyscall_darwin_arm64.go b/unix/zsyscall_darwin_arm64.go
index 49d2225..f47eedd 100644
--- a/unix/zsyscall_darwin_arm64.go
+++ b/unix/zsyscall_darwin_arm64.go
@@ -643,17 +643,22 @@
 
 // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
 
-func setattrlist(path *byte, list unsafe.Pointer, buf unsafe.Pointer, size uintptr, options int) (err error) {
-	_, _, e1 := syscall_syscall6(libc_setattrlist_trampoline_addr, uintptr(unsafe.Pointer(path)), uintptr(list), uintptr(buf), uintptr(size), uintptr(options), 0)
+func utimensat(dirfd int, path string, times *[2]Timespec, flags int) (err error) {
+	var _p0 *byte
+	_p0, err = BytePtrFromString(path)
+	if err != nil {
+		return
+	}
+	_, _, e1 := syscall_syscall6(libc_utimensat_trampoline_addr, uintptr(dirfd), uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(times)), uintptr(flags), 0, 0)
 	if e1 != 0 {
 		err = errnoErr(e1)
 	}
 	return
 }
 
-var libc_setattrlist_trampoline_addr uintptr
+var libc_utimensat_trampoline_addr uintptr
 
-//go:cgo_import_dynamic libc_setattrlist setattrlist "/usr/lib/libSystem.B.dylib"
+//go:cgo_import_dynamic libc_utimensat utimensat "/usr/lib/libSystem.B.dylib"
 
 // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
 
diff --git a/unix/zsyscall_darwin_arm64.s b/unix/zsyscall_darwin_arm64.s
index 4ebcf21..4d26f7d 100644
--- a/unix/zsyscall_darwin_arm64.s
+++ b/unix/zsyscall_darwin_arm64.s
@@ -228,11 +228,11 @@
 GLOBL	·libc_flistxattr_trampoline_addr(SB), RODATA, $8
 DATA	·libc_flistxattr_trampoline_addr(SB)/8, $libc_flistxattr_trampoline<>(SB)
 
-TEXT libc_setattrlist_trampoline<>(SB),NOSPLIT,$0-0
-	JMP	libc_setattrlist(SB)
+TEXT libc_utimensat_trampoline<>(SB),NOSPLIT,$0-0
+	JMP	libc_utimensat(SB)
 
-GLOBL	·libc_setattrlist_trampoline_addr(SB), RODATA, $8
-DATA	·libc_setattrlist_trampoline_addr(SB)/8, $libc_setattrlist_trampoline<>(SB)
+GLOBL	·libc_utimensat_trampoline_addr(SB), RODATA, $8
+DATA	·libc_utimensat_trampoline_addr(SB)/8, $libc_utimensat_trampoline<>(SB)
 
 TEXT libc_fcntl_trampoline<>(SB),NOSPLIT,$0-0
 	JMP	libc_fcntl(SB)