Commit eb2b0ed5 authored by Evan Jones's avatar Evan Jones Committed by Ian Lance Taylor

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 <iant@golang.org>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: default avatarIan Lance Taylor <iant@golang.org>
parent 86b7721c
......@@ -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
}
......
......@@ -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
......
......@@ -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
*/
......
......@@ -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
*/
......
......@@ -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
*/
......
......@@ -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
*/
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment