v2api/reverse: implement Readlink
This commit is contained in:
parent
84ed139cd2
commit
5276092663
@ -2,6 +2,7 @@ package fusefrontend_reverse
|
||||
|
||||
import (
|
||||
"context"
|
||||
"path/filepath"
|
||||
"syscall"
|
||||
|
||||
"golang.org/x/sys/unix"
|
||||
@ -20,16 +21,16 @@ type Node struct {
|
||||
}
|
||||
|
||||
// Lookup - FUSE call for discovering a file.
|
||||
func (n *Node) Lookup(ctx context.Context, name string, out *fuse.EntryOut) (ch *fs.Inode, errno syscall.Errno) {
|
||||
func (n *Node) Lookup(ctx context.Context, cName string, out *fuse.EntryOut) (ch *fs.Inode, errno syscall.Errno) {
|
||||
dirfd := int(-1)
|
||||
pName := ""
|
||||
t := n.lookupFileType(name)
|
||||
t := n.lookupFileType(cName)
|
||||
if t == typeDiriv {
|
||||
// gocryptfs.diriv
|
||||
return n.lookupDiriv(ctx, out)
|
||||
} else if t == typeName {
|
||||
// gocryptfs.longname.*.name
|
||||
return n.lookupLongnameName(ctx, name, out)
|
||||
return n.lookupLongnameName(ctx, cName, out)
|
||||
} else if t == typeConfig {
|
||||
// gocryptfs.conf
|
||||
var err error
|
||||
@ -43,7 +44,7 @@ func (n *Node) Lookup(ctx context.Context, name string, out *fuse.EntryOut) (ch
|
||||
defer syscall.Close(dirfd)
|
||||
} else if t == typeReal {
|
||||
// real file
|
||||
dirfd, pName, errno = n.prepareAtSyscall(name)
|
||||
dirfd, pName, errno = n.prepareAtSyscall(cName)
|
||||
if errno != 0 {
|
||||
return
|
||||
}
|
||||
@ -58,7 +59,7 @@ func (n *Node) Lookup(ctx context.Context, name string, out *fuse.EntryOut) (ch
|
||||
ch = n.newChild(ctx, st, out)
|
||||
// Translate ciphertext size in `out.Attr.Size` to plaintext size
|
||||
if t == typeReal {
|
||||
n.translateSize(dirfd, pName, &out.Attr)
|
||||
n.translateSize(dirfd, cName, pName, &out.Attr)
|
||||
}
|
||||
return ch, 0
|
||||
}
|
||||
@ -89,10 +90,25 @@ func (n *Node) Getattr(ctx context.Context, f fs.FileHandle, out *fuse.AttrOut)
|
||||
out.Attr.FromStat(st)
|
||||
|
||||
// Translate ciphertext size in `out.Attr.Size` to plaintext size
|
||||
n.translateSize(dirfd, pName, &out.Attr)
|
||||
cName := filepath.Base(n.Path())
|
||||
n.translateSize(dirfd, cName, pName, &out.Attr)
|
||||
|
||||
if rn.args.ForceOwner != nil {
|
||||
out.Owner = *rn.args.ForceOwner
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
// Readlink - FUSE call.
|
||||
//
|
||||
// Symlink-safe through openBackingDir() + Readlinkat().
|
||||
func (n *Node) Readlink(ctx context.Context) (out []byte, errno syscall.Errno) {
|
||||
dirfd, pName, errno := n.prepareAtSyscall("")
|
||||
if errno != 0 {
|
||||
return
|
||||
}
|
||||
defer syscall.Close(dirfd)
|
||||
|
||||
cName := filepath.Base(n.Path())
|
||||
return n.readlink(dirfd, cName, pName)
|
||||
}
|
||||
|
37
internal/fusefrontend_reverse/node_api_check.go
Normal file
37
internal/fusefrontend_reverse/node_api_check.go
Normal file
@ -0,0 +1,37 @@
|
||||
package fusefrontend_reverse
|
||||
|
||||
import (
|
||||
"github.com/hanwen/go-fuse/v2/fs"
|
||||
)
|
||||
|
||||
// Check that we have implemented the fs.Node* interfaces
|
||||
var _ = (fs.NodeGetattrer)((*Node)(nil))
|
||||
var _ = (fs.NodeLookuper)((*Node)(nil))
|
||||
var _ = (fs.NodeReaddirer)((*Node)(nil))
|
||||
var _ = (fs.NodeReadlinker)((*Node)(nil))
|
||||
|
||||
/* TODO
|
||||
var _ = (fs.NodeOpener)((*Node)(nil))
|
||||
var _ = (fs.NodeStatfser)((*Node)(nil))
|
||||
var _ = (fs.NodeMknoder)((*Node)(nil))
|
||||
var _ = (fs.NodeGetxattrer)((*Node)(nil))
|
||||
var _ = (fs.NodeListxattrer)((*Node)(nil))
|
||||
*/
|
||||
|
||||
/* Not needed
|
||||
var _ = (fs.NodeOpendirer)((*Node)(nil))
|
||||
*/
|
||||
|
||||
/* Will not implement these - reverse mode is read-only!
|
||||
var _ = (fs.NodeCreater)((*Node)(nil))
|
||||
var _ = (fs.NodeMkdirer)((*Node)(nil))
|
||||
var _ = (fs.NodeRmdirer)((*Node)(nil))
|
||||
var _ = (fs.NodeUnlinker)((*Node)(nil))
|
||||
var _ = (fs.NodeSetattrer)((*Node)(nil))
|
||||
var _ = (fs.NodeLinker)((*Node)(nil))
|
||||
var _ = (fs.NodeSymlinker)((*Node)(nil))
|
||||
var _ = (fs.NodeRenamer)((*Node)(nil))
|
||||
var _ = (fs.NodeSetxattrer)((*Node)(nil))
|
||||
var _ = (fs.NodeRemovexattrer)((*Node)(nil))
|
||||
var _ = (fs.NodeCopyFileRanger)((*Node)(nil))
|
||||
*/
|
@ -26,12 +26,13 @@ const (
|
||||
)
|
||||
|
||||
// translateSize translates the ciphertext size in `out` into plaintext size.
|
||||
func (n *Node) translateSize(dirfd int, cName string, out *fuse.Attr) {
|
||||
func (n *Node) translateSize(dirfd int, cName string, pName string, out *fuse.Attr) {
|
||||
if out.IsRegular() {
|
||||
rn := n.rootNode()
|
||||
out.Size = rn.contentEnc.PlainSizeToCipherSize(out.Size)
|
||||
} else if out.IsSymlink() {
|
||||
panic("todo: call readlink once it is implemented")
|
||||
cLink, _ := n.readlink(dirfd, cName, pName)
|
||||
out.Size = uint64(len(cLink))
|
||||
}
|
||||
}
|
||||
|
||||
@ -151,3 +152,29 @@ func (n *Node) lookupDiriv(ctx context.Context, out *fuse.EntryOut) (ch *fs.Inod
|
||||
ch = n.NewInode(ctx, vf, id)
|
||||
return
|
||||
}
|
||||
|
||||
// readlink reads and encrypts a symlink. Used by Readlink, Getattr, Lookup.
|
||||
func (n *Node) readlink(dirfd int, cName string, pName string) (out []byte, errno syscall.Errno) {
|
||||
plainTarget, err := syscallcompat.Readlinkat(dirfd, pName)
|
||||
if err != nil {
|
||||
errno = fs.ToErrno(err)
|
||||
return
|
||||
}
|
||||
rn := n.rootNode()
|
||||
if rn.args.PlaintextNames {
|
||||
return []byte(plainTarget), 0
|
||||
}
|
||||
// Nonce is derived from the relative *ciphertext* path
|
||||
p := filepath.Join(n.Path(), cName)
|
||||
nonce := pathiv.Derive(p, pathiv.PurposeSymlinkIV)
|
||||
// Symlinks are encrypted like file contents and base64-encoded
|
||||
cBinTarget := rn.contentEnc.EncryptBlockNonce([]byte(plainTarget), 0, nil, nonce)
|
||||
cTarget := rn.nameTransform.B64EncodeToString(cBinTarget)
|
||||
// The kernel will reject a symlink target above 4096 chars and return
|
||||
// and I/O error to the user. Better emit the proper error ourselves.
|
||||
if len(cTarget) > syscallcompat.PATH_MAX {
|
||||
errno = syscall.ENAMETOOLONG
|
||||
return
|
||||
}
|
||||
return []byte(cTarget), 0
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user