aboutsummaryrefslogtreecommitdiff
path: root/internal/fusefrontend_reverse
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_reverse
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_reverse')
-rw-r--r--internal/fusefrontend_reverse/node_xattr.go11
-rw-r--r--internal/fusefrontend_reverse/node_xattr_darwin.go12
-rw-r--r--internal/fusefrontend_reverse/node_xattr_linux.go10
3 files changed, 19 insertions, 14 deletions
diff --git a/internal/fusefrontend_reverse/node_xattr.go b/internal/fusefrontend_reverse/node_xattr.go
index f22764a..9e99cfa 100644
--- a/internal/fusefrontend_reverse/node_xattr.go
+++ b/internal/fusefrontend_reverse/node_xattr.go
@@ -7,6 +7,7 @@ import (
"syscall"
"github.com/rfjakob/gocryptfs/v2/internal/pathiv"
+ "github.com/rfjakob/gocryptfs/v2/internal/syscallcompat"
)
// We store encrypted xattrs under this prefix plus the base64-encoded
@@ -65,10 +66,18 @@ func (n *Node) Listxattr(ctx context.Context, dest []byte) (uint32, syscall.Errn
if rn.args.NoXattr {
return 0, 0
}
- pNames, errno := n.listXAttr()
+ // Can use dest as a temporary buffer
+ sz, errno := n.listXAttr(dest)
if errno != 0 {
return 0, errno
}
+ // If dest empty, return the required size
+ if len(dest) == 0 {
+ // Asssume ciphertext expansion by a factor of 2
+ // TODO: double-check max expansion factor
+ return uint32(sz * 2), 0
+ }
+ pNames := syscallcompat.ParseListxattrBlob(dest[:sz])
var buf bytes.Buffer
for _, pName := range pNames {
// ACLs are passed through without encryption
diff --git a/internal/fusefrontend_reverse/node_xattr_darwin.go b/internal/fusefrontend_reverse/node_xattr_darwin.go
index 6816a18..1832f7f 100644
--- a/internal/fusefrontend_reverse/node_xattr_darwin.go
+++ b/internal/fusefrontend_reverse/node_xattr_darwin.go
@@ -4,6 +4,7 @@ import (
"syscall"
"github.com/hanwen/go-fuse/v2/fs"
+ "golang.org/x/sys/unix"
"github.com/rfjakob/gocryptfs/v2/internal/syscallcompat"
)
@@ -33,7 +34,7 @@ func (n *Node) getXAttr(cAttr string) (out []byte, errno syscall.Errno) {
return cData, 0
}
-func (n *Node) listXAttr() (out []string, errno syscall.Errno) {
+func (n *Node) listXAttr(buf []byte) (sz int, errno syscall.Errno) {
d, errno := n.prepareAtSyscall("")
if errno != 0 {
return
@@ -43,13 +44,10 @@ func (n *Node) listXAttr() (out []string, errno syscall.Errno) {
// O_NONBLOCK to not block on FIFOs.
fd, err := syscallcompat.Openat(d.dirfd, d.pName, syscall.O_RDONLY|syscall.O_NONBLOCK|syscall.O_NOFOLLOW, 0)
if err != nil {
- return nil, fs.ToErrno(err)
+ return 0, fs.ToErrno(err)
}
defer syscall.Close(fd)
- pNames, err := syscallcompat.Flistxattr(fd)
- if err != nil {
- return nil, fs.ToErrno(err)
- }
- return pNames, 0
+ sz, err = unix.Flistxattr(fd, buf)
+ return sz, fs.ToErrno(err)
}
diff --git a/internal/fusefrontend_reverse/node_xattr_linux.go b/internal/fusefrontend_reverse/node_xattr_linux.go
index 3c574f5..226ace4 100644
--- a/internal/fusefrontend_reverse/node_xattr_linux.go
+++ b/internal/fusefrontend_reverse/node_xattr_linux.go
@@ -5,6 +5,7 @@ import (
"syscall"
"github.com/hanwen/go-fuse/v2/fs"
+ "golang.org/x/sys/unix"
"github.com/rfjakob/gocryptfs/v2/internal/syscallcompat"
)
@@ -27,7 +28,7 @@ func (n *Node) getXAttr(cAttr string) (out []byte, errno syscall.Errno) {
return pData, 0
}
-func (n *Node) listXAttr() (out []string, errno syscall.Errno) {
+func (n *Node) listXAttr(buf []byte) (sz int, errno syscall.Errno) {
d, errno := n.prepareAtSyscall("")
if errno != 0 {
return
@@ -35,9 +36,6 @@ func (n *Node) listXAttr() (out []string, errno syscall.Errno) {
defer syscall.Close(d.dirfd)
procPath := fmt.Sprintf("/proc/self/fd/%d/%s", d.dirfd, d.pName)
- pNames, err := syscallcompat.Llistxattr(procPath)
- if err != nil {
- return nil, fs.ToErrno(err)
- }
- return pNames, 0
+ sz, err := unix.Llistxattr(procPath, buf)
+ return sz, fs.ToErrno(err)
}