diff options
| author | Jakob Unterwurzacher | 2020-07-11 19:32:38 +0200 | 
|---|---|---|
| committer | Jakob Unterwurzacher | 2020-07-11 19:32:38 +0200 | 
| commit | c35b575d5f5aa29c4f39e9f0df15385d9f379caf (patch) | |
| tree | 96b96f74b0c454aa9c09aa88034c13dcbcbf8ed7 /internal/fusefrontend | |
| parent | b971c75e67c26b126a64ab8b00f416b3b573f194 (diff) | |
v2api: implement Link
Diffstat (limited to 'internal/fusefrontend')
| -rw-r--r-- | internal/fusefrontend/node.go | 50 | ||||
| -rw-r--r-- | internal/fusefrontend/node_api_check.go | 2 | 
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))  */ | 
