diff options
author | Sebastian Lackner | 2019-01-16 15:38:32 +0100 |
---|---|---|
committer | Jakob Unterwurzacher | 2019-01-16 20:55:20 +0100 |
commit | 682e642cfa556c2d72c4050bfb8e38febdec49b3 (patch) | |
tree | 5c17005d3a2506da59dacd851eb586c544b239d0 /internal/syscallcompat/sys_linux.go | |
parent | 1d2ce9c213093c91b86ba6c28537ccda4469fe1f (diff) |
fusefrontend: Rework the Utimens handling on macOS.
For Linux, everything effectively stays the same. For both path-based and
fd-based Utimens() calls, we use unix.UtimesNanoAt(). To avoid introducing
a separate syscall wrapper for futimens() (as done in go-fuse, for example),
we instead use the /proc/self/fd - trick.
On macOS, this changes quite a lot:
* Path-based Utimens() calls were previously completely broken, since
unix.UtimensNanoAt() ignores the passed file descriptor. Note that this
cannot be fixed easily since there IS no appropriate syscall available on
macOS prior to High Sierra (10.13). We emulate this case by using
Fchdir() + setattrlist().
* Fd-based Utimens() calls were previously translated to f.GetAttr() (to
fill any empty parameters) and syscall.Futimes(), which does not does
support nanosecond precision. Both issues can be fixed by switching to
fsetattrlist().
Fixes https://github.com/rfjakob/gocryptfs/issues/350
Diffstat (limited to 'internal/syscallcompat/sys_linux.go')
-rw-r--r-- | internal/syscallcompat/sys_linux.go | 23 |
1 files changed, 23 insertions, 0 deletions
diff --git a/internal/syscallcompat/sys_linux.go b/internal/syscallcompat/sys_linux.go index 625e136..92d8183 100644 --- a/internal/syscallcompat/sys_linux.go +++ b/internal/syscallcompat/sys_linux.go @@ -6,6 +6,7 @@ import ( "runtime" "sync" "syscall" + "time" "golang.org/x/sys/unix" @@ -191,6 +192,28 @@ func MkdiratUser(dirfd int, path string, mode uint32, context *fuse.Context) (er return Mkdirat(dirfd, path, mode) } +func timesToTimespec(a *time.Time, m *time.Time) []unix.Timespec { + ts := make([]unix.Timespec, 2) + ts[0] = unix.Timespec(fuse.UtimeToTimespec(a)) + ts[1] = unix.Timespec(fuse.UtimeToTimespec(m)) + return ts +} + +// FutimesNano syscall. +func FutimesNano(fd int, a *time.Time, m *time.Time) (err error) { + ts := timesToTimespec(a, m) + // To avoid introducing a separate syscall wrapper for futimens() + // (as done in go-fuse, for example), we instead use the /proc/self/fd trick. + procPath := fmt.Sprintf("/proc/self/fd/%d", fd) + return unix.UtimesNanoAt(unix.AT_FDCWD, procPath, ts, 0) +} + +// UtimesNanoAtNofollow is like UtimesNanoAt but never follows symlinks. +func UtimesNanoAtNofollow(dirfd int, path string, a *time.Time, m *time.Time) (err error) { + ts := timesToTimespec(a, m) + return unix.UtimesNanoAt(dirfd, path, ts, unix.AT_SYMLINK_NOFOLLOW) +} + // Getdents syscall. func Getdents(fd int) ([]fuse.DirEntry, error) { return getdents(fd) |