diff options
| author | Jakob Unterwurzacher | 2026-02-02 22:18:25 +0100 |
|---|---|---|
| committer | Jakob Unterwurzacher | 2026-02-03 20:28:10 +0100 |
| commit | 14045511d3d91f36845a138359718c0fe7dff21c (patch) | |
| tree | 66bcc155f68e7c284a2179a0ff582e06e001209c /internal/fusefrontend/node_xattr.go | |
| parent | 6ac778beb0c962e0c2413c1bd91595a9bbccd25b (diff) | |
Use user-provided Listxattr buffer sizexattr_user_buffer
This huge buffer showed up big time in ./profiling/ls.bash
and caused a 2x LS benchmark slowdown.
Instead of the fixed-size buffer, use the buffer size
hint the user has provided us.
We return inaccurate (larger than actual, which should be safe)
numbers when the user has provided no buffer (size probe).
Diffstat (limited to 'internal/fusefrontend/node_xattr.go')
| -rw-r--r-- | internal/fusefrontend/node_xattr.go | 15 |
1 files changed, 14 insertions, 1 deletions
diff --git a/internal/fusefrontend/node_xattr.go b/internal/fusefrontend/node_xattr.go index 1470a2a..2ca5ff7 100644 --- a/internal/fusefrontend/node_xattr.go +++ b/internal/fusefrontend/node_xattr.go @@ -9,6 +9,7 @@ import ( "github.com/hanwen/go-fuse/v2/fuse" + "github.com/rfjakob/gocryptfs/v2/internal/syscallcompat" "github.com/rfjakob/gocryptfs/v2/internal/tlog" ) @@ -136,10 +137,22 @@ func (n *Node) Listxattr(ctx context.Context, dest []byte) (uint32, syscall.Errn if rn.args.NoXattr { return 0, 0 } - cNames, errno := n.listXAttr() + // cBuf is the buffer for the encrypted attr names. Double the size of what the user + // requested to allow for ciphertext expansion due to padding and base64 encoding. + // TODO: double-check max expansion factor + cBuf := make([]byte, 2*len(dest)) + sz, errno := n.listXAttr(cBuf) if errno != 0 { return 0, errno } + // A call with empty dest is a size probe as described in man 2 llistxattr. + // Should return the size of the full attr list and success. + // Because we don't know the size of the decrypted names yet, we return the + // size of the encrypted names. This is slightly higher and hence safe. + if len(dest) == 0 { + return uint32(sz), 0 + } + cNames := syscallcompat.ParseListxattrBlob(cBuf[:sz]) var buf bytes.Buffer for _, curName := range cNames { // ACLs are passed through without encryption |
