aboutsummaryrefslogtreecommitdiff
path: root/internal/fusefrontend/node_xattr.go
diff options
context:
space:
mode:
authorJakob Unterwurzacher2026-02-02 22:18:25 +0100
committerJakob Unterwurzacher2026-02-03 20:28:10 +0100
commit14045511d3d91f36845a138359718c0fe7dff21c (patch)
tree66bcc155f68e7c284a2179a0ff582e06e001209c /internal/fusefrontend/node_xattr.go
parent6ac778beb0c962e0c2413c1bd91595a9bbccd25b (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.go15
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