unix: use setattrlist for UtimesNanoAt on Darwin

Use to setarrlist to implement UtimesNanoAt with nanosecond precision
(on Mac OS 10.13 with APFS). Translate AT_SYMLINK_NOFOLLOW to
FSOPT_NOFOLLOW correspondingly.

Change-Id: I1468a1f4eecb53b2280ff6329b1ec64e204701f1
Reviewed-on: https://go-review.googlesource.com/75650
Run-TryBot: Tobias Klauser <tobias.klauser@gmail.com>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Ian Lance Taylor <iant@golang.org>
diff --git a/unix/mkerrors.sh b/unix/mkerrors.sh
index c7a7473..4ddd4ff 100755
--- a/unix/mkerrors.sh
+++ b/unix/mkerrors.sh
@@ -426,6 +426,7 @@
 		$2 ~ /^UTIME_/ ||
 		$2 ~ /^XATTR_(CREATE|REPLACE)/ ||
 		$2 ~ /^ATTR_(BIT_MAP_COUNT|(CMN|VOL|FILE)_)/ ||
+		$2 ~ /^FSOPT_/ ||
 		$2 ~ /^WDIOC_/ ||
 		$2 !~ "WMESGLEN" &&
 		$2 ~ /^W[A-Z0-9]+$/ ||
diff --git a/unix/syscall_bsd.go b/unix/syscall_bsd.go
index 3906090..47b0598 100644
--- a/unix/syscall_bsd.go
+++ b/unix/syscall_bsd.go
@@ -571,7 +571,7 @@
 		return EINVAL
 	}
 	// Darwin setattrlist can set nanosecond timestamps
-	err := setattrlistTimes(path, ts)
+	err := setattrlistTimes(path, ts, 0)
 	if err != ENOSYS {
 		return err
 	}
@@ -595,6 +595,10 @@
 	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 edcab03..9a6783e 100644
--- a/unix/syscall_darwin.go
+++ b/unix/syscall_darwin.go
@@ -187,7 +187,7 @@
 	return
 }
 
-func setattrlistTimes(path string, times []Timespec) error {
+func setattrlistTimes(path string, times []Timespec, flags int) error {
 	_p0, err := BytePtrFromString(path)
 	if err != nil {
 		return err
@@ -199,8 +199,10 @@
 
 	// order is mtime, atime: the opposite of Chtimes
 	attributes := [2]Timespec{times[1], times[0]}
-
-	const options = 0
+	options := 0
+	if flags&AT_SYMLINK_NOFOLLOW != 0 {
+		options |= FSOPT_NOFOLLOW
+	}
 	_, _, e1 := Syscall6(
 		SYS_SETATTRLIST,
 		uintptr(unsafe.Pointer(_p0)),
diff --git a/unix/syscall_dragonfly.go b/unix/syscall_dragonfly.go
index 63ee371..25eeada 100644
--- a/unix/syscall_dragonfly.go
+++ b/unix/syscall_dragonfly.go
@@ -125,7 +125,7 @@
 	return
 }
 
-func setattrlistTimes(path string, times []Timespec) error {
+func setattrlistTimes(path string, times []Timespec, flags int) error {
 	// used on Darwin for UtimesNano
 	return ENOSYS
 }
diff --git a/unix/syscall_freebsd.go b/unix/syscall_freebsd.go
index 823d53a..a82ce12 100644
--- a/unix/syscall_freebsd.go
+++ b/unix/syscall_freebsd.go
@@ -120,7 +120,7 @@
 	return
 }
 
-func setattrlistTimes(path string, times []Timespec) error {
+func setattrlistTimes(path string, times []Timespec, flags int) error {
 	// used on Darwin for UtimesNano
 	return ENOSYS
 }
diff --git a/unix/syscall_netbsd.go b/unix/syscall_netbsd.go
index 3e28aa1..4455eff 100644
--- a/unix/syscall_netbsd.go
+++ b/unix/syscall_netbsd.go
@@ -124,7 +124,7 @@
 	return -1, ENOSYS
 }
 
-func setattrlistTimes(path string, times []Timespec) error {
+func setattrlistTimes(path string, times []Timespec, flags int) error {
 	// used on Darwin for UtimesNano
 	return ENOSYS
 }
diff --git a/unix/syscall_openbsd.go b/unix/syscall_openbsd.go
index fe05375..2158196 100644
--- a/unix/syscall_openbsd.go
+++ b/unix/syscall_openbsd.go
@@ -102,7 +102,7 @@
 	return
 }
 
-func setattrlistTimes(path string, times []Timespec) error {
+func setattrlistTimes(path string, times []Timespec, flags int) error {
 	// used on Darwin for UtimesNano
 	return ENOSYS
 }
diff --git a/unix/zerrors_darwin_386.go b/unix/zerrors_darwin_386.go
index b238a03..ac581f3 100644
--- a/unix/zerrors_darwin_386.go
+++ b/unix/zerrors_darwin_386.go
@@ -470,6 +470,11 @@
 	FF1                               = 0x4000
 	FFDLY                             = 0x4000
 	FLUSHO                            = 0x800000
+	FSOPT_ATTR_CMN_EXTENDED           = 0x20
+	FSOPT_NOFOLLOW                    = 0x1
+	FSOPT_NOINMEMUPDATE               = 0x2
+	FSOPT_PACK_INVAL_ATTRS            = 0x8
+	FSOPT_REPORT_FULLSIZE             = 0x4
 	F_ADDFILESIGS                     = 0x3d
 	F_ADDFILESIGS_FOR_DYLD_SIM        = 0x53
 	F_ADDFILESIGS_RETURN              = 0x61
diff --git a/unix/zerrors_darwin_amd64.go b/unix/zerrors_darwin_amd64.go
index f7e4e3a..2ba407a 100644
--- a/unix/zerrors_darwin_amd64.go
+++ b/unix/zerrors_darwin_amd64.go
@@ -470,6 +470,11 @@
 	FF1                               = 0x4000
 	FFDLY                             = 0x4000
 	FLUSHO                            = 0x800000
+	FSOPT_ATTR_CMN_EXTENDED           = 0x20
+	FSOPT_NOFOLLOW                    = 0x1
+	FSOPT_NOINMEMUPDATE               = 0x2
+	FSOPT_PACK_INVAL_ATTRS            = 0x8
+	FSOPT_REPORT_FULLSIZE             = 0x4
 	F_ADDFILESIGS                     = 0x3d
 	F_ADDFILESIGS_FOR_DYLD_SIM        = 0x53
 	F_ADDFILESIGS_RETURN              = 0x61
diff --git a/unix/zerrors_darwin_arm.go b/unix/zerrors_darwin_arm.go
index b5c7999..f4a2fde 100644
--- a/unix/zerrors_darwin_arm.go
+++ b/unix/zerrors_darwin_arm.go
@@ -470,6 +470,11 @@
 	FF1                               = 0x4000
 	FFDLY                             = 0x4000
 	FLUSHO                            = 0x800000
+	FSOPT_ATTR_CMN_EXTENDED           = 0x20
+	FSOPT_NOFOLLOW                    = 0x1
+	FSOPT_NOINMEMUPDATE               = 0x2
+	FSOPT_PACK_INVAL_ATTRS            = 0x8
+	FSOPT_REPORT_FULLSIZE             = 0x4
 	F_ADDFILESIGS                     = 0x3d
 	F_ADDFILESIGS_FOR_DYLD_SIM        = 0x53
 	F_ADDFILESIGS_RETURN              = 0x61
diff --git a/unix/zerrors_darwin_arm64.go b/unix/zerrors_darwin_arm64.go
index bb78e53..4c2e696 100644
--- a/unix/zerrors_darwin_arm64.go
+++ b/unix/zerrors_darwin_arm64.go
@@ -470,6 +470,11 @@
 	FF1                               = 0x4000
 	FFDLY                             = 0x4000
 	FLUSHO                            = 0x800000
+	FSOPT_ATTR_CMN_EXTENDED           = 0x20
+	FSOPT_NOFOLLOW                    = 0x1
+	FSOPT_NOINMEMUPDATE               = 0x2
+	FSOPT_PACK_INVAL_ATTRS            = 0x8
+	FSOPT_REPORT_FULLSIZE             = 0x4
 	F_ADDFILESIGS                     = 0x3d
 	F_ADDFILESIGS_FOR_DYLD_SIM        = 0x53
 	F_ADDFILESIGS_RETURN              = 0x61