v2api: implement Readlink

libgocryptfs
Jakob Unterwurzacher 2 years ago
parent 1618fbbac5
commit 23180794fe
  1. 31
      internal/fusefrontend/node.go
  2. 1
      internal/fusefrontend/node_api_check.go
  3. 20
      internal/fusefrontend/root_node.go

@ -178,3 +178,34 @@ func (n *Node) Unlink(ctx context.Context, name string) syscall.Errno {
}
return fs.ToErrno(err)
}
// Readlink - FUSE call.
//
// Symlink-safe through openBackingDir() + Readlinkat().
func (n *Node) Readlink(ctx context.Context) ([]byte, syscall.Errno) {
rn := n.rootNode()
p := n.path()
if rn.isFiltered(p) {
return nil, syscall.EPERM
}
dirfd, cName, err := rn.openBackingDir(p)
if err != nil {
return nil, fs.ToErrno(err)
}
defer syscall.Close(dirfd)
cTarget, err := syscallcompat.Readlinkat(dirfd, cName)
if err != nil {
return nil, fs.ToErrno(err)
}
if rn.args.PlaintextNames {
return []byte(cTarget), 0
}
// Symlinks are encrypted like file contents (GCM) and base64-encoded
target, err := rn.decryptSymlinkTarget(cTarget)
if err != nil {
tlog.Warn.Printf("Readlink %q: decrypting target failed: %v", cName, err)
return nil, syscall.EIO
}
return []byte(target), 0
}

@ -12,3 +12,4 @@ var _ = (fs.NodeCreater)((*Node)(nil))
var _ = (fs.NodeMkdirer)((*Node)(nil))
var _ = (fs.NodeRmdirer)((*Node)(nil))
var _ = (fs.NodeUnlinker)((*Node)(nil))
var _ = (fs.NodeReadlinker)((*Node)(nil))

@ -117,3 +117,23 @@ func (rn *RootNode) isFiltered(path string) bool {
// are exclusive
return false
}
// decryptSymlinkTarget: "cData64" is base64-decoded and decrypted
// like file contents (GCM).
// The empty string decrypts to the empty string.
//
// This function does not do any I/O and is hence symlink-safe.
func (rn *RootNode) decryptSymlinkTarget(cData64 string) (string, error) {
if cData64 == "" {
return "", nil
}
cData, err := rn.nameTransform.B64DecodeString(cData64)
if err != nil {
return "", err
}
data, err := rn.contentEnc.DecryptBlock([]byte(cData), 0, nil)
if err != nil {
return "", err
}
return string(data), nil
}

Loading…
Cancel
Save