forked from bazil/fuse
-
Notifications
You must be signed in to change notification settings - Fork 1
/
options.go
260 lines (233 loc) · 7.12 KB
/
options.go
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
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
package fuse
import (
"strings"
)
func dummyOption(conf *mountConfig) error {
return nil
}
// mountConfig holds the configuration for a mount operation.
// Use it by passing MountOption values to Mount.
type mountConfig struct {
options map[string]string
maxReadahead uint32
timeGran uint32
initFlags InitFlags
maxBackground uint16
congestionThreshold uint16
}
func escapeComma(s string) string {
s = strings.Replace(s, `\`, `\\`, -1)
s = strings.Replace(s, `,`, `\,`, -1)
return s
}
// getOptions makes a string of options suitable for passing to FUSE
// mount flag `-o`. Returns an empty string if no options were set.
// Any platform specific adjustments should happen before the call.
func (m *mountConfig) getOptions() string {
var opts []string
for k, v := range m.options {
k = escapeComma(k)
if v != "" {
k += "=" + escapeComma(v)
}
opts = append(opts, k)
}
return strings.Join(opts, ",")
}
type mountOption func(*mountConfig) error
// MountOption is passed to Mount to change the behavior of the mount.
type MountOption mountOption
// FSName sets the file system name (also called source) that is
// visible in the list of mounted file systems.
//
// FreeBSD ignores this option.
func FSName(name string) MountOption {
return func(conf *mountConfig) error {
conf.options["fsname"] = name
return nil
}
}
// Subtype sets the subtype of the mount. The main type is always
// `fuse`. The type in a list of mounted file systems will look like
// `fuse.foo`.
//
// FreeBSD ignores this option.
func Subtype(fstype string) MountOption {
return func(conf *mountConfig) error {
conf.options["subtype"] = fstype
return nil
}
}
// DaemonTimeout sets the time in seconds between a request and a reply before
// the FUSE mount is declared dead.
//
// FreeBSD only. Others ignore this option.
func DaemonTimeout(name string) MountOption {
return daemonTimeout(name)
}
// AllowOther allows other users to access the file system.
func AllowOther() MountOption {
return func(conf *mountConfig) error {
conf.options["allow_other"] = ""
return nil
}
}
// AllowDev enables interpreting character or block special devices on the
// filesystem.
func AllowDev() MountOption {
return func(conf *mountConfig) error {
conf.options["dev"] = ""
return nil
}
}
// AllowSUID allows set-user-identifier or set-group-identifier bits to take
// effect.
func AllowSUID() MountOption {
return func(conf *mountConfig) error {
conf.options["suid"] = ""
return nil
}
}
// DefaultPermissions makes the kernel enforce access control based on
// the file mode (as in chmod).
//
// Without this option, the Node itself decides what is and is not
// allowed. This is normally ok because FUSE file systems cannot be
// accessed by other users without AllowOther.
//
// FreeBSD ignores this option.
func DefaultPermissions() MountOption {
return func(conf *mountConfig) error {
conf.options["default_permissions"] = ""
return nil
}
}
// ReadOnly makes the mount read-only.
func ReadOnly() MountOption {
return func(conf *mountConfig) error {
conf.options["ro"] = ""
return nil
}
}
// MaxReadahead sets the number of bytes that can be prefetched for
// sequential reads. The kernel can enforce a maximum value lower than
// this.
//
// This setting makes the kernel perform speculative reads that do not
// originate from any client process. This usually tremendously
// improves read performance.
func MaxReadahead(n uint32) MountOption {
return func(conf *mountConfig) error {
conf.maxReadahead = n
return nil
}
}
// AsyncRead enables multiple outstanding read requests for the same
// handle. Without this, there is at most one request in flight at a
// time.
func AsyncRead() MountOption {
return func(conf *mountConfig) error {
conf.initFlags |= InitAsyncRead
return nil
}
}
// WritebackCache enables the kernel to buffer writes before sending
// them to the FUSE server. Without this, writethrough caching is
// used.
func WritebackCache() MountOption {
return func(conf *mountConfig) error {
conf.initFlags |= InitWritebackCache
return nil
}
}
// CacheSymlinks enables the kernel to cache symlink contents.
func CacheSymlinks() MountOption {
return func(conf *mountConfig) error {
conf.initFlags |= InitCacheSymlinks
return nil
}
}
// TimeGran sets the granularity of timestamps in nanoseconds.
//
// Default is 1 nanosecond, must be power of 10.
func TimeGran(n uint32) MountOption {
return func(conf *mountConfig) error {
conf.timeGran = n
return nil
}
}
// ExplicitInvalidateData stops the kernel from invalidating cached file data automatically.
// Use e.g. `InvalidateNodeData` to invalidate cached data as needed.
func ExplicitInvalidateData() MountOption {
return func(conf *mountConfig) error {
conf.initFlags |= InitExplicitInvalidateData
return nil
}
}
// AllowNonEmptyMount allows the mounting over a non-empty directory.
//
// The files in it will be shadowed by the freshly created mount. By
// default these mounts are rejected to prevent accidental covering up
// of data, which could for example prevent automatic backup.
func AllowNonEmptyMount() MountOption {
return func(conf *mountConfig) error {
conf.options["nonempty"] = ""
return nil
}
}
// MaxBackground sets the maximum number of FUSE requests the kernel
// will submit in the background. Background requests are used when an
// immediate answer is not needed. This may help with request latency.
//
// On Linux, this can be adjusted on the fly with
// /sys/fs/fuse/connections/CONN/max_background
func MaxBackground(n uint16) MountOption {
return func(conf *mountConfig) error {
conf.maxBackground = n
return nil
}
}
// CongestionThreshold sets the number of outstanding background FUSE
// requests beyond which the kernel considers the filesystem
// congested. This may help with request latency.
//
// On Linux, this can be adjusted on the fly with
// /sys/fs/fuse/connections/CONN/congestion_threshold
func CongestionThreshold(n uint16) MountOption {
// TODO to test this, we'd have to figure out our connection id
// and read /sys
return func(conf *mountConfig) error {
conf.congestionThreshold = n
return nil
}
}
// LockingFlock enables flock-based (BSD) locking. This is mostly
// useful for distributed filesystems with global locking. Without
// this, kernel manages local locking automatically.
func LockingFlock() MountOption {
return func(conf *mountConfig) error {
conf.initFlags |= InitFlockLocks
return nil
}
}
// LockingPOSIX enables flock-based (BSD) locking. This is mostly
// useful for distributed filesystems with global locking. Without
// this, kernel manages local locking automatically.
//
// Beware POSIX locks are a broken API with unintuitive behavior for
// callers.
func LockingPOSIX() MountOption {
return func(conf *mountConfig) error {
conf.initFlags |= InitPOSIXLocks
return nil
}
}
// HandleKillPriv enables SUID/SGID/cap management in the FUSE server.
//
// This is the newer `InitHandleKillPrivV2` interface from FUSE protocol 7.33, not the deprecated one from 7.26.
func HandleKillPriv() MountOption {
return func(conf *mountConfig) error {
conf.initFlags |= InitHandleKillPrivV2
return nil
}
}