summaryrefslogtreecommitdiff
path: root/internal/syscallcompat/sys_darwin.go
blob: ebda80f5d0277cd7567273e87dd29fb39ee27ae6 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
package syscallcompat

import (
	"log"
	"runtime"
	"syscall"

	"golang.org/x/sys/unix"

	"github.com/hanwen/go-fuse/fuse"
)

const (
	// O_DIRECT means oncached I/O on Linux. No direct equivalent on MacOS and defined
	// to zero there.
	O_DIRECT = 0

	// O_PATH is only defined on Linux
	O_PATH = 0

	// KAUTH_UID_NONE and KAUTH_GID_NONE are special values to
	// revert permissions to the process credentials.
	KAUTH_UID_NONE = ^uint32(0) - 100
	KAUTH_GID_NONE = ^uint32(0) - 100
)

// Unfortunately pthread_setugid_np does not have a syscall wrapper yet.
func pthread_setugid_np(uid uint32, gid uint32) (err error) {
	_, _, e1 := syscall.RawSyscall(syscall.SYS_SETTID, uintptr(uid), uintptr(gid), 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.
func EnospcPrealloc(fd int, off int64, len int64) error {
	return nil
}

// See above.
func Fallocate(fd int, mode uint32, off int64, len int64) error {
	return syscall.EOPNOTSUPP
}

// Dup3 is not available on Darwin, so we use Dup2 instead.
func Dup3(oldfd int, newfd int, flags int) (err error) {
	if flags != 0 {
		log.Panic("darwin does not support dup3 flags")
	}
	return syscall.Dup2(oldfd, newfd)
}

////////////////////////////////////////////////////////
//// Emulated Syscalls (see emulate.go) ////////////////
////////////////////////////////////////////////////////

func OpenatUser(dirfd int, path string, flags int, mode uint32, context *fuse.Context) (fd int, err error) {
	if context != nil {
		runtime.LockOSThread()
		defer runtime.UnlockOSThread()

		err = pthread_setugid_np(context.Owner.Uid, context.Owner.Gid)
		if err != nil {
			return -1, err
		}
		defer pthread_setugid_np(KAUTH_UID_NONE, KAUTH_GID_NONE)
	}

	return Openat(dirfd, path, flags, mode)
}

func Mknodat(dirfd int, path string, mode uint32, dev int) (err error) {
	return emulateMknodat(dirfd, path, mode, dev)
}

func MknodatUser(dirfd int, path string, mode uint32, dev int, context *fuse.Context) (err error) {
	if context != nil {
		runtime.LockOSThread()
		defer runtime.UnlockOSThread()

		err = pthread_setugid_np(context.Owner.Uid, context.Owner.Gid)
		if err != nil {
			return err
		}
		defer pthread_setugid_np(KAUTH_UID_NONE, KAUTH_GID_NONE)
	}

	return Mknodat(dirfd, path, mode, dev)
}

func FchmodatNofollow(dirfd int, path string, mode uint32) (err error) {
	return unix.Fchmodat(dirfd, path, mode, unix.AT_SYMLINK_NOFOLLOW)
}

func SymlinkatUser(oldpath string, newdirfd int, newpath string, context *fuse.Context) (err error) {
	if context != nil {
		runtime.LockOSThread()
		defer runtime.UnlockOSThread()

		err = pthread_setugid_np(context.Owner.Uid, context.Owner.Gid)
		if err != nil {
			return err
		}
		defer pthread_setugid_np(KAUTH_UID_NONE, KAUTH_GID_NONE)
	}

	return Symlinkat(oldpath, newdirfd, newpath)
}

func MkdiratUser(dirfd int, path string, mode uint32, context *fuse.Context) (err error) {
	if context != nil {
		runtime.LockOSThread()
		defer runtime.UnlockOSThread()

		err = pthread_setugid_np(context.Owner.Uid, context.Owner.Gid)
		if err != nil {
			return err
		}
		defer pthread_setugid_np(KAUTH_UID_NONE, KAUTH_GID_NONE)
	}

	return Mkdirat(dirfd, path, mode)
}

func Getdents(fd int) ([]fuse.DirEntry, error) {
	return emulateGetdents(fd)
}