@@ -16,11 +16,17 @@ import (
1616 "github.com/rclone/rclone/vfs"
1717)
1818
19+ /**
20+ References:
21+ * https://github.com/octohelm/unifs/blob/main/pkg/fuse/node.go
22+ * https://github.com/rfjakob/gocryptfs/blob/master/internal/fusefrontend_reverse/node.go
23+ * https://github.com/seaweedfs/seaweedfs/tree/master/weed/mount
24+ */
25+
1926// Node represents a directory or file
2027type Node struct {
21- fusefs.Inode
22- node vfs.Node
2328 fsys * FS
29+ fusefs.Inode
2430}
2531
2632// Node types must be InodeEmbedders
@@ -35,57 +41,66 @@ func newNode(fsys *FS, vfsNode vfs.Node) (node *Node) {
3541 return node
3642 }
3743 node = & Node {
38- node : vfsNode ,
3944 fsys : fsys ,
4045 }
4146 // Cache the node for later
4247 vfsNode .SetSys (node )
4348 return node
4449}
4550
51+ // Path returns the path of the node relative to the root
52+ func (n * Node ) path (names ... string ) string {
53+ return n .fsys .path (n , names ... )
54+ }
55+
4656// String used for pretty printing.
4757func (n * Node ) String () string {
48- return n .node .Path ()
58+ return n .path ()
59+ }
60+
61+ // VFS returns the VFS that this node is part of
62+ func (n * Node ) VFS () * vfs.VFS {
63+ return n .fsys .VFS
64+ }
65+
66+ // lookup a Node given a path
67+ func (n * Node ) lookupNode (leaf string ) (vfs.Node , syscall.Errno ) {
68+ var (
69+ node vfs.Node
70+ err error
71+ )
72+ if leaf == "" {
73+ node , err = n .VFS ().Stat (n .path ())
74+ } else {
75+ node , err = n .VFS ().Stat (n .path (leaf ))
76+ }
77+ return node , translateError (err )
4978}
5079
51- // lookup a Node in a directory
52- func (n * Node ) lookupVfsNodeInDir (leaf string ) (vfsNode vfs.Node , errno syscall.Errno ) {
53- dir , ok := n .node .(* vfs.Dir )
80+ // lookup a Dir given a path
81+ func (n * Node ) lookupDir (leaf string ) (* vfs.Dir , syscall.Errno ) {
82+ vfsNode , errno := n .lookupNode (leaf )
83+ if errno != 0 {
84+ return nil , errno
85+ }
86+ if ! vfsNode .IsDir () {
87+ return nil , syscall .ENOTDIR
88+ }
89+ dir , ok := vfsNode .(* vfs.Dir )
5490 if ! ok {
5591 return nil , syscall .ENOTDIR
5692 }
57- vfsNode , err := dir .Stat (leaf )
58- return vfsNode , translateError (err )
93+ return dir , 0
5994}
6095
61- // // lookup a Dir given a path
62- // func (n *Node) lookupDir(path string) (dir *vfs.Dir, code fuse.Status) {
63- // node, code := fsys.lookupVfsNodeInDir(path)
64- // if !code.Ok() {
65- // return nil, code
66- // }
67- // dir, ok := n.(*vfs.Dir)
68- // if !ok {
69- // return nil, fuse.ENOTDIR
70- // }
71- // return dir, fuse.OK
72- // }
73-
74- // // lookup a parent Dir given a path returning the dir and the leaf
75- // func (n *Node) lookupParentDir(filePath string) (leaf string, dir *vfs.Dir, code fuse.Status) {
76- // parentDir, leaf := path.Split(filePath)
77- // dir, code = fsys.lookupDir(parentDir)
78- // return leaf, dir, code
79- // }
80-
8196// Statfs implements statistics for the filesystem that holds this
8297// Inode. If not defined, the `out` argument will zeroed with an OK
8398// result. This is because OSX filesystems must Statfs, or the mount
8499// will not work.
85100func (n * Node ) Statfs (ctx context.Context , out * fuse.StatfsOut ) syscall.Errno {
86101 defer log .Trace (n , "" )("out=%+v" , & out )
87102 const blockSize = 4096
88- total , _ , free := n .fsys . VFS .Statfs ()
103+ total , _ , free := n .VFS () .Statfs ()
89104 out .Blocks = uint64 (total ) / blockSize // Total data blocks in file system.
90105 out .Bfree = uint64 (free ) / blockSize // Free blocks in file system.
91106 out .Bavail = out .Bfree // Free blocks in file system if you're not root.
@@ -110,7 +125,11 @@ var _ = (fusefs.NodeStatfser)((*Node)(nil))
110125// with the Options.NullPermissions setting. If blksize is unset, 4096
111126// is assumed, and the 'blocks' field is set accordingly.
112127func (n * Node ) Getattr (ctx context.Context , f fusefs.FileHandle , out * fuse.AttrOut ) syscall.Errno {
113- n .fsys .setAttrOut (n .node , out )
128+ vfsNode , errno := n .lookupNode ("" )
129+ if errno != 0 {
130+ return errno
131+ }
132+ n .fsys .setAttrOut (vfsNode , out )
114133 return 0
115134}
116135
@@ -120,18 +139,22 @@ var _ = (fusefs.NodeGetattrer)((*Node)(nil))
120139func (n * Node ) Setattr (ctx context.Context , f fusefs.FileHandle , in * fuse.SetAttrIn , out * fuse.AttrOut ) (errno syscall.Errno ) {
121140 defer log .Trace (n , "in=%v" , in )("out=%#v, errno=%v" , & out , & errno )
122141 var err error
123- n .fsys .setAttrOut (n .node , out )
142+ vfsNode , errno := n .lookupNode ("" )
143+ if errno != 0 {
144+ return errno
145+ }
146+ n .fsys .setAttrOut (vfsNode , out )
124147 size , ok := in .GetSize ()
125148 if ok {
126- err = n . node .Truncate (int64 (size ))
149+ err = vfsNode .Truncate (int64 (size ))
127150 if err != nil {
128151 return translateError (err )
129152 }
130153 out .Attr .Size = size
131154 }
132155 mtime , ok := in .GetMTime ()
133156 if ok {
134- err = n . node .SetModTime (mtime )
157+ err = vfsNode .SetModTime (mtime )
135158 if err != nil {
136159 return translateError (err )
137160 }
@@ -149,12 +172,16 @@ func (n *Node) Open(ctx context.Context, flags uint32) (fh fusefs.FileHandle, fu
149172 defer log .Trace (n , "flags=%#o" , flags )("errno=%v" , & errno )
150173 // fuse flags are based off syscall flags as are os flags, so
151174 // should be compatible
152- handle , err := n .node .Open (int (flags ))
175+ vfsNode , errno := n .lookupNode ("" )
176+ if errno != 0 {
177+ return nil , 0 , errno
178+ }
179+ handle , err := vfsNode .Open (int (flags ))
153180 if err != nil {
154181 return nil , 0 , translateError (err )
155182 }
156183 // If size unknown then use direct io to read
157- if entry := n . node .DirEntry (); entry != nil && entry .Size () < 0 {
184+ if entry := vfsNode .DirEntry (); entry != nil && entry .Size () < 0 {
158185 fuseFlags |= fuse .FOPEN_DIRECT_IO
159186 }
160187 if n .fsys .opt .DirectIO {
@@ -190,17 +217,15 @@ var _ = (fusefs.NodeOpener)((*Node)(nil))
190217// populate their fuse.EntryOut arguments.
191218func (n * Node ) Lookup (ctx context.Context , name string , out * fuse.EntryOut ) (inode * fusefs.Inode , errno syscall.Errno ) {
192219 defer log .Trace (n , "name=%q" , name )("inode=%v, attr=%v, errno=%v" , & inode , & out , & errno )
193- vfsNode , errno := n .lookupVfsNodeInDir (name )
220+ vfsNode , errno := n .lookupNode (name )
194221 if errno != 0 {
195222 return nil , errno
196223 }
197- newNode := newNode (n .fsys , vfsNode )
198224
199- // FIXME
200- // out.SetEntryTimeout(dt time.Duration)
201- // out.SetAttrTimeout(dt time.Duration)
202225 n .fsys .setEntryOut (vfsNode , out )
203226
227+ newNode := newNode (n .fsys , vfsNode )
228+
204229 return n .NewInode (ctx , newNode , fusefs.StableAttr {Mode : out .Attr .Mode }), 0
205230}
206231
@@ -211,8 +236,9 @@ var _ = (fusefs.NodeLookuper)((*Node)(nil))
211236// this method is just for performing sanity/permission
212237// checks. The default is to return success.
213238func (n * Node ) Opendir (ctx context.Context ) syscall.Errno {
214- if ! n .node .IsDir () {
215- return syscall .ENOTDIR
239+ _ , errno := n .lookupDir ("" )
240+ if errno != 0 {
241+ return errno
216242 }
217243 return 0
218244}
@@ -286,10 +312,11 @@ var _ fusefs.DirStream = (*dirStream)(nil)
286312// static in-memory file systems need not implement NodeReaddirer.
287313func (n * Node ) Readdir (ctx context.Context ) (ds fusefs.DirStream , errno syscall.Errno ) {
288314 defer log .Trace (n , "" )("ds=%v, errno=%v" , & ds , & errno )
289- if ! n .node .IsDir () {
290- return nil , syscall .ENOTDIR
315+ vfsDir , errno := n .lookupDir ("" )
316+ if errno != 0 {
317+ return nil , errno
291318 }
292- fh , err := n . node .Open (os .O_RDONLY )
319+ fh , err := vfsDir .Open (os .O_RDONLY )
293320 if err != nil {
294321 return nil , translateError (err )
295322 }
@@ -314,16 +341,16 @@ var _ = (fusefs.NodeReaddirer)((*Node)(nil))
314341// Default is to return EROFS.
315342func (n * Node ) Mkdir (ctx context.Context , name string , mode uint32 , out * fuse.EntryOut ) (inode * fusefs.Inode , errno syscall.Errno ) {
316343 defer log .Trace (name , "mode=0%o" , mode )("inode=%v, errno=%v" , & inode , & errno )
317- dir , ok := n .node .( * vfs. Dir )
318- if ! ok {
319- return nil , syscall . ENOTDIR
344+ vfsDir , errno := n .lookupDir ( "" )
345+ if errno != 0 {
346+ return nil , errno
320347 }
321- newDir , err := dir .Mkdir (name )
348+ newDir , err := vfsDir .Mkdir (name )
322349 if err != nil {
323350 return nil , translateError (err )
324351 }
325352 newNode := newNode (n .fsys , newDir )
326- n .fsys .setEntryOut (newNode . node , out )
353+ n .fsys .setEntryOut (newDir , out )
327354 newInode := n .NewInode (ctx , newNode , fusefs.StableAttr {Mode : out .Attr .Mode })
328355 return newInode , 0
329356}
@@ -336,13 +363,13 @@ var _ = (fusefs.NodeMkdirer)((*Node)(nil))
336363// Default is to return EROFS.
337364func (n * Node ) Create (ctx context.Context , name string , flags uint32 , mode uint32 , out * fuse.EntryOut ) (node * fusefs.Inode , fh fusefs.FileHandle , fuseFlags uint32 , errno syscall.Errno ) {
338365 defer log .Trace (n , "name=%q, flags=%#o, mode=%#o" , name , flags , mode )("node=%v, fh=%v, flags=%#o, errno=%v" , & node , & fh , & fuseFlags , & errno )
339- dir , ok := n .node .( * vfs. Dir )
340- if ! ok {
341- return nil , nil , 0 , syscall . ENOTDIR
366+ vfsDir , errno := n .lookupDir ( "" )
367+ if errno != 0 {
368+ return nil , nil , 0 , errno
342369 }
343370 // translate the fuse flags to os flags
344371 osFlags := int (flags ) | os .O_CREATE
345- file , err := dir .Create (name , osFlags )
372+ file , err := vfsDir .Create (name , osFlags )
346373 if err != nil {
347374 return nil , nil , 0 , translateError (err )
348375 }
@@ -359,7 +386,7 @@ func (n *Node) Create(ctx context.Context, name string, flags uint32, mode uint3
359386 // }
360387
361388 // Find the created node
362- vfsNode , errno := n .lookupVfsNodeInDir (name )
389+ vfsNode , errno := n .lookupNode (name )
363390 if errno != 0 {
364391 return nil , nil , 0 , errno
365392 }
@@ -377,7 +404,7 @@ var _ = (fusefs.NodeCreater)((*Node)(nil))
377404// FS tree automatically. Default is to return EROFS.
378405func (n * Node ) Unlink (ctx context.Context , name string ) (errno syscall.Errno ) {
379406 defer log .Trace (n , "name=%q" , name )("errno=%v" , & errno )
380- vfsNode , errno := n .lookupVfsNodeInDir (name )
407+ vfsNode , errno := n .lookupNode (name )
381408 if errno != 0 {
382409 return errno
383410 }
@@ -390,7 +417,7 @@ var _ = (fusefs.NodeUnlinker)((*Node)(nil))
390417// Default is to return EROFS.
391418func (n * Node ) Rmdir (ctx context.Context , name string ) (errno syscall.Errno ) {
392419 defer log .Trace (n , "name=%q" , name )("errno=%v" , & errno )
393- vfsNode , errno := n .lookupVfsNodeInDir (name )
420+ vfsNode , errno := n .lookupNode (name )
394421 if errno != 0 {
395422 return errno
396423 }
@@ -404,20 +431,20 @@ var _ = (fusefs.NodeRmdirer)((*Node)(nil))
404431// OK. Default is to return EROFS.
405432func (n * Node ) Rename (ctx context.Context , oldName string , newParent fusefs.InodeEmbedder , newName string , flags uint32 ) (errno syscall.Errno ) {
406433 defer log .Trace (n , "oldName=%q, newParent=%v, newName=%q" , oldName , newParent , newName )("errno=%v" , & errno )
407- oldDir , ok := n .node .( * vfs. Dir )
408- if ! ok {
409- return syscall . ENOTDIR
434+ vfsDir , errno := n .lookupDir ( "" )
435+ if errno != 0 {
436+ return errno
410437 }
411438 newParentNode , ok := newParent .(* Node )
412439 if ! ok {
413440 fs .Errorf (n , "newParent was not a *Node" )
414441 return syscall .EIO
415442 }
416- newDir , ok := newParentNode .node .( * vfs. Dir )
417- if ! ok {
443+ newDir , errno := newParentNode .lookupDir ( "" )
444+ if errno != 0 {
418445 return syscall .ENOTDIR
419446 }
420- return translateError (oldDir .Rename (oldName , newName , newDir ))
447+ return translateError (vfsDir .Rename (oldName , newName , newDir ))
421448}
422449
423450var _ = (fusefs .NodeRenamer )((* Node )(nil ))
@@ -464,8 +491,8 @@ var _ fusefs.NodeReadlinker = (*Node)(nil)
464491// Readlink read symbolic link target.
465492func (n * Node ) Readlink (ctx context.Context ) (ret []byte , err syscall.Errno ) {
466493 defer log .Trace (n , "" )("ret=%v, err=%v" , & ret , & err )
467- path := n .node . Path ()
468- s , serr := n .node . VFS ().Readlink (path )
494+ nodePath := n .path ()
495+ s , serr := n .VFS ().Readlink (nodePath )
469496 return []byte (s ), translateError (serr )
470497}
471498
@@ -474,8 +501,8 @@ var _ fusefs.NodeSymlinker = (*Node)(nil)
474501// Symlink create symbolic link.
475502func (n * Node ) Symlink (ctx context.Context , target , name string , out * fuse.EntryOut ) (node * fusefs.Inode , err syscall.Errno ) {
476503 defer log .Trace (n , "name=%v, target=%v" , name , target )("node=%v, err=%v" , & node , & err )
477- fullPath := path .Join (n .node . Path (), name )
478- vfsNode , serr := n .node . VFS ().CreateSymlink (target , fullPath )
504+ fullPath := path .Join (n .path (), name )
505+ vfsNode , serr := n .VFS ().CreateSymlink (target , fullPath )
479506 if serr != nil {
480507 return nil , translateError (serr )
481508 }
0 commit comments