1// Copyright 2016 the Go-FUSE Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style
3// license that can be found in the LICENSE file.
4
5package nodefs
6
7// This file contains FileSystemConnector's implementation of
8// RawFileSystem
9
10import (
11	"fmt"
12	"log"
13	"strings"
14	"time"
15
16	"github.com/hanwen/go-fuse/v2/fuse"
17)
18
19// Returns the RawFileSystem so it can be mounted.
20func (c *FileSystemConnector) RawFS() fuse.RawFileSystem {
21	return (*rawBridge)(c)
22}
23
24type rawBridge FileSystemConnector
25
26func (c *rawBridge) Fsync(cancel <-chan struct{}, input *fuse.FsyncIn) fuse.Status {
27	node := c.toInode(input.NodeId)
28	opened := node.mount.getOpenedFile(input.Fh)
29
30	if opened != nil {
31		return opened.WithFlags.File.Fsync(int(input.FsyncFlags))
32	}
33
34	return fuse.ENOSYS
35}
36
37func (c *rawBridge) SetDebug(debug bool) {
38	c.fsConn().SetDebug(debug)
39}
40
41func (c *rawBridge) FsyncDir(cancel <-chan struct{}, input *fuse.FsyncIn) fuse.Status {
42	return fuse.ENOSYS
43}
44
45func (c *rawBridge) fsConn() *FileSystemConnector {
46	return (*FileSystemConnector)(c)
47}
48
49func (c *rawBridge) String() string {
50	if c.rootNode == nil || c.rootNode.mount == nil {
51		return "go-fuse:unmounted"
52	}
53
54	name := fmt.Sprintf("%T", c.rootNode.Node())
55	name = strings.TrimLeft(name, "*")
56	return name
57}
58
59func (c *rawBridge) Init(s *fuse.Server) {
60	c.server = s
61	c.rootNode.Node().OnMount((*FileSystemConnector)(c))
62}
63
64func (c *FileSystemConnector) lookupMountUpdate(out *fuse.Attr, mount *fileSystemMount) (node *Inode, code fuse.Status) {
65	code = mount.mountInode.Node().GetAttr(out, nil, nil)
66	if !code.Ok() {
67		log.Println("Root getattr should not return error", code)
68		out.Mode = fuse.S_IFDIR | 0755
69		return mount.mountInode, fuse.OK
70	}
71
72	return mount.mountInode, fuse.OK
73}
74
75// internalLookup executes a lookup without affecting NodeId reference counts.
76func (c *FileSystemConnector) internalLookup(cancel <-chan struct{}, out *fuse.Attr, parent *Inode, name string, header *fuse.InHeader) (node *Inode, code fuse.Status) {
77
78	// We may already know the child because it was created using Create or Mkdir,
79	// from an earlier lookup, or because the nodes were created in advance
80	// (in-memory filesystems).
81	child := parent.GetChild(name)
82
83	if child != nil && child.mountPoint != nil {
84		return c.lookupMountUpdate(out, child.mountPoint)
85	}
86
87	if child != nil && !parent.mount.options.LookupKnownChildren {
88		code = child.fsInode.GetAttr(out, nil, &fuse.Context{Caller: header.Caller, Cancel: cancel})
89	} else {
90		child, code = parent.fsInode.Lookup(out, name, &fuse.Context{Caller: header.Caller, Cancel: cancel})
91	}
92
93	return child, code
94}
95
96func (c *rawBridge) Lookup(cancel <-chan struct{}, header *fuse.InHeader, name string, out *fuse.EntryOut) (code fuse.Status) {
97	// Prevent Lookup() and Forget() from running concurrently.
98	// Allow several Lookups to be run simultaneously.
99	c.lookupLock.RLock()
100	defer c.lookupLock.RUnlock()
101
102	parent := c.toInode(header.NodeId)
103	if !parent.IsDir() {
104		log.Printf("Lookup %q called on non-Directory node %d", name, header.NodeId)
105		return fuse.ENOTDIR
106	}
107
108	child, code := c.fsConn().internalLookup(cancel, &out.Attr, parent, name, header)
109	if code == fuse.ENOENT && parent.mount.negativeEntry(out) {
110		return fuse.OK
111	}
112	if !code.Ok() {
113		return code
114	}
115	if child == nil {
116		log.Println("Lookup returned fuse.OK with nil child", name)
117	}
118
119	child.mount.fillEntry(out)
120	out.NodeId, out.Generation = c.fsConn().lookupUpdate(child)
121	if out.Ino == 0 {
122		out.Ino = out.NodeId
123	}
124
125	return fuse.OK
126}
127
128func (c *rawBridge) Forget(nodeID, nlookup uint64) {
129	// Prevent Lookup() and Forget() from running concurrently.
130	c.lookupLock.Lock()
131	defer c.lookupLock.Unlock()
132
133	c.fsConn().forgetUpdate(nodeID, int(nlookup))
134}
135
136func (c *rawBridge) GetAttr(cancel <-chan struct{}, input *fuse.GetAttrIn, out *fuse.AttrOut) (code fuse.Status) {
137	node := c.toInode(input.NodeId)
138
139	var f File
140	if input.Flags()&fuse.FUSE_GETATTR_FH != 0 {
141		if opened := node.mount.getOpenedFile(input.Fh()); opened != nil {
142			f = opened.WithFlags.File
143		}
144	}
145
146	dest := &out.Attr
147	code = node.fsInode.GetAttr(dest, f, &fuse.Context{Caller: input.Caller, Cancel: cancel})
148	if !code.Ok() {
149		return code
150	}
151
152	if out.Nlink == 0 {
153		// With Nlink == 0, newer kernels will refuse link
154		// operations.
155		out.Nlink = 1
156	}
157
158	node.mount.fillAttr(out, input.NodeId)
159	return fuse.OK
160}
161
162func (c *rawBridge) OpenDir(cancel <-chan struct{}, input *fuse.OpenIn, out *fuse.OpenOut) (code fuse.Status) {
163	node := c.toInode(input.NodeId)
164	de := &connectorDir{
165		inode: node,
166		node:  node.Node(),
167		rawFS: c,
168	}
169	h, opened := node.mount.registerFileHandle(node, de, nil, input.Flags)
170	out.OpenFlags = opened.FuseFlags
171	out.Fh = h
172	return fuse.OK
173}
174
175func (c *rawBridge) ReadDir(cancel <-chan struct{}, input *fuse.ReadIn, out *fuse.DirEntryList) fuse.Status {
176	node := c.toInode(input.NodeId)
177	opened := node.mount.getOpenedFile(input.Fh)
178	return opened.dir.ReadDir(cancel, input, out)
179}
180
181func (c *rawBridge) ReadDirPlus(cancel <-chan struct{}, input *fuse.ReadIn, out *fuse.DirEntryList) fuse.Status {
182	node := c.toInode(input.NodeId)
183	opened := node.mount.getOpenedFile(input.Fh)
184	return opened.dir.ReadDirPlus(cancel, input, out)
185}
186
187func (c *rawBridge) Open(cancel <-chan struct{}, input *fuse.OpenIn, out *fuse.OpenOut) (status fuse.Status) {
188	node := c.toInode(input.NodeId)
189	f, code := node.fsInode.Open(input.Flags, &fuse.Context{Caller: input.Caller, Cancel: cancel})
190	if !code.Ok() {
191		return code
192	}
193	h, opened := node.mount.registerFileHandle(node, nil, f, input.Flags)
194	out.OpenFlags = opened.FuseFlags
195	out.Fh = h
196	return fuse.OK
197}
198
199func (c *rawBridge) SetAttr(cancel <-chan struct{}, input *fuse.SetAttrIn, out *fuse.AttrOut) (code fuse.Status) {
200	node := c.toInode(input.NodeId)
201
202	var f File
203	if fh, ok := input.GetFh(); ok {
204		if opened := node.mount.getOpenedFile(fh); opened != nil {
205			f = opened.WithFlags.File
206		}
207	}
208
209	if permissions, ok := input.GetMode(); ok {
210		code = node.fsInode.Chmod(f, permissions, &fuse.Context{Caller: input.Caller, Cancel: cancel})
211	}
212
213	uid, uok := input.GetUID()
214	gid, gok := input.GetGID()
215
216	if code.Ok() && (uok || gok) {
217		code = node.fsInode.Chown(f, uid, gid, &fuse.Context{Caller: input.Caller, Cancel: cancel})
218	}
219	if sz, ok := input.GetSize(); code.Ok() && ok {
220		code = node.fsInode.Truncate(f, sz, &fuse.Context{Caller: input.Caller, Cancel: cancel})
221	}
222
223	atime, aok := input.GetATime()
224	mtime, mok := input.GetMTime()
225	if code.Ok() && (aok || mok) {
226		var a, m *time.Time
227
228		if aok {
229			a = &atime
230		}
231		if mok {
232			m = &mtime
233		}
234
235		code = node.fsInode.Utimens(f, a, m, &fuse.Context{Caller: input.Caller, Cancel: cancel})
236	}
237
238	if !code.Ok() {
239		return code
240	}
241
242	// Must call GetAttr(); the filesystem may override some of
243	// the changes we effect here.
244	attr := &out.Attr
245	code = node.fsInode.GetAttr(attr, nil, &fuse.Context{Caller: input.Caller, Cancel: cancel})
246	if code.Ok() {
247		node.mount.fillAttr(out, input.NodeId)
248	}
249	return code
250}
251
252func (c *rawBridge) Fallocate(cancel <-chan struct{}, input *fuse.FallocateIn) (code fuse.Status) {
253	n := c.toInode(input.NodeId)
254	opened := n.mount.getOpenedFile(input.Fh)
255
256	return n.fsInode.Fallocate(opened, input.Offset, input.Length, input.Mode, &fuse.Context{Caller: input.Caller, Cancel: cancel})
257}
258
259func (c *rawBridge) Readlink(cancel <-chan struct{}, header *fuse.InHeader) (out []byte, code fuse.Status) {
260	n := c.toInode(header.NodeId)
261	return n.fsInode.Readlink(&fuse.Context{Caller: header.Caller, Cancel: cancel})
262}
263
264func (c *rawBridge) Mknod(cancel <-chan struct{}, input *fuse.MknodIn, name string, out *fuse.EntryOut) (code fuse.Status) {
265	parent := c.toInode(input.NodeId)
266
267	child, code := parent.fsInode.Mknod(name, input.Mode, uint32(input.Rdev), &fuse.Context{Caller: input.Caller, Cancel: cancel})
268	if code.Ok() {
269		c.childLookup(out, child, &fuse.Context{Caller: input.Caller, Cancel: cancel})
270		code = child.fsInode.GetAttr(&out.Attr, nil, &fuse.Context{Caller: input.Caller, Cancel: cancel})
271	}
272	return code
273}
274
275func (c *rawBridge) Mkdir(cancel <-chan struct{}, input *fuse.MkdirIn, name string, out *fuse.EntryOut) (code fuse.Status) {
276	parent := c.toInode(input.NodeId)
277
278	child, code := parent.fsInode.Mkdir(name, input.Mode, &fuse.Context{Caller: input.Caller, Cancel: cancel})
279	if code.Ok() {
280		c.childLookup(out, child, &fuse.Context{Caller: input.Caller, Cancel: cancel})
281		code = child.fsInode.GetAttr(&out.Attr, nil, &fuse.Context{Caller: input.Caller, Cancel: cancel})
282	}
283	return code
284}
285
286func (c *rawBridge) Unlink(cancel <-chan struct{}, header *fuse.InHeader, name string) (code fuse.Status) {
287	parent := c.toInode(header.NodeId)
288	return parent.fsInode.Unlink(name, &fuse.Context{Caller: header.Caller, Cancel: cancel})
289}
290
291func (c *rawBridge) Rmdir(cancel <-chan struct{}, header *fuse.InHeader, name string) (code fuse.Status) {
292	parent := c.toInode(header.NodeId)
293	return parent.fsInode.Rmdir(name, &fuse.Context{Caller: header.Caller, Cancel: cancel})
294}
295
296func (c *rawBridge) Symlink(cancel <-chan struct{}, header *fuse.InHeader, pointedTo string, linkName string, out *fuse.EntryOut) (code fuse.Status) {
297	parent := c.toInode(header.NodeId)
298
299	child, code := parent.fsInode.Symlink(linkName, pointedTo, &fuse.Context{Caller: header.Caller, Cancel: cancel})
300	if code.Ok() {
301		c.childLookup(out, child, &fuse.Context{Caller: header.Caller, Cancel: cancel})
302		code = child.fsInode.GetAttr(&out.Attr, nil, &fuse.Context{Caller: header.Caller, Cancel: cancel})
303	}
304	return code
305}
306
307func (c *rawBridge) Rename(cancel <-chan struct{}, input *fuse.RenameIn, oldName string, newName string) (code fuse.Status) {
308	if input.Flags != 0 {
309		return fuse.ENOSYS
310	}
311	oldParent := c.toInode(input.NodeId)
312
313	child := oldParent.GetChild(oldName)
314	if child == nil {
315		return fuse.ENOENT
316	}
317	if child.mountPoint != nil {
318		return fuse.EBUSY
319	}
320
321	newParent := c.toInode(input.Newdir)
322	if oldParent.mount != newParent.mount {
323		return fuse.EXDEV
324	}
325
326	return oldParent.fsInode.Rename(oldName, newParent.fsInode, newName, &fuse.Context{Caller: input.Caller, Cancel: cancel})
327}
328
329func (c *rawBridge) Link(cancel <-chan struct{}, input *fuse.LinkIn, name string, out *fuse.EntryOut) (code fuse.Status) {
330	existing := c.toInode(input.Oldnodeid)
331	parent := c.toInode(input.NodeId)
332
333	if existing.mount != parent.mount {
334		return fuse.EXDEV
335	}
336
337	child, code := parent.fsInode.Link(name, existing.fsInode, &fuse.Context{Caller: input.Caller, Cancel: cancel})
338	if code.Ok() {
339		c.childLookup(out, child, &fuse.Context{Caller: input.Caller, Cancel: cancel})
340		code = child.fsInode.GetAttr(&out.Attr, nil, &fuse.Context{Caller: input.Caller, Cancel: cancel})
341	}
342
343	return code
344}
345
346func (c *rawBridge) Access(cancel <-chan struct{}, input *fuse.AccessIn) (code fuse.Status) {
347	n := c.toInode(input.NodeId)
348	return n.fsInode.Access(input.Mask, &fuse.Context{Caller: input.Caller, Cancel: cancel})
349}
350
351func (c *rawBridge) Create(cancel <-chan struct{}, input *fuse.CreateIn, name string, out *fuse.CreateOut) (code fuse.Status) {
352	parent := c.toInode(input.NodeId)
353	f, child, code := parent.fsInode.Create(name, uint32(input.Flags), input.Mode, &fuse.Context{Caller: input.Caller, Cancel: cancel})
354	if !code.Ok() {
355		return code
356	}
357
358	c.childLookup(&out.EntryOut, child, &fuse.Context{Caller: input.Caller, Cancel: cancel})
359	handle, opened := parent.mount.registerFileHandle(child, nil, f, input.Flags)
360
361	out.OpenOut.OpenFlags = opened.FuseFlags
362	out.OpenOut.Fh = handle
363	return code
364}
365
366func (c *rawBridge) Release(cancel <-chan struct{}, input *fuse.ReleaseIn) {
367	if input.Fh != 0 {
368		node := c.toInode(input.NodeId)
369		opened := node.mount.unregisterFileHandle(input.Fh, node)
370		opened.WithFlags.File.Release()
371	}
372}
373
374func (c *rawBridge) ReleaseDir(input *fuse.ReleaseIn) {
375	if input.Fh != 0 {
376		node := c.toInode(input.NodeId)
377		node.mount.unregisterFileHandle(input.Fh, node)
378	}
379}
380func (c *rawBridge) GetXAttr(cancel <-chan struct{}, header *fuse.InHeader, attribute string, dest []byte) (sz uint32, code fuse.Status) {
381	node := c.toInode(header.NodeId)
382	data, errno := node.fsInode.GetXAttr(attribute, &fuse.Context{Caller: header.Caller, Cancel: cancel})
383
384	if len(data) > len(dest) {
385		return uint32(len(data)), fuse.ERANGE
386	}
387	copy(dest, data)
388	return uint32(len(data)), errno
389}
390
391func (c *rawBridge) GetXAttrData(cancel <-chan struct{}, header *fuse.InHeader, attribute string) (data []byte, code fuse.Status) {
392	node := c.toInode(header.NodeId)
393	return node.fsInode.GetXAttr(attribute, &fuse.Context{Caller: header.Caller, Cancel: cancel})
394}
395
396func (c *rawBridge) RemoveXAttr(cancel <-chan struct{}, header *fuse.InHeader, attr string) fuse.Status {
397	node := c.toInode(header.NodeId)
398	return node.fsInode.RemoveXAttr(attr, &fuse.Context{Caller: header.Caller, Cancel: cancel})
399}
400
401func (c *rawBridge) SetXAttr(cancel <-chan struct{}, input *fuse.SetXAttrIn, attr string, data []byte) fuse.Status {
402	node := c.toInode(input.NodeId)
403	return node.fsInode.SetXAttr(attr, data, int(input.Flags), &fuse.Context{Caller: input.Caller, Cancel: cancel})
404}
405
406func (c *rawBridge) ListXAttr(cancel <-chan struct{}, header *fuse.InHeader, dest []byte) (uint32, fuse.Status) {
407	node := c.toInode(header.NodeId)
408	attrs, code := node.fsInode.ListXAttr(&fuse.Context{Caller: header.Caller, Cancel: cancel})
409	if code != fuse.OK {
410		return 0, code
411	}
412
413	var sz uint32
414	for _, v := range attrs {
415		sz += uint32(len(v)) + 1
416	}
417
418	if int(sz) > len(dest) {
419		return sz, fuse.ERANGE
420	}
421
422	dest = dest[:0]
423	for _, v := range attrs {
424		dest = append(dest, v...)
425		dest = append(dest, 0)
426	}
427
428	return sz, code
429}
430
431////////////////
432// files.
433
434func (c *rawBridge) Write(cancel <-chan struct{}, input *fuse.WriteIn, data []byte) (written uint32, code fuse.Status) {
435	node := c.toInode(input.NodeId)
436	opened := node.mount.getOpenedFile(input.Fh)
437
438	var f File
439	if opened != nil {
440		f = opened.WithFlags.File
441	}
442
443	return node.Node().Write(f, data, int64(input.Offset), &fuse.Context{Caller: input.Caller, Cancel: cancel})
444}
445
446func (c *rawBridge) Read(cancel <-chan struct{}, input *fuse.ReadIn, buf []byte) (fuse.ReadResult, fuse.Status) {
447	node := c.toInode(input.NodeId)
448	opened := node.mount.getOpenedFile(input.Fh)
449
450	var f File
451	if opened != nil {
452		f = opened.WithFlags.File
453	}
454
455	return node.Node().Read(f, buf, int64(input.Offset), &fuse.Context{Caller: input.Caller, Cancel: cancel})
456}
457
458func (c *rawBridge) GetLk(cancel <-chan struct{}, input *fuse.LkIn, out *fuse.LkOut) (code fuse.Status) {
459	n := c.toInode(input.NodeId)
460	opened := n.mount.getOpenedFile(input.Fh)
461
462	return n.fsInode.GetLk(opened, input.Owner, &input.Lk, input.LkFlags, &out.Lk, &fuse.Context{Caller: input.Caller, Cancel: cancel})
463}
464
465func (c *rawBridge) SetLk(cancel <-chan struct{}, input *fuse.LkIn) (code fuse.Status) {
466	n := c.toInode(input.NodeId)
467	opened := n.mount.getOpenedFile(input.Fh)
468
469	return n.fsInode.SetLk(opened, input.Owner, &input.Lk, input.LkFlags, &fuse.Context{Caller: input.Caller, Cancel: cancel})
470}
471
472func (c *rawBridge) SetLkw(cancel <-chan struct{}, input *fuse.LkIn) (code fuse.Status) {
473	n := c.toInode(input.NodeId)
474	opened := n.mount.getOpenedFile(input.Fh)
475
476	return n.fsInode.SetLkw(opened, input.Owner, &input.Lk, input.LkFlags, &fuse.Context{Caller: input.Caller, Cancel: cancel})
477}
478
479func (c *rawBridge) StatFs(cancel <-chan struct{}, header *fuse.InHeader, out *fuse.StatfsOut) fuse.Status {
480	node := c.toInode(header.NodeId)
481	s := node.Node().StatFs()
482	if s == nil {
483		return fuse.ENOSYS
484	}
485	*out = *s
486	return fuse.OK
487}
488
489func (c *rawBridge) Flush(cancel <-chan struct{}, input *fuse.FlushIn) fuse.Status {
490	node := c.toInode(input.NodeId)
491	opened := node.mount.getOpenedFile(input.Fh)
492
493	if opened != nil {
494		return opened.WithFlags.File.Flush()
495	}
496	return fuse.OK
497}
498
499func (c *rawBridge) CopyFileRange(cancel <-chan struct{}, input *fuse.CopyFileRangeIn) (written uint32, code fuse.Status) {
500	return 0, fuse.ENOSYS
501}
502
503func (fs *rawBridge) Lseek(cancel <-chan struct{}, in *fuse.LseekIn, out *fuse.LseekOut) fuse.Status {
504	return fuse.ENOSYS
505}
506