From af5441dcd9033e81da43ab77887a7b5aac693ab6 Mon Sep 17 00:00:00 2001 From: Jakob Unterwurzacher Date: Tue, 9 Aug 2016 22:18:46 +0200 Subject: [PATCH] fusefrontend: use NsecToTimespec() for Utimens This fixes a build problem on 32-bit hosts: internal/fusefrontend/file.go:400: cannot use a.Unix() (type int64) as type int32 in assignment internal/fusefrontend/file.go:406: cannot use m.Unix() (type int64) as type int32 in assignment It also enables full nanosecond timestamps for dates after 1970. --- internal/fusefrontend/file.go | 30 ++++++++++++++++++------------ internal/fusefrontend/fs.go | 9 ++++++--- 2 files changed, 24 insertions(+), 15 deletions(-) diff --git a/internal/fusefrontend/file.go b/internal/fusefrontend/file.go index b9bb2c9..61b1e55 100644 --- a/internal/fusefrontend/file.go +++ b/internal/fusefrontend/file.go @@ -388,23 +388,29 @@ func (f *file) GetAttr(a *fuse.Attr) fuse.Status { const _UTIME_OMIT = ((1 << 30) - 2) +// utimeToTimespec converts a "time.Time" pointer as passed to Utimens to a +// Timespec that can be passed to the utimensat syscall. +func utimeToTimespec(t *time.Time) (ts syscall.Timespec) { + if t == nil { + ts.Nsec = _UTIME_OMIT + } else { + ts = syscall.NsecToTimespec(t.UnixNano()) + // For dates before 1970, NsecToTimespec incorrectly returns negative + // nanoseconds. Ticket: https://github.com/golang/go/issues/12777 + if ts.Nsec < 0 { + ts.Nsec = 0 + } + } + return ts +} + func (f *file) Utimens(a *time.Time, m *time.Time) fuse.Status { f.fdLock.RLock() defer f.fdLock.RUnlock() ts := make([]syscall.Timespec, 2) - - if a == nil { - ts[0].Nsec = _UTIME_OMIT - } else { - ts[0].Sec = a.Unix() - } - - if m == nil { - ts[1].Nsec = _UTIME_OMIT - } else { - ts[1].Sec = m.Unix() - } + ts[0] = utimeToTimespec(a) + ts[1] = utimeToTimespec(m) fn := fmt.Sprintf("/proc/self/fd/%d", f.fd.Fd()) err := syscall.UtimesNano(fn, ts) diff --git a/internal/fusefrontend/fs.go b/internal/fusefrontend/fs.go index 5367622..1219479 100644 --- a/internal/fusefrontend/fs.go +++ b/internal/fusefrontend/fs.go @@ -230,15 +230,18 @@ func (fs *FS) Truncate(path string, offset uint64, context *fuse.Context) (code return code } -func (fs *FS) Utimens(path string, Atime *time.Time, Mtime *time.Time, context *fuse.Context) (code fuse.Status) { +func (fs *FS) Utimens(path string, a *time.Time, m *time.Time, context *fuse.Context) (code fuse.Status) { if fs.isFiltered(path) { return fuse.EPERM } - cPath, err := fs.encryptPath(path) + cPath, err := fs.getBackingPath(path) if err != nil { return fuse.ToStatus(err) } - return fs.FileSystem.Utimens(cPath, Atime, Mtime, context) + ts := make([]syscall.Timespec, 2) + ts[0] = utimeToTimespec(a) + ts[1] = utimeToTimespec(m) + return fuse.ToStatus(syscall.UtimesNano(cPath, ts)) } func (fs *FS) StatFs(path string) *fuse.StatfsOut {