summaryrefslogtreecommitdiff
path: root/internal
diff options
context:
space:
mode:
authorBolshevik2018-05-07 22:01:36 +0200
committerJakob Unterwurzacher2018-05-10 23:25:49 +0200
commita41ec2028cf2ad24eafb531d661ea1fe0f751f39 (patch)
tree4dde96d860195c16c65060c9bab0cb6883ff3434 /internal
parenta276321dea04eaa0cfc80c56e8faca4b8ded0b7a (diff)
xattr: optimize storage, store as binary instead of bae64
Values a binary-safe, there is no need to base64-encode them. Old, base64-encoded values are supported transparently on reading. Writing xattr values now always writes them binary.
Diffstat (limited to 'internal')
-rw-r--r--internal/fusefrontend/xattr.go43
1 files changed, 36 insertions, 7 deletions
diff --git a/internal/fusefrontend/xattr.go b/internal/fusefrontend/xattr.go
index 9833368..ac4b15f 100644
--- a/internal/fusefrontend/xattr.go
+++ b/internal/fusefrontend/xattr.go
@@ -36,17 +36,16 @@ func (fs *FS) GetXAttr(path string, attr string, context *fuse.Context) ([]byte,
if err != nil {
return nil, fuse.ToStatus(err)
}
- cData64, err := xattr.Get(cPath, cAttr)
+ encryptedData, err := xattr.Get(cPath, cAttr)
if err != nil {
return nil, unpackXattrErr(err)
}
- // xattr data is decrypted like a symlink target
- data, err := fs.decryptSymlinkTarget(string(cData64))
+ data, err := fs.decryptXattrValue(encryptedData)
if err != nil {
tlog.Warn.Printf("GetXAttr: %v", err)
return nil, fuse.EIO
}
- return []byte(data), fuse.OK
+ return data, fuse.OK
}
// SetXAttr implements pathfs.Filesystem.
@@ -65,9 +64,8 @@ func (fs *FS) SetXAttr(path string, attr string, data []byte, flags int, context
return fuse.ToStatus(err)
}
cAttr := fs.encryptXattrName(attr)
- // xattr data is encrypted like a symlink target
- cData64 := []byte(fs.encryptSymlinkTarget(string(data)))
- return unpackXattrErr(xattr.SetWithFlags(cPath, cAttr, cData64, flags))
+ cData := fs.encryptXattrValue(data)
+ return unpackXattrErr(xattr.SetWithFlags(cPath, cAttr, cData, flags))
}
// RemoveXAttr implements pathfs.Filesystem.
@@ -136,6 +134,37 @@ func (fs *FS) decryptXattrName(cAttr string) (attr string, err error) {
return attr, nil
}
+// encryptXattrValue encrypts the xattr value "data".
+// The data is encrypted like a file content block, but without binding it to
+// a file location (block number and file id are set to zero).
+// Special case: an empty value is encrypted to an empty value.
+func (fs *FS) encryptXattrValue(data []byte) (cData []byte) {
+ if len(data) == 0 {
+ return []byte{}
+ }
+ return fs.contentEnc.EncryptBlock(data, 0, nil)
+}
+
+// decryptXattrValue decrypts the xattr value "cData".
+func (fs *FS) decryptXattrValue(cData []byte) (data []byte, err error) {
+ if len(cData) == 0 {
+ return []byte{}, nil
+ }
+ data, err1 := fs.contentEnc.DecryptBlock([]byte(cData), 0, nil)
+ if err1 == nil {
+ return data, nil
+ }
+ // This backward compatibility is needed to support old
+ // file systems having xattr values base64-encoded.
+ cData, err2 := fs.nameTransform.B64.DecodeString(string(cData))
+ if err2 != nil {
+ // Looks like the value was not base64-encoded, but just corrupt.
+ // Return the original decryption error: err1
+ return nil, err1
+ }
+ return fs.contentEnc.DecryptBlock([]byte(cData), 0, nil)
+}
+
// unpackXattrErr unpacks an error value that we got from xattr.Get/Set/etc
// and converts it to a fuse status.
func unpackXattrErr(err error) fuse.Status {