diff options
author | Jakob Unterwurzacher | 2020-07-14 19:55:20 +0200 |
---|---|---|
committer | Jakob Unterwurzacher | 2020-07-14 19:55:20 +0200 |
commit | 57d572dbc10cfb1d14642598b0827d4119b26b64 (patch) | |
tree | 16e46ff7a7746edfc471ba06ef0570db92fd09fe /internal/fusefrontend/node_xattr.go | |
parent | 4a0966e79efb157b612e4f5867ec6f111571546c (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.go | 86 |
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 +} |