From db778aae7db844e77b602816a4fd0aeab5d6857e Mon Sep 17 00:00:00 2001 From: Jakob Unterwurzacher Date: Sun, 25 Mar 2018 21:02:33 +0200 Subject: [PATCH] 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. --- internal/fusefrontend/fs.go | 8 ++++ tests/xattr/xattr_integration_test.go | 54 +++++++++++++++++++++++++++ 2 files changed, 62 insertions(+) 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)