diff options
author | Jakob Unterwurzacher | 2018-11-12 22:22:10 +0100 |
---|---|---|
committer | Jakob Unterwurzacher | 2019-01-01 16:24:25 +0100 |
commit | 60e7a0ca9f2a2bcf8a727f606db134d60e9a5e18 (patch) | |
tree | a318ec9b98f99313200a26edbce0ffab6b57582d | |
parent | 1d5500c3db3b4b1f5a5fbc49c7934d3665739a0a (diff) |
fusefrontend: xattr: fix hang on FIFOs
An Open() a fifo blocks until it is opened for writing.
This meant that xattr operations on FIFOs would block.
Pass O_NONBLOCK to fix that, and add a test.
-rw-r--r-- | internal/fusefrontend/xattr_linux.go | 5 | ||||
-rw-r--r-- | tests/xattr/xattr_integration_test.go | 58 |
2 files changed, 51 insertions, 12 deletions
diff --git a/internal/fusefrontend/xattr_linux.go b/internal/fusefrontend/xattr_linux.go index 915713d..a96a147 100644 --- a/internal/fusefrontend/xattr_linux.go +++ b/internal/fusefrontend/xattr_linux.go @@ -35,11 +35,12 @@ func procFd(fd int) string { // getFileFd calls fs.Open() on relative plaintext path "relPath" and returns // the resulting fusefrontend.*File along with the underlying fd. The caller -// MUST call file.Release() when done with the file. +// MUST call file.Release() when done with the file. The O_NONBLOCK flag is +// used to not block on FIFOs. // // Used by xattrGet() and friends. func (fs *FS) getFileFd(relPath string, context *fuse.Context) (*File, int, fuse.Status) { - fuseFile, status := fs.Open(relPath, syscall.O_RDONLY, context) + fuseFile, status := fs.Open(relPath, syscall.O_RDONLY|syscall.O_NONBLOCK, context) if !status.Ok() { return nil, -1, status } diff --git a/tests/xattr/xattr_integration_test.go b/tests/xattr/xattr_integration_test.go index 8e48399..5c402cc 100644 --- a/tests/xattr/xattr_integration_test.go +++ b/tests/xattr/xattr_integration_test.go @@ -49,37 +49,75 @@ func TestMain(m *testing.M) { os.Exit(r) } -func TestXattrSetGetRm(t *testing.T) { - attr := "user.foo" - fn := test_helpers.DefaultPlainDir + "/TestXattrSetGetRm" - err := ioutil.WriteFile(fn, nil, 0700) +func setGetRmList(fn string) error { + // List + list, err := xattr.LList(fn) if err != nil { - t.Fatalf("creating empty file failed: %v", err) + return err } + if len(list) > 0 { + return fmt.Errorf("Should have gotten empty result, got %v", list) + } + attr := "user.foo" // Set val1 := []byte("123456789") err = xattr.LSet(fn, attr, val1) if err != nil { - t.Fatal(err) + return err } // Read back val2, err := xattr.LGet(fn, attr) if err != nil { - t.Fatal(err) + return err } if !bytes.Equal(val1, val2) { - t.Fatalf("wrong readback value: %v != %v", val1, val2) + return fmt.Errorf("wrong readback value: %v != %v", val1, val2) } // Remove err = xattr.LRemove(fn, attr) if err != nil { - t.Fatal(err) + return err } // Read back val3, err := xattr.LGet(fn, attr) if err == nil { - t.Fatalf("attr is still there after deletion!? val3=%v", val3) + return fmt.Errorf("attr is still there after deletion!? val3=%v", val3) + } + // List + list, err = xattr.LList(fn) + if err != nil { + return err + } + if len(list) > 0 { + return fmt.Errorf("Should have gotten empty result, got %v", list) + } + return nil +} + +// Test xattr set, get, rm on a regular file. +func TestSetGetRmRegularFile(t *testing.T) { + fn := test_helpers.DefaultPlainDir + "/TestSetGetRmRegularFile" + err := ioutil.WriteFile(fn, nil, 0700) + if err != nil { + t.Fatalf("creating empty file failed: %v", err) + } + err = setGetRmList(fn) + if err != nil { + t.Error(err) + } +} + +// Test xattr set, get, rm on a fifo. This should not hang. +func TestSetGetRmFifo(t *testing.T) { + fn := test_helpers.DefaultPlainDir + "/TestSetGetRmFifo" + err := syscall.Mkfifo(fn, 0700) + if err != nil { + t.Fatalf("creating fifo failed: %v", err) } + // We expect to get EPERM, but we should not hang: + // $ setfattr -n user.foo -v XXXXX fifo + // setfattr: fifo: Operation not permitted + setGetRmList(fn) } func TestXattrSetEmpty(t *testing.T) { |