diff options
Diffstat (limited to 'internal')
-rw-r--r-- | internal/fusefrontend/node.go | 32 | ||||
-rw-r--r-- | internal/fusefrontend/node_helpers.go | 34 |
2 files changed, 44 insertions, 22 deletions
diff --git a/internal/fusefrontend/node.go b/internal/fusefrontend/node.go index 9d49add..7505f92 100644 --- a/internal/fusefrontend/node.go +++ b/internal/fusefrontend/node.go @@ -69,7 +69,13 @@ func (n *Node) Lookup(ctx context.Context, name string, out *fuse.EntryOut) (ch if err != nil { return nil, fs.ToErrno(err) } + + // Create new inode and fill `out` ch = n.newChild(ctx, st, out) + + // Translate ciphertext size in `out.Attr.Size` to plaintext size + n.translateSize(dirfd, cName, &out.Attr) + return ch, 0 } @@ -98,13 +104,9 @@ func (n *Node) Getattr(ctx context.Context, f fs.FileHandle, out *fuse.AttrOut) rn.inoMap.TranslateStat(st) out.Attr.FromStat(st) - // Fix size - if out.IsRegular() { - out.Size = rn.contentEnc.CipherSizeToPlainSize(out.Size) - } else if out.IsSymlink() { - target, _ := n.Readlink(ctx) - out.Size = uint64(len(target)) - } + // Translate ciphertext size in `out.Attr.Size` to plaintext size + n.translateSize(dirfd, cName, &out.Attr) + if rn.args.ForceOwner != nil { out.Owner = *rn.args.ForceOwner } @@ -221,21 +223,7 @@ func (n *Node) Readlink(ctx context.Context) (out []byte, errno syscall.Errno) { } defer syscall.Close(dirfd) - cTarget, err := syscallcompat.Readlinkat(dirfd, cName) - if err != nil { - return nil, fs.ToErrno(err) - } - rn := n.rootNode() - 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 + return n.readlink(dirfd, cName) } // Open - FUSE call. Open already-existing file. diff --git a/internal/fusefrontend/node_helpers.go b/internal/fusefrontend/node_helpers.go index a7a32af..a31a41d 100644 --- a/internal/fusefrontend/node_helpers.go +++ b/internal/fusefrontend/node_helpers.go @@ -2,10 +2,14 @@ package fusefrontend import ( "context" + "syscall" "github.com/hanwen/go-fuse/v2/fs" "github.com/hanwen/go-fuse/v2/fuse" + + "github.com/rfjakob/gocryptfs/internal/syscallcompat" + "github.com/rfjakob/gocryptfs/internal/tlog" ) // toFuseCtx tries to extract a fuse.Context from a generic context.Context. @@ -29,3 +33,33 @@ func toNode(op fs.InodeEmbedder) *Node { } return op.(*Node) } + +// readlink reads and decrypts a symlink. Used by Readlink, Getattr, Lookup. +func (n *Node) readlink(dirfd int, cName string) (out []byte, errno syscall.Errno) { + cTarget, err := syscallcompat.Readlinkat(dirfd, cName) + if err != nil { + return nil, fs.ToErrno(err) + } + rn := n.rootNode() + 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 +} + +// translateSize translates the ciphertext size in `out` into plaintext size. +func (n *Node) translateSize(dirfd int, cName string, out *fuse.Attr) { + if out.IsRegular() { + rn := n.rootNode() + out.Size = rn.contentEnc.CipherSizeToPlainSize(out.Size) + } else if out.IsSymlink() { + target, _ := n.readlink(dirfd, cName) + out.Size = uint64(len(target)) + } +} |