aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJakob Unterwurzacher2018-03-25 21:02:33 +0200
committerJakob Unterwurzacher2018-03-25 21:06:10 +0200
commitdb778aae7db844e77b602816a4fd0aeab5d6857e (patch)
tree1544087ce9fb32926a276781507c2604b366e113
parent1ed3d51df1750d5472b1349222c352171f1e8d64 (diff)
fusefrontend: handle empty xattrs efficiently
We handle empty files by storing an actual empty file on disk. Handle xattrs similarily and encrypt the empty value to the empty value.
-rw-r--r--internal/fusefrontend/fs.go8
-rw-r--r--tests/xattr/xattr_integration_test.go54
2 files changed, 62 insertions, 0 deletions
diff --git a/internal/fusefrontend/fs.go b/internal/fusefrontend/fs.go
index 738f113..e246264 100644
--- a/internal/fusefrontend/fs.go
+++ b/internal/fusefrontend/fs.go
@@ -348,7 +348,11 @@ func (fs *FS) StatFs(path string) *fuse.StatfsOut {
// decryptSymlinkTarget: "cData64" is base64-decoded and decrypted
// like file contents (GCM).
+// The empty string decrypts to the empty string.
func (fs *FS) decryptSymlinkTarget(cData64 string) (string, error) {
+ if cData64 == "" {
+ return "", nil
+ }
cData, err := fs.nameTransform.B64.DecodeString(cData64)
if err != nil {
return "", err
@@ -409,7 +413,11 @@ func (fs *FS) Unlink(path string, context *fuse.Context) (code fuse.Status) {
// encryptSymlinkTarget: "data" is encrypted like file contents (GCM)
// and base64-encoded.
+// The empty string encrypts to the empty string.
func (fs *FS) encryptSymlinkTarget(data string) (cData64 string) {
+ if data == "" {
+ return ""
+ }
cData := fs.contentEnc.EncryptBlock([]byte(data), 0, nil)
cData64 = fs.nameTransform.B64.EncodeToString(cData)
return cData64
diff --git a/tests/xattr/xattr_integration_test.go b/tests/xattr/xattr_integration_test.go
index 1e081c2..58d62d9 100644
--- a/tests/xattr/xattr_integration_test.go
+++ b/tests/xattr/xattr_integration_test.go
@@ -66,6 +66,60 @@ func TestXattrSetGetRm(t *testing.T) {
}
}
+func TestXattrSetEmpty(t *testing.T) {
+ attr := "user.foo"
+ fn := test_helpers.DefaultPlainDir + "/TestXattrSetEmpty1"
+ err := ioutil.WriteFile(fn, nil, 0700)
+ if err != nil {
+ t.Fatalf("creating empty file failed: %v", err)
+ }
+ // Make sure it does not exist already
+ _, err = xattr.Get(fn, attr)
+ if err == nil {
+ t.Fatal("we should have got an error here")
+ }
+ // Set empty value
+ err = xattr.Set(fn, attr, nil)
+ if err != nil {
+ t.Fatal(err)
+ }
+ // Read back
+ val, err := xattr.Get(fn, attr)
+ if err != nil {
+ t.Fatal(err)
+ }
+ if len(val) != 0 {
+ t.Errorf("wrong length: want=0 have=%d", len(val))
+ }
+ // Overwrite empty value with something
+ val1 := []byte("xyz123")
+ err = xattr.Set(fn, attr, val1)
+ if err != nil {
+ t.Fatal(err)
+ }
+ // Read back
+ val2, err := xattr.Get(fn, attr)
+ if err != nil {
+ t.Fatal(err)
+ }
+ if !bytes.Equal(val1, val2) {
+ t.Fatalf("wrong readback value: %v != %v", val1, val2)
+ }
+ // Overwrite something with empty value
+ err = xattr.Set(fn, attr, nil)
+ if err != nil {
+ t.Fatal(err)
+ }
+ // Read back
+ val, err = xattr.Get(fn, attr)
+ if err != nil {
+ t.Fatal(err)
+ }
+ if len(val) != 0 {
+ t.Errorf("wrong length: want=0 have=%d", len(val2))
+ }
+}
+
func TestXattrList(t *testing.T) {
fn := test_helpers.DefaultPlainDir + "/TestXattrList"
err := ioutil.WriteFile(fn, nil, 0700)