diff options
| author | Jakob Unterwurzacher | 2018-03-25 21:02:33 +0200 | 
|---|---|---|
| committer | Jakob Unterwurzacher | 2018-03-25 21:06:10 +0200 | 
| commit | db778aae7db844e77b602816a4fd0aeab5d6857e (patch) | |
| tree | 1544087ce9fb32926a276781507c2604b366e113 | |
| parent | 1ed3d51df1750d5472b1349222c352171f1e8d64 (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.go | 8 | ||||
| -rw-r--r-- | tests/xattr/xattr_integration_test.go | 54 | 
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) | 
