aboutsummaryrefslogtreecommitdiff
path: root/internal/fusefrontend/node_xattr.go
diff options
context:
space:
mode:
authorJakob Unterwurzacher2020-07-14 19:55:20 +0200
committerJakob Unterwurzacher2020-07-14 19:55:20 +0200
commit57d572dbc10cfb1d14642598b0827d4119b26b64 (patch)
tree16e46ff7a7746edfc471ba06ef0570db92fd09fe /internal/fusefrontend/node_xattr.go
parent4a0966e79efb157b612e4f5867ec6f111571546c (diff)
v2api: implement Getxattr, Setxattr, Removexattr, Listxattr
gocryptfs/tests/xattr passes.
Diffstat (limited to 'internal/fusefrontend/node_xattr.go')
-rw-r--r--internal/fusefrontend/node_xattr.go86
1 files changed, 86 insertions, 0 deletions
diff --git a/internal/fusefrontend/node_xattr.go b/internal/fusefrontend/node_xattr.go
new file mode 100644
index 0000000..de40915
--- /dev/null
+++ b/internal/fusefrontend/node_xattr.go
@@ -0,0 +1,86 @@
+// Package fusefrontend interfaces directly with the go-fuse library.
+package fusefrontend
+
+import (
+ "bytes"
+ "context"
+ "strings"
+ "syscall"
+
+ "github.com/rfjakob/gocryptfs/internal/tlog"
+)
+
+// xattr names are encrypted like file names, but with a fixed IV.
+// Padded with "_xx" for length 16.
+var xattrNameIV = []byte("xattr_name_iv_xx")
+
+// We store encrypted xattrs under this prefix plus the base64-encoded
+// encrypted original name.
+var xattrStorePrefix = "user.gocryptfs."
+
+// 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()
+ cAttr := rn.encryptXattrName(attr)
+ cData, errno := n.getXAttr(cAttr)
+ if errno != 0 {
+ return 0, errno
+ }
+ data, err := rn.decryptXattrValue(cData)
+ if err != nil {
+ tlog.Warn.Printf("GetXAttr: %v", err)
+ return ^uint32(0), syscall.EIO
+ }
+ l := copy(dest, data)
+ return uint32(l), 0
+}
+
+// SetXAttr - FUSE call. Set extended attribute.
+//
+// This function is symlink-safe through Fsetxattr.
+func (n *Node) Setxattr(ctx context.Context, attr string, data []byte, flags uint32) syscall.Errno {
+ rn := n.rootNode()
+ flags = uint32(filterXattrSetFlags(int(flags)))
+ cAttr := rn.encryptXattrName(attr)
+ cData := rn.encryptXattrValue(data)
+ return n.setXAttr(cAttr, cData, flags)
+}
+
+// RemoveXAttr - FUSE call.
+//
+// This function is symlink-safe through Fremovexattr.
+func (n *Node) Removexattr(ctx context.Context, attr string) syscall.Errno {
+ rn := n.rootNode()
+ cAttr := rn.encryptXattrName(attr)
+ return n.removeXAttr(cAttr)
+}
+
+// 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) {
+ cNames, errno := n.listXAttr()
+ if errno != 0 {
+ return 0, errno
+ }
+ rn := n.rootNode()
+ var buf bytes.Buffer
+ for _, curName := range cNames {
+ if !strings.HasPrefix(curName, xattrStorePrefix) {
+ continue
+ }
+ name, err := rn.decryptXattrName(curName)
+ if err != nil {
+ tlog.Warn.Printf("ListXAttr: invalid xattr name %q: %v", curName, err)
+ rn.reportMitigatedCorruption(curName)
+ continue
+ }
+ buf.WriteString(name + "\000")
+ }
+ if buf.Len() > len(dest) {
+ return ^uint32(0), syscall.ERANGE
+ }
+ return uint32(copy(dest, buf.Bytes())), 0
+}