v2api: implement Symlink
This commit is contained in:
parent
c35b575d5f
commit
250dbc6436
@ -400,3 +400,52 @@ func (n *Node) Link(ctx context.Context, target fs.InodeEmbedder, name string, o
|
|||||||
inode = n.newChild(ctx, st, out)
|
inode = n.newChild(ctx, st, out)
|
||||||
return inode, 0
|
return inode, 0
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Symlink - FUSE call. Create a symlink.
|
||||||
|
//
|
||||||
|
// Symlink-safe through use of Symlinkat.
|
||||||
|
func (n *Node) Symlink(ctx context.Context, target, 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)
|
||||||
|
|
||||||
|
// Make sure context is nil if we don't want to preserve the owner
|
||||||
|
rn := n.rootNode()
|
||||||
|
if !rn.args.PreserveOwner {
|
||||||
|
ctx = nil
|
||||||
|
}
|
||||||
|
|
||||||
|
cTarget := target
|
||||||
|
if !rn.args.PlaintextNames {
|
||||||
|
// Symlinks are encrypted like file contents (GCM) and base64-encoded
|
||||||
|
cTarget = rn.encryptSymlinkTarget(target)
|
||||||
|
}
|
||||||
|
// Create ".name" file to store long file name (except in PlaintextNames mode)
|
||||||
|
var err error
|
||||||
|
ctx2 := toFuseCtx(ctx)
|
||||||
|
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." symlink
|
||||||
|
err = syscallcompat.SymlinkatUser(cTarget, dirfd, cName, ctx2)
|
||||||
|
if err != nil {
|
||||||
|
nametransform.DeleteLongNameAt(dirfd, cName)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// Create symlink
|
||||||
|
err = syscallcompat.SymlinkatUser(cTarget, dirfd, cName, ctx2)
|
||||||
|
}
|
||||||
|
|
||||||
|
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
|
||||||
|
}
|
||||||
|
@ -19,6 +19,7 @@ var _ = (fs.NodeSetattrer)((*Node)(nil))
|
|||||||
var _ = (fs.NodeStatfser)((*Node)(nil))
|
var _ = (fs.NodeStatfser)((*Node)(nil))
|
||||||
var _ = (fs.NodeMknoder)((*Node)(nil))
|
var _ = (fs.NodeMknoder)((*Node)(nil))
|
||||||
var _ = (fs.NodeLinker)((*Node)(nil))
|
var _ = (fs.NodeLinker)((*Node)(nil))
|
||||||
|
var _ = (fs.NodeSymlinker)((*Node)(nil))
|
||||||
|
|
||||||
/* TODO
|
/* TODO
|
||||||
var _ = (fs.NodeGetxattrer)((*Node)(nil))
|
var _ = (fs.NodeGetxattrer)((*Node)(nil))
|
||||||
@ -26,6 +27,5 @@ var _ = (fs.NodeSetxattrer)((*Node)(nil))
|
|||||||
var _ = (fs.NodeRemovexattrer)((*Node)(nil))
|
var _ = (fs.NodeRemovexattrer)((*Node)(nil))
|
||||||
var _ = (fs.NodeListxattrer)((*Node)(nil))
|
var _ = (fs.NodeListxattrer)((*Node)(nil))
|
||||||
var _ = (fs.NodeCopyFileRanger)((*Node)(nil))
|
var _ = (fs.NodeCopyFileRanger)((*Node)(nil))
|
||||||
var _ = (fs.NodeSymlinker)((*Node)(nil))
|
|
||||||
var _ = (fs.NodeRenamer)((*Node)(nil))
|
var _ = (fs.NodeRenamer)((*Node)(nil))
|
||||||
*/
|
*/
|
||||||
|
@ -245,3 +245,17 @@ func (rn *RootNode) openBackingDir(relPath string) (dirfd int, cName string, err
|
|||||||
}
|
}
|
||||||
return dirfd, cName, nil
|
return dirfd, cName, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// encryptSymlinkTarget: "data" is encrypted like file contents (GCM)
|
||||||
|
// and base64-encoded.
|
||||||
|
// The empty string encrypts to the empty string.
|
||||||
|
//
|
||||||
|
// Symlink-safe because it does not do any I/O.
|
||||||
|
func (rn *RootNode) encryptSymlinkTarget(data string) (cData64 string) {
|
||||||
|
if data == "" {
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
cData := rn.contentEnc.EncryptBlock([]byte(data), 0, nil)
|
||||||
|
cData64 = rn.nameTransform.B64EncodeToString(cData)
|
||||||
|
return cData64
|
||||||
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user