Commit 07d43e8a authored by Jakob Unterwurzacher's avatar Jakob Unterwurzacher

Fix several Utimens-related build problems on OSX

Properly implementing Utimens caused the OSX build to break because
the utimensat system call is not available there.

This patch reverts the OSX implementation of Utimens to using
syscall.Utimes(). This is not actually correct but the best we can do.

Thanks to @spaghetti2514 who reported the issue and tested the patches.
parent 923cd7b1
......@@ -5,7 +5,6 @@ import (
"os"
"sync"
"syscall"
"time"
"github.com/hanwen/go-fuse/fuse"
)
......@@ -201,30 +200,7 @@ func (f *loopbackFile) GetAttr(a *fuse.Attr) fuse.Status {
return fuse.OK
}
const _UTIME_NOW = ((1 << 30) - 1)
const _UTIME_OMIT = ((1 << 30) - 2)
// Utimens - file handle based version of loopbackFileSystem.Utimens()
func (f *loopbackFile) Utimens(a *time.Time, m *time.Time) fuse.Status {
var ts [2]syscall.Timespec
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()
}
f.lock.Lock()
err := futimens(int(f.File.Fd()), &ts)
f.lock.Unlock()
return fuse.ToStatus(err)
}
// Utimens implemented in files_linux.go
// Allocate implemented in files_linux.go
......
......@@ -60,3 +60,40 @@ func (f *loopbackFile) Allocate(off uint64, sz uint64, mode uint32) fuse.Status
}
return fuse.OK
}
const _UTIME_NOW = ((1 << 30) - 1)
const _UTIME_OMIT = ((1 << 30) - 2)
// timeToTimeval - Convert time.Time to syscall.Timeval
//
// Note: This does not use syscall.NsecToTimespec because
// that does not work properly for times before 1970,
// see https://github.com/golang/go/issues/12777
func timeToTimeval(t *time.Time) syscall.Timeval {
var tv syscall.Timeval
tv.Usec = int32(t.Nanosecond() / 1000)
tv.Sec = t.Unix()
return tv
}
// OSX does not have the utimensat syscall neded to implement this properly.
// We do our best to emulate it using futimes.
func (f *loopbackFile) Utimens(a *time.Time, m *time.Time) fuse.Status {
tv := make([]syscall.Timeval, 2)
if a == nil {
tv[0].Usec = _UTIME_OMIT
} else {
tv[0] = timeToTimeval(a)
}
if m == nil {
tv[1].Usec = _UTIME_OMIT
} else {
tv[1] = timeToTimeval(m)
}
f.lock.Lock()
err := syscall.Futimes(int(f.File.Fd()), tv)
f.lock.Unlock()
return fuse.ToStatus(err)
}
......@@ -2,6 +2,7 @@ package nodefs
import (
"syscall"
"time"
"github.com/hanwen/go-fuse/fuse"
)
......@@ -15,3 +16,28 @@ func (f *loopbackFile) Allocate(off uint64, sz uint64, mode uint32) fuse.Status
}
return fuse.OK
}
const _UTIME_NOW = ((1 << 30) - 1)
const _UTIME_OMIT = ((1 << 30) - 2)
// Utimens - file handle based version of loopbackFileSystem.Utimens()
func (f *loopbackFile) Utimens(a *time.Time, m *time.Time) fuse.Status {
var ts [2]syscall.Timespec
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()
}
f.lock.Lock()
err := futimens(int(f.File.Fd()), &ts)
f.lock.Unlock()
return fuse.ToStatus(err)
}
......@@ -6,7 +6,6 @@ import (
"os"
"path/filepath"
"syscall"
"time"
"github.com/hanwen/go-fuse/fuse"
"github.com/hanwen/go-fuse/fuse/nodefs"
......@@ -118,29 +117,6 @@ func (fs *loopbackFileSystem) Truncate(path string, offset uint64, context *fuse
return fuse.ToStatus(os.Truncate(fs.GetPath(path), int64(offset)))
}
const _UTIME_NOW = ((1 << 30) - 1)
const _UTIME_OMIT = ((1 << 30) - 2)
// Utimens - path based version of loopbackFile.Utimens()
func (fs *loopbackFileSystem) Utimens(path string, a *time.Time, m *time.Time, context *fuse.Context) (code fuse.Status) {
var ts [2]syscall.Timespec
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()
}
err := sysUtimensat(0, fs.GetPath(path), &ts, _AT_SYMLINK_NOFOLLOW)
return fuse.ToStatus(err)
}
func (fs *loopbackFileSystem) Readlink(name string, context *fuse.Context) (out string, code fuse.Status) {
f, err := os.Readlink(fs.GetPath(name))
return f, fuse.ToStatus(err)
......
......@@ -2,6 +2,7 @@ package pathfs
import (
"syscall"
"time"
"github.com/hanwen/go-fuse/fuse"
)
......@@ -21,3 +22,38 @@ func (fs *loopbackFileSystem) StatFs(name string) *fuse.StatfsOut {
}
return nil
}
const _UTIME_NOW = ((1 << 30) - 1)
const _UTIME_OMIT = ((1 << 30) - 2)
// timeToTimeval - Convert time.Time to syscall.Timeval
//
// Note: This does not use syscall.NsecToTimespec because
// that does not work properly for times before 1970,
// see https://github.com/golang/go/issues/12777
func timeToTimeval(t *time.Time) syscall.Timeval {
var tv syscall.Timeval
tv.Usec = int32(t.Nanosecond() / 1000)
tv.Sec = t.Unix()
return tv
}
// OSX does not have the utimensat syscall neded to implement this properly.
// We do our best to emulate it using futimes.
func (fs *loopbackFileSystem) Utimens(path string, a *time.Time, m *time.Time, context *fuse.Context) fuse.Status {
tv := make([]syscall.Timeval, 2)
if a == nil {
tv[0].Usec = _UTIME_OMIT
} else {
tv[0] = timeToTimeval(a)
}
if m == nil {
tv[1].Usec = _UTIME_OMIT
} else {
tv[1] = timeToTimeval(m)
}
err := syscall.Utimes(path, tv)
return fuse.ToStatus(err)
}
......@@ -3,6 +3,7 @@ package pathfs
import (
"fmt"
"syscall"
"time"
"github.com/hanwen/go-fuse/fuse"
)
......@@ -51,3 +52,26 @@ func (fs *loopbackFileSystem) SetXAttr(name string, attr string, data []byte, fl
err := syscall.Setxattr(fs.GetPath(name), attr, data, flags)
return fuse.ToStatus(err)
}
const _UTIME_NOW = ((1 << 30) - 1)
const _UTIME_OMIT = ((1 << 30) - 2)
// Utimens - path based version of loopbackFile.Utimens()
func (fs *loopbackFileSystem) Utimens(path string, a *time.Time, m *time.Time, context *fuse.Context) (code fuse.Status) {
var ts [2]syscall.Timespec
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()
}
err := sysUtimensat(0, fs.GetPath(path), &ts, _AT_SYMLINK_NOFOLLOW)
return fuse.ToStatus(err)
}
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