aboutsummaryrefslogtreecommitdiff
path: root/internal/fusefrontend
diff options
context:
space:
mode:
authorJakob Unterwurzacher2020-07-11 19:32:38 +0200
committerJakob Unterwurzacher2020-07-11 19:32:38 +0200
commitc35b575d5f5aa29c4f39e9f0df15385d9f379caf (patch)
tree96b96f74b0c454aa9c09aa88034c13dcbcbf8ed7 /internal/fusefrontend
parentb971c75e67c26b126a64ab8b00f416b3b573f194 (diff)
v2api: implement Link
Diffstat (limited to 'internal/fusefrontend')
-rw-r--r--internal/fusefrontend/node.go50
-rw-r--r--internal/fusefrontend/node_api_check.go2
2 files changed, 51 insertions, 1 deletions
diff --git a/internal/fusefrontend/node.go b/internal/fusefrontend/node.go
index c4a80dd..2f5f3ec 100644
--- a/internal/fusefrontend/node.go
+++ b/internal/fusefrontend/node.go
@@ -350,3 +350,53 @@ func (n *Node) Mknod(ctx context.Context, name string, mode, rdev uint32, out *f
inode = n.newChild(ctx, st, out)
return inode, 0
}
+
+// Link - FUSE call. Creates a hard link at "newPath" pointing to file
+// "oldPath".
+//
+// Symlink-safe through use of Linkat().
+func (n *Node) Link(ctx context.Context, target fs.InodeEmbedder, name string, out *fuse.EntryOut) (inode *fs.Inode, errno syscall.Errno) {
+ dirfd, cName, errno := n.prepareAtSyscall(name)
+ if errno != 0 {
+ return
+ }
+ defer syscall.Close(dirfd)
+
+ n2 := target.(*Node)
+ dirfd2, cName2, errno := n2.prepareAtSyscall("")
+ if errno != 0 {
+ return
+ }
+ defer syscall.Close(dirfd2)
+
+ // Handle long file name (except in PlaintextNames mode)
+ rn := n.rootNode()
+ var err error
+ if !rn.args.PlaintextNames && nametransform.IsLongContent(cName) {
+ err = rn.nameTransform.WriteLongNameAt(dirfd, cName, name)
+ if err != nil {
+ errno = fs.ToErrno(err)
+ return
+ }
+ // Create "gocryptfs.longfile." link
+ err = syscallcompat.Linkat(dirfd2, cName2, dirfd, cName, 0)
+ if err != nil {
+ nametransform.DeleteLongNameAt(dirfd, cName)
+ }
+ } else {
+ // Create regular link
+ err = syscallcompat.Linkat(dirfd2, cName2, dirfd, cName, 0)
+ }
+ if err != nil {
+ errno = fs.ToErrno(err)
+ return
+ }
+
+ st, err := syscallcompat.Fstatat2(dirfd, cName, unix.AT_SYMLINK_NOFOLLOW)
+ if err != nil {
+ errno = fs.ToErrno(err)
+ return
+ }
+ inode = n.newChild(ctx, st, out)
+ return inode, 0
+}
diff --git a/internal/fusefrontend/node_api_check.go b/internal/fusefrontend/node_api_check.go
index d99564f..a59971f 100644
--- a/internal/fusefrontend/node_api_check.go
+++ b/internal/fusefrontend/node_api_check.go
@@ -18,6 +18,7 @@ var _ = (fs.NodeOpendirer)((*Node)(nil))
var _ = (fs.NodeSetattrer)((*Node)(nil))
var _ = (fs.NodeStatfser)((*Node)(nil))
var _ = (fs.NodeMknoder)((*Node)(nil))
+var _ = (fs.NodeLinker)((*Node)(nil))
/* TODO
var _ = (fs.NodeGetxattrer)((*Node)(nil))
@@ -25,7 +26,6 @@ var _ = (fs.NodeSetxattrer)((*Node)(nil))
var _ = (fs.NodeRemovexattrer)((*Node)(nil))
var _ = (fs.NodeListxattrer)((*Node)(nil))
var _ = (fs.NodeCopyFileRanger)((*Node)(nil))
-var _ = (fs.NodeLinker)((*Node)(nil))
var _ = (fs.NodeSymlinker)((*Node)(nil))
var _ = (fs.NodeRenamer)((*Node)(nil))
*/