]> Cypherpunks repositories - gostls13.git/commitdiff
syscall: use setattrlist for UtimesNano on Darwin for ns resolution
authorEvan Jones <ej@evanjones.ca>
Wed, 1 Nov 2017 16:44:14 +0000 (12:44 -0400)
committerIan Lance Taylor <iant@golang.org>
Wed, 1 Nov 2017 21:54:42 +0000 (21:54 +0000)
Mac OS X 10.13 introduced APFS which stores nanosecond resolution
timestamps. The implementation of os.Stat already returns full
resolution timestamps, but os.Chtimes only sets timestamps with
microsecond resolution.

Fix this by using setattrlist on Darwin, which takes a struct timeval
with nanosecond resolution. This is what Mac OS X 10.13 appears uses
to implement utimensat, according to dtruss.

Fixes #22528

Change-Id: I397dabef6b2b73a081382999aa4c4405ab8c6015
Reviewed-on: https://go-review.googlesource.com/74952
Run-TryBot: Ian Lance Taylor <iant@golang.org>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Ian Lance Taylor <iant@golang.org>
src/syscall/syscall_bsd.go
src/syscall/syscall_darwin.go
src/syscall/syscall_dragonfly.go
src/syscall/syscall_freebsd.go
src/syscall/syscall_netbsd.go
src/syscall/syscall_openbsd.go

index a968562b73604a591ff4b4b9de4f00c6bc4e5d8a..d141a7de9d41b712ccdc179e84735264dcbfa022 100644 (file)
@@ -510,7 +510,12 @@ func UtimesNano(path string, ts []Timespec) error {
        if len(ts) != 2 {
                return EINVAL
        }
-       err := utimensat(_AT_FDCWD, path, (*[2]Timespec)(unsafe.Pointer(&ts[0])), 0)
+       // Darwin setattrlist can set nanosecond timestamps
+       err := setattrlistTimes(path, ts)
+       if err != ENOSYS {
+               return err
+       }
+       err = utimensat(_AT_FDCWD, path, (*[2]Timespec)(unsafe.Pointer(&ts[0])), 0)
        if err != ENOSYS {
                return err
        }
index 9845effb2695d0364b40d801be1d22d5f74d4cba..cf21ec46886709b18f77324e2a92186e2ea4a9ee 100644 (file)
@@ -93,6 +93,8 @@ func PtraceDetach(pid int) (err error) { return ptrace(PT_DETACH, pid, 0, 0) }
 
 const (
        attrBitMapCount = 5
+       attrCmnModtime  = 0x00000400
+       attrCmnAcctime  = 0x00001000
        attrCmnFullpath = 0x08000000
 )
 
@@ -186,6 +188,34 @@ func Getfsstat(buf []Statfs_t, flags int) (n int, err error) {
        return
 }
 
+func setattrlistTimes(path string, times []Timespec) error {
+       _p0, err := BytePtrFromString(path)
+       if err != nil {
+               return err
+       }
+
+       var attrList attrList
+       attrList.bitmapCount = attrBitMapCount
+       attrList.CommonAttr = attrCmnModtime | attrCmnAcctime
+
+       // order is mtime, atime: the opposite of Chtimes
+       attributes := [2]Timespec{times[1], times[0]}
+       const options = 0
+       _, _, e1 := Syscall6(
+               SYS_SETATTRLIST,
+               uintptr(unsafe.Pointer(_p0)),
+               uintptr(unsafe.Pointer(&attrList)),
+               uintptr(unsafe.Pointer(&attributes)),
+               uintptr(unsafe.Sizeof(attributes)),
+               uintptr(options),
+               0,
+       )
+       if e1 != 0 {
+               return e1
+       }
+       return nil
+}
+
 func utimensat(dirfd int, path string, times *[2]Timespec, flag int) error {
        // Darwin doesn't support SYS_UTIMENSAT
        return ENOSYS
index 766d005bd382271fe042a72430b233a036f44bdb..fead9d9b48207f3df527da7689adc94c6b7ff983 100644 (file)
@@ -125,6 +125,11 @@ func Getfsstat(buf []Statfs_t, flags int) (n int, err error) {
        return
 }
 
+func setattrlistTimes(path string, times []Timespec) error {
+       // used on Darwin for UtimesNano
+       return ENOSYS
+}
+
 /*
  * Exposed directly
  */
index 85790b31d209eb50b65cc57cd70486dca219ac20..2c7533c157c9d85de6499968f4d510c309418305 100644 (file)
@@ -134,6 +134,11 @@ func Getfsstat(buf []Statfs_t, flags int) (n int, err error) {
        return
 }
 
+func setattrlistTimes(path string, times []Timespec) error {
+       // used on Darwin for UtimesNano
+       return ENOSYS
+}
+
 /*
  * Exposed directly
  */
index 21af0fa0de6fd2d7b7fbbd22a827ec9ef420aa45..c645b139b1cdd43c856f2137986a42cd14840509 100644 (file)
@@ -121,6 +121,11 @@ func sendfile(outfd int, infd int, offset *int64, count int) (written int, err e
        return -1, ENOSYS
 }
 
+func setattrlistTimes(path string, times []Timespec) error {
+       // used on Darwin for UtimesNano
+       return ENOSYS
+}
+
 /*
  * Exposed directly
  */
index 7ac8b2d0408bc8ffa4eaf83d0696afe52ae7b1a8..a43d88bf7a827a3cce90bee53f47a0b03f29a665 100644 (file)
@@ -99,6 +99,11 @@ func Getfsstat(buf []Statfs_t, flags int) (n int, err error) {
        return
 }
 
+func setattrlistTimes(path string, times []Timespec) error {
+       // used on Darwin for UtimesNano
+       return ENOSYS
+}
+
 /*
  * Exposed directly
  */