New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
syscall: UtimesNano does not use nanosecond system call on BSD, Solaris #16480
Comments
I don't think there's anything Solaris-specific here. The os package does the same thing on all POSIX systems (file_posix.go): func Chtimes(name string, atime time.Time, mtime time.Time) error {
var utimes [2]syscall.Timespec
utimes[0] = syscall.NsecToTimespec(atime.UnixNano())
utimes[1] = syscall.NsecToTimespec(mtime.UnixNano())
if e := syscall.UtimesNano(name, utimes[0:]); e != nil {
return &PathError{"chtimes", name, e}
}
return nil
} ... where syscall.UtimesNano always converts to microseconds. Many operating systems have The os.Chtimes documentation is a little misleading:
... since it's not really the filesystem truncating things. This seems fixable. |
Currently only the syscall Linux-es' packages use utimensat in syscall.UtimesNano so that Emmanuels-MBP-2:syscall emmanuelodeke$ go version
go version devel +5df7f52 Sun Sep 25 23:42:59 2016 +0000 darwin/amd64
Emmanuels-MBP-2:syscall emmanuelodeke$ grep -Rn 'func utimensat' *
zsyscall_linux_386.go:128:func utimensat(dirfd int, path string, times *[2]Timespec) (err error) {
zsyscall_linux_amd64.go:128:func utimensat(dirfd int, path string, times *[2]Timespec) (err error) {
zsyscall_linux_arm.go:128:func utimensat(dirfd int, path string, times *[2]Timespec) (err error) {
zsyscall_linux_arm64.go:128:func utimensat(dirfd int, path string, times *[2]Timespec) (err error) {
zsyscall_linux_mips64.go:126:func utimensat(dirfd int, path string, times *[2]Timespec) (err error) {
zsyscall_linux_mips64le.go:126:func utimensat(dirfd int, path string, times *[2]Timespec) (err error) {
zsyscall_linux_ppc64.go:128:func utimensat(dirfd int, path string, times *[2]Timespec) (err error) {
zsyscall_linux_ppc64le.go:128:func utimensat(dirfd int, path string, times *[2]Timespec) (err error) {
zsyscall_linux_s390x.go:126:func utimensat(dirfd int, path string, times *[2]Timespec) (err error) { Unfortunately doesn't seem like darwin doesn't support utimensat and there is a comment in the syscall code about it However, it seems like we can do this for Solaris and perhaps the other BSDs. |
I think the package docs for os.Chtimes are correct. For example you can use a nanosecond-specific system call but if you're writing to FAT32, it's still going to get truncated to 2-second granularity. The expectation is that the implementation of syscall.UtimesNano uses the most precise system call available. That's true on Linux: it tries utimensat and falls back to utimes when utimensat is not available. It appears to be true on Windows too: it uses SetFileTime which works at 100ns granularity, but that's true of everything on Windows. On BSD systems, there is a TODO in syscall_bsd.go to use a higher precision call. On Solaris, there is no TODO but still the implementation uses plain syscall.Utimes. If Solaris has a more precise call, the Solaris implementation of syscall.UtimesNano should use it. |
@odeke-em utimensat has been supported since OpenBSD 5.0 (Nov 2011), NetBSD 6.0 (Oct 2012), and FreeBSD 11.0 (Oct 2016). It looks like it's still unsupported on Darwin though. |
Actually ama let someone who is an expert on syscalls and BSD handle this, |
All actively supported versions of Solaris from Solaris 10 onwards support utimensat since roughly 2010. |
You can see that I added support (changed UtimesNano) to use this in the sys/unix package as part of the changes for #8609: |
FreeBSD actually first added support for utimensat in FreeBSD 10 as part of this review in January 2015: https://reviews.freebsd.org/D1426 http://fxr.watson.org/fxr/source/sys/stat.h?v=FREEBSD10#L331 |
Hello there @binarycrusader, the Go1.9 tree is open. Any interest/bandwidth for getting this in? Thanks. |
The same problem also exists in x/sys/unix. I'll have a look at it and send CLs for both. |
All the BSDs and Solaris support the utimensat syscall, but Darwin doesn't. Account for that by adding the //sys lines not to syscall_bsd.go but the individual OS's syscall_*.go files and implement utimensat on Darwin as just returning ENOSYS, such that UtimesNano will fall back to use utimes as it currently does unconditionally. This also adds the previously missing utimensat syscall number for FreeBSD and Dragonfly. Fixes golang#16480 Change-Id: I367454c6168eb1f7150b988fa16cf02abff42f34
Submitted https://golang.org/cl/55130 attempting to fix this issue in the |
Change https://golang.org/cl/55130 mentions this issue: |
Change https://golang.org/cl/55141 mentions this issue: |
golang.org/cl/55130 added utimensat for Solaris but didn't use it in UtimesNano (despite indicating otherwise in the commit message). Fix this by also using utimensat for UtimesNano on Solaris. Because all versions of Solaris suppported by Go support utimensat, there is no need for the fallback logic and utimensat can be called unconditionally. This issue was pointed out by Shawn Walker-Salas. Updates #16480 Change-Id: I114338113a6da3cfcb8bca950674bdc8f5a7a9e5 Reviewed-on: https://go-review.googlesource.com/55141 Run-TryBot: Ian Lance Taylor <iant@golang.org> Reviewed-by: Ian Lance Taylor <iant@golang.org>
ZFS on Solaris retains nanosecond precision file timestamps. These can be seen in the information returned by
os.Stat
. Howeveros.Chtimes
seems limited to setting microsecond precision. This means, among other things, that a file can't be copied with the timestamp fully retained.The text was updated successfully, but these errors were encountered: