aboutsummaryrefslogtreecommitdiff
path: root/internal/syscallcompat/sys_darwin.go
blob: be85fee35b45370f54b101592f7eb14a2f5ac49e (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
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
package syscallcompat

import (
	"log"
	"runtime"
	"syscall"

	"golang.org/x/sys/unix"

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

	"github.com/rfjakob/gocryptfs/internal/tlog"
)

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 Fchmodat(dirfd int, path string, mode uint32, flags int) (err error) {
	// Why would we ever want to call this without AT_SYMLINK_NOFOLLOW?
	if flags&unix.AT_SYMLINK_NOFOLLOW == 0 {
		tlog.Warn.Printf("Fchmodat: adding missing AT_SYMLINK_NOFOLLOW flag")
		flags |= unix.AT_SYMLINK_NOFOLLOW
	}
	return unix.Fchmodat(dirfd, path, mode, flags)
}

func Symlinkat(oldpath string, newdirfd int, newpath string) (err error) {
	return emulateSymlinkat(oldpath, newdirfd, newpath)
}

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 Mkdirat(dirfd int, path string, mode uint32) (err error) {
	return emulateMkdirat(dirfd, path, mode)
}

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 Fstatat(dirfd int, path string, stat *unix.Stat_t, flags int) (err error) {
	return emulateFstatat(dirfd, path, stat, flags)
}

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