From: Evan Jones Date: Wed, 1 Nov 2017 16:44:14 +0000 (-0400) Subject: syscall: use setattrlist for UtimesNano on Darwin for ns resolution X-Git-Tag: go1.10beta1~461 X-Git-Url: http://www.git.cypherpunks.su/?a=commitdiff_plain;h=eb2b0ed5b59cfb340de0118235bfda60e0de4a8d;p=gostls13.git syscall: use setattrlist for UtimesNano on Darwin for ns resolution 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 TryBot-Result: Gobot Gobot Reviewed-by: Ian Lance Taylor --- diff --git a/src/syscall/syscall_bsd.go b/src/syscall/syscall_bsd.go index a968562b73..d141a7de9d 100644 --- a/src/syscall/syscall_bsd.go +++ b/src/syscall/syscall_bsd.go @@ -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 } diff --git a/src/syscall/syscall_darwin.go b/src/syscall/syscall_darwin.go index 9845effb26..cf21ec4688 100644 --- a/src/syscall/syscall_darwin.go +++ b/src/syscall/syscall_darwin.go @@ -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 diff --git a/src/syscall/syscall_dragonfly.go b/src/syscall/syscall_dragonfly.go index 766d005bd3..fead9d9b48 100644 --- a/src/syscall/syscall_dragonfly.go +++ b/src/syscall/syscall_dragonfly.go @@ -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 */ diff --git a/src/syscall/syscall_freebsd.go b/src/syscall/syscall_freebsd.go index 85790b31d2..2c7533c157 100644 --- a/src/syscall/syscall_freebsd.go +++ b/src/syscall/syscall_freebsd.go @@ -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 */ diff --git a/src/syscall/syscall_netbsd.go b/src/syscall/syscall_netbsd.go index 21af0fa0de..c645b139b1 100644 --- a/src/syscall/syscall_netbsd.go +++ b/src/syscall/syscall_netbsd.go @@ -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 */ diff --git a/src/syscall/syscall_openbsd.go b/src/syscall/syscall_openbsd.go index 7ac8b2d040..a43d88bf7a 100644 --- a/src/syscall/syscall_openbsd.go +++ b/src/syscall/syscall_openbsd.go @@ -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 */