summaryrefslogtreecommitdiff
path: root/internal/syscallcompat/sys_darwin.go
diff options
context:
space:
mode:
Diffstat (limited to 'internal/syscallcompat/sys_darwin.go')
-rw-r--r--internal/syscallcompat/sys_darwin.go87
1 files changed, 87 insertions, 0 deletions
diff --git a/internal/syscallcompat/sys_darwin.go b/internal/syscallcompat/sys_darwin.go
index ebda80f..699e38c 100644
--- a/internal/syscallcompat/sys_darwin.go
+++ b/internal/syscallcompat/sys_darwin.go
@@ -2,8 +2,11 @@ package syscallcompat
import (
"log"
+ "path/filepath"
"runtime"
"syscall"
+ "time"
+ "unsafe"
"golang.org/x/sys/unix"
@@ -33,6 +36,24 @@ func pthread_setugid_np(uid uint32, gid uint32) (err error) {
return
}
+// Unfortunately fsetattrlist does not have a syscall wrapper yet.
+func fsetattrlist(fd int, list unsafe.Pointer, buf unsafe.Pointer, size uintptr, options int) (err error) {
+ _, _, e1 := syscall.Syscall6(syscall.SYS_FSETATTRLIST, uintptr(fd), uintptr(list), uintptr(buf), uintptr(size), uintptr(options), 0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// Setattrlist already has a syscall wrapper, but it is not exported.
+func setattrlist(path *byte, list unsafe.Pointer, buf unsafe.Pointer, size uintptr, options int) (err error) {
+ _, _, e1 := syscall.Syscall6(syscall.SYS_SETATTRLIST, uintptr(unsafe.Pointer(path)), uintptr(list), uintptr(buf), uintptr(size), uintptr(options), 0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
// Sorry, fallocate is not available on OSX at all and
// fcntl F_PREALLOCATE is not accessible from Go.
// See https://github.com/rfjakob/gocryptfs/issues/18 if you want to help.
@@ -125,6 +146,72 @@ func MkdiratUser(dirfd int, path string, mode uint32, context *fuse.Context) (er
return Mkdirat(dirfd, path, mode)
}
+type attrList struct {
+ bitmapCount uint16
+ _ uint16
+ CommonAttr uint32
+ VolAttr uint32
+ DirAttr uint32
+ FileAttr uint32
+ Forkattr uint32
+}
+
+func timesToAttrList(a *time.Time, m *time.Time) (attrList attrList, attributes [2]unix.Timespec) {
+ attrList.bitmapCount = unix.ATTR_BIT_MAP_COUNT
+ attrList.CommonAttr = 0
+ i := 0
+ if m != nil {
+ attributes[i] = unix.Timespec(fuse.UtimeToTimespec(m))
+ attrList.CommonAttr |= unix.ATTR_CMN_MODTIME
+ i += 1
+ }
+ if a != nil {
+ attributes[i] = unix.Timespec(fuse.UtimeToTimespec(a))
+ attrList.CommonAttr |= unix.ATTR_CMN_ACCTIME
+ i += 1
+ }
+ return attrList, attributes
+}
+
+// FutimesNano syscall.
+func FutimesNano(fd int, a *time.Time, m *time.Time) (err error) {
+ attrList, attributes := timesToAttrList(a, m)
+ return fsetattrlist(fd, unsafe.Pointer(&attrList), unsafe.Pointer(&attributes),
+ unsafe.Sizeof(attributes), 0)
+}
+
+// UtimesNanoAtNofollow is like UtimesNanoAt but never follows symlinks.
+//
+// Unfortunately we cannot use unix.UtimesNanoAt since it is broken and just
+// ignores the provided 'dirfd'. In addition, it also lacks handling of 'nil'
+// pointers (used to preserve one of both timestamps).
+func UtimesNanoAtNofollow(dirfd int, path string, a *time.Time, m *time.Time) (err error) {
+ if !filepath.IsAbs(path) {
+ chdirMutex.Lock()
+ defer chdirMutex.Unlock()
+ var cwd int
+ cwd, err = syscall.Open(".", syscall.O_RDONLY, 0)
+ if err != nil {
+ return err
+ }
+ defer syscall.Close(cwd)
+ err = syscall.Fchdir(dirfd)
+ if err != nil {
+ return err
+ }
+ defer syscall.Fchdir(cwd)
+ }
+
+ _p0, err := syscall.BytePtrFromString(path)
+ if err != nil {
+ return err
+ }
+
+ attrList, attributes := timesToAttrList(a, m)
+ return setattrlist(_p0, unsafe.Pointer(&attrList), unsafe.Pointer(&attributes),
+ unsafe.Sizeof(attributes), unix.FSOPT_NOFOLLOW)
+}
+
func Getdents(fd int) ([]fuse.DirEntry, error) {
return emulateGetdents(fd)
}