diff options
| author | Aleksey Vasenev | 2024-11-17 23:14:36 +0300 |
|---|---|---|
| committer | Jakob Unterwurzacher | 2025-11-22 21:24:20 +0100 |
| commit | ed1c5e4a9f5ce1921f3ec03b32e591ce828ec5b9 (patch) | |
| tree | a2e1f64e772e2af169df3ce4ac955fbf3ec8c83b /internal/fusefrontend_reverse/node_xattr.go | |
| parent | be34b9822bea4ce3b717c1b9bf5076f1118427ec (diff) | |
Xattrs support in reverse mode
Fixes https://github.com/rfjakob/gocryptfs/issues/827
Diffstat (limited to 'internal/fusefrontend_reverse/node_xattr.go')
| -rw-r--r-- | internal/fusefrontend_reverse/node_xattr.go | 81 |
1 files changed, 81 insertions, 0 deletions
diff --git a/internal/fusefrontend_reverse/node_xattr.go b/internal/fusefrontend_reverse/node_xattr.go new file mode 100644 index 0000000..f4e3bda --- /dev/null +++ b/internal/fusefrontend_reverse/node_xattr.go @@ -0,0 +1,81 @@ +// Package fusefrontend_reverse interfaces directly with the go-fuse library. +package fusefrontend_reverse + +import ( + "bytes" + "context" + "syscall" + + "github.com/rfjakob/gocryptfs/v2/internal/pathiv" +) + +// We store encrypted xattrs under this prefix plus the base64-encoded +// encrypted original name. +var xattrStorePrefix = "user.gocryptfs." + +// isAcl returns true if the attribute name is for storing ACLs +// +// ACLs are passed through without encryption +func isAcl(attr string) bool { + return attr == "system.posix_acl_access" || attr == "system.posix_acl_default" +} + +// GetXAttr - FUSE call. Reads the value of extended attribute "attr". +// +// This function is symlink-safe through Fgetxattr. +func (n *Node) Getxattr(ctx context.Context, attr string, dest []byte) (uint32, syscall.Errno) { + rn := n.rootNode() + var data []byte + // ACLs are passed through without encryption + if isAcl(attr) { + var errno syscall.Errno + data, errno = n.getXAttr(attr) + if errno != 0 { + return 0, errno + } + } else { + pAttr, err := rn.decryptXattrName(attr) + if err != nil { + return 0, syscall.EINVAL + } + pData, errno := n.getXAttr(pAttr) + if errno != 0 { + return 0, errno + } + nonce := pathiv.Derive(n.Path()+"\000"+attr, pathiv.PurposeXattrIV) + data = rn.encryptXattrValue(pData, nonce) + } + if len(dest) < len(data) { + return uint32(len(data)), syscall.ERANGE + } + l := copy(dest, data) + return uint32(l), 0 +} + +// ListXAttr - FUSE call. Lists extended attributes on the file at "relPath". +// +// This function is symlink-safe through Flistxattr. +func (n *Node) Listxattr(ctx context.Context, dest []byte) (uint32, syscall.Errno) { + pNames, errno := n.listXAttr() + if errno != 0 { + return 0, errno + } + rn := n.rootNode() + var buf bytes.Buffer + for _, pName := range pNames { + // ACLs are passed through without encryption + if isAcl(pName) { + buf.WriteString(pName + "\000") + continue + } + cName, err := rn.encryptXattrName(pName) + if err != nil { + continue + } + buf.WriteString(cName + "\000") + } + if buf.Len() > len(dest) { + return uint32(buf.Len()), syscall.ERANGE + } + return uint32(copy(dest, buf.Bytes())), 0 +} |
