From 81a6d3d4661161314846fcfc8933859f962d7420 Mon Sep 17 00:00:00 2001 From: Aaron Jacobs Date: Tue, 4 Aug 2015 08:24:16 +1000 Subject: [PATCH 01/17] Declared errorfs.FS and a factory. --- samples/errorfs/error_fs.go | 41 +++++++++++++++++++++++++++++++++++++ 1 file changed, 41 insertions(+) create mode 100644 samples/errorfs/error_fs.go diff --git a/samples/errorfs/error_fs.go b/samples/errorfs/error_fs.go new file mode 100644 index 0000000..6e1a2e1 --- /dev/null +++ b/samples/errorfs/error_fs.go @@ -0,0 +1,41 @@ +// Copyright 2015 Google Inc. All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package errorfs + +import ( + "reflect" + "syscall" + + "github.com/jacobsa/fuse/fuseutil" +) + +const FooContents = "xxxx" + +// A file system whose sole contents are a file named "foo" containing the +// string defined by FooContents. +// +// The file system can be configured to returned canned errors for particular +// operations using the method SetError. +type FS interface { + fuseutil.FileSystem + + // Cause the file system to return the supplied error for all future + // operations matching the supplied type. + SetError(t reflect.Type, err syscall.Errno) +} + +func New() (fs FS) { + panic("TODO") +} From 4df87deabd7028600a2f54fceac8e61ddbbaafb1 Mon Sep 17 00:00:00 2001 From: Aaron Jacobs Date: Tue, 4 Aug 2015 08:27:55 +1000 Subject: [PATCH 02/17] Added a test stub. --- samples/errorfs/error_fs.go | 6 ++-- samples/errorfs/error_fs_test.go | 61 ++++++++++++++++++++++++++++++++ 2 files changed, 65 insertions(+), 2 deletions(-) create mode 100644 samples/errorfs/error_fs_test.go diff --git a/samples/errorfs/error_fs.go b/samples/errorfs/error_fs.go index 6e1a2e1..8fe401c 100644 --- a/samples/errorfs/error_fs.go +++ b/samples/errorfs/error_fs.go @@ -15,6 +15,7 @@ package errorfs import ( + "errors" "reflect" "syscall" @@ -36,6 +37,7 @@ type FS interface { SetError(t reflect.Type, err syscall.Errno) } -func New() (fs FS) { - panic("TODO") +func New() (fs FS, err error) { + err = errors.New("TODO") + return } diff --git a/samples/errorfs/error_fs_test.go b/samples/errorfs/error_fs_test.go new file mode 100644 index 0000000..e4f45ef --- /dev/null +++ b/samples/errorfs/error_fs_test.go @@ -0,0 +1,61 @@ +// Copyright 2015 Google Inc. All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package errorfs_test + +import ( + "testing" + + "github.com/jacobsa/fuse/fuseutil" + "github.com/jacobsa/fuse/samples" + "github.com/jacobsa/fuse/samples/errorfs" + . "github.com/jacobsa/ogletest" +) + +func TestErrorFS(t *testing.T) { RunTests(t) } + +//////////////////////////////////////////////////////////////////////// +// Boilerplate +//////////////////////////////////////////////////////////////////////// + +type ErrorFSTest struct { + samples.SampleTest + fs errorfs.FS +} + +func init() { RegisterTestSuite(&ErrorFSTest{}) } + +var _ SetUpInterface = &ErrorFSTest{} +var _ TearDownInterface = &ErrorFSTest{} + +func (t *ErrorFSTest) SetUp(ti *TestInfo) { + var err error + + // Create the file system. + t.fs, err = errorfs.New() + AssertEq(nil, err) + + t.Server = fuseutil.NewFileSystemServer(t.fs) + + // Mount it. + t.SampleTest.SetUp(ti) +} + +//////////////////////////////////////////////////////////////////////// +// Tests +//////////////////////////////////////////////////////////////////////// + +func (t *ErrorFSTest) DoesFoo() { + AssertTrue(false, "TODO") +} From e1bfc5006b130c3244c2d34ebf0371c992a8af40 Mon Sep 17 00:00:00 2001 From: Aaron Jacobs Date: Tue, 4 Aug 2015 08:29:38 +1000 Subject: [PATCH 03/17] Added test names. --- samples/errorfs/error_fs_test.go | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/samples/errorfs/error_fs_test.go b/samples/errorfs/error_fs_test.go index e4f45ef..34d13e5 100644 --- a/samples/errorfs/error_fs_test.go +++ b/samples/errorfs/error_fs_test.go @@ -56,6 +56,18 @@ func (t *ErrorFSTest) SetUp(ti *TestInfo) { // Tests //////////////////////////////////////////////////////////////////////// -func (t *ErrorFSTest) DoesFoo() { +func (t *ErrorFSTest) OpenFile() { + AssertTrue(false, "TODO") +} + +func (t *ErrorFSTest) ReadFile() { + AssertTrue(false, "TODO") +} + +func (t *ErrorFSTest) OpenDir() { + AssertTrue(false, "TODO") +} + +func (t *ErrorFSTest) ReadDir() { AssertTrue(false, "TODO") } From 8aecb35541d7a883e800551c101593a3bc678733 Mon Sep 17 00:00:00 2001 From: Aaron Jacobs Date: Tue, 4 Aug 2015 08:31:51 +1000 Subject: [PATCH 04/17] ErrorFSTest.OpenFile --- samples/errorfs/error_fs_test.go | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/samples/errorfs/error_fs_test.go b/samples/errorfs/error_fs_test.go index 34d13e5..726ffa1 100644 --- a/samples/errorfs/error_fs_test.go +++ b/samples/errorfs/error_fs_test.go @@ -15,11 +15,17 @@ package errorfs_test import ( + "os" + "path" + "reflect" + "syscall" "testing" + "github.com/jacobsa/fuse/fuseops" "github.com/jacobsa/fuse/fuseutil" "github.com/jacobsa/fuse/samples" "github.com/jacobsa/fuse/samples/errorfs" + . "github.com/jacobsa/oglematchers" . "github.com/jacobsa/ogletest" ) @@ -57,7 +63,10 @@ func (t *ErrorFSTest) SetUp(ti *TestInfo) { //////////////////////////////////////////////////////////////////////// func (t *ErrorFSTest) OpenFile() { - AssertTrue(false, "TODO") + t.fs.SetError(reflect.TypeOf(&fuseops.OpenFileOp{}), syscall.EOWNERDEAD) + + _, err := os.Open(path.Join(t.Dir, "foo")) + ExpectThat(err, Error(HasSubstr("TODO"))) } func (t *ErrorFSTest) ReadFile() { From 978399a2685e32c0aa8a8c97234407d00687e1d0 Mon Sep 17 00:00:00 2001 From: Aaron Jacobs Date: Tue, 4 Aug 2015 08:35:59 +1000 Subject: [PATCH 05/17] errorFS.SetError --- samples/errorfs/error_fs.go | 26 ++++++++++++++++++++++++-- 1 file changed, 24 insertions(+), 2 deletions(-) diff --git a/samples/errorfs/error_fs.go b/samples/errorfs/error_fs.go index 8fe401c..e2f32f5 100644 --- a/samples/errorfs/error_fs.go +++ b/samples/errorfs/error_fs.go @@ -15,8 +15,8 @@ package errorfs import ( - "errors" "reflect" + "sync" "syscall" "github.com/jacobsa/fuse/fuseutil" @@ -38,6 +38,28 @@ type FS interface { } func New() (fs FS, err error) { - err = errors.New("TODO") + fs = &errorFS{ + errors: make(map[string]syscall.Errno), + } + return } + +type errorFS struct { + fuseutil.NotImplementedFileSystem + + mu sync.Mutex + + // Keys are reflect.Type.Name strings. + // + // GUARDED_BY(mu) + errors map[string]syscall.Errno +} + +// LOCKS_EXCLUDED(fs.mu) +func (fs *errorFS) SetError(t reflect.Type, err syscall.Errno) { + fs.mu.Lock() + defer fs.mu.Unlock() + + fs.errors[t.Name()] = err +} From c3601bff1c9d739e3d3422ef2e26a5cb3ff660e2 Mon Sep 17 00:00:00 2001 From: Aaron Jacobs Date: Tue, 4 Aug 2015 08:40:38 +1000 Subject: [PATCH 06/17] errorFS.GetInodeAttributes --- samples/errorfs/error_fs.go | 51 +++++++++++++++++++++++++++++++++++++ 1 file changed, 51 insertions(+) diff --git a/samples/errorfs/error_fs.go b/samples/errorfs/error_fs.go index e2f32f5..d9df677 100644 --- a/samples/errorfs/error_fs.go +++ b/samples/errorfs/error_fs.go @@ -15,15 +15,22 @@ package errorfs import ( + "fmt" + "os" "reflect" "sync" "syscall" + "golang.org/x/net/context" + + "github.com/jacobsa/fuse/fuseops" "github.com/jacobsa/fuse/fuseutil" ) const FooContents = "xxxx" +const fooInodeID = fuseops.RootInodeID + 1 + // A file system whose sole contents are a file named "foo" containing the // string defined by FooContents. // @@ -63,3 +70,47 @@ func (fs *errorFS) SetError(t reflect.Type, err syscall.Errno) { fs.errors[t.Name()] = err } + +// LOCKS_EXCLUDED(fs.mu) +func (fs *errorFS) transformError(op interface{}, err *error) bool { + fs.mu.Lock() + defer fs.mu.Unlock() + + var ok bool + *err, ok = fs.errors[reflect.TypeOf(op).Name()] + return ok +} + +//////////////////////////////////////////////////////////////////////// +// File system methods +//////////////////////////////////////////////////////////////////////// + +// LOCKS_EXCLUDED(fs.mu) +func (fs *errorFS) GetInodeAttributes( + ctx context.Context, + op *fuseops.GetInodeAttributesOp) (err error) { + if fs.transformError(op, &err) { + return + } + + // Figure out which inode the request is for. + switch { + case op.Inode == fuseops.RootInodeID: + op.Attributes = fuseops.InodeAttributes{ + Mode: os.ModeDir | 0777, + } + + case op.Inode == fooInodeID: + op.Attributes = fuseops.InodeAttributes{ + Nlink: 1, + Size: uint64(len(FooContents)), + Mode: 0444, + } + + default: + err = fmt.Errorf("Unknown inode: %d", op.Inode) + return + } + + return +} From c71b2cbf33326ca368ba774c9a4e9829695dd2af Mon Sep 17 00:00:00 2001 From: Aaron Jacobs Date: Tue, 4 Aug 2015 08:42:51 +1000 Subject: [PATCH 07/17] Fixed two bugs. --- samples/errorfs/error_fs.go | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/samples/errorfs/error_fs.go b/samples/errorfs/error_fs.go index d9df677..a5f4a73 100644 --- a/samples/errorfs/error_fs.go +++ b/samples/errorfs/error_fs.go @@ -46,7 +46,7 @@ type FS interface { func New() (fs FS, err error) { fs = &errorFS{ - errors: make(map[string]syscall.Errno), + errors: make(map[reflect.Type]syscall.Errno), } return @@ -57,10 +57,8 @@ type errorFS struct { mu sync.Mutex - // Keys are reflect.Type.Name strings. - // // GUARDED_BY(mu) - errors map[string]syscall.Errno + errors map[reflect.Type]syscall.Errno } // LOCKS_EXCLUDED(fs.mu) @@ -68,7 +66,7 @@ func (fs *errorFS) SetError(t reflect.Type, err syscall.Errno) { fs.mu.Lock() defer fs.mu.Unlock() - fs.errors[t.Name()] = err + fs.errors[t] = err } // LOCKS_EXCLUDED(fs.mu) @@ -76,9 +74,13 @@ func (fs *errorFS) transformError(op interface{}, err *error) bool { fs.mu.Lock() defer fs.mu.Unlock() - var ok bool - *err, ok = fs.errors[reflect.TypeOf(op).Name()] - return ok + cannedErr, ok := fs.errors[reflect.TypeOf(op)] + if ok { + *err = cannedErr + return true + } + + return false } //////////////////////////////////////////////////////////////////////// From 54db03b63d4d22ec67ce3a5c0c0918a315814df8 Mon Sep 17 00:00:00 2001 From: Aaron Jacobs Date: Tue, 4 Aug 2015 08:45:51 +1000 Subject: [PATCH 08/17] errorFS.LookUpInode --- samples/errorfs/error_fs.go | 32 +++++++++++++++++++++++++++----- 1 file changed, 27 insertions(+), 5 deletions(-) diff --git a/samples/errorfs/error_fs.go b/samples/errorfs/error_fs.go index a5f4a73..7c1a315 100644 --- a/samples/errorfs/error_fs.go +++ b/samples/errorfs/error_fs.go @@ -31,6 +31,12 @@ const FooContents = "xxxx" const fooInodeID = fuseops.RootInodeID + 1 +var fooAttrs = fuseops.InodeAttributes{ + Nlink: 1, + Size: uint64(len(FooContents)), + Mode: 0444, +} + // A file system whose sole contents are a file named "foo" containing the // string defined by FooContents. // @@ -103,11 +109,7 @@ func (fs *errorFS) GetInodeAttributes( } case op.Inode == fooInodeID: - op.Attributes = fuseops.InodeAttributes{ - Nlink: 1, - Size: uint64(len(FooContents)), - Mode: 0444, - } + op.Attributes = fooAttrs default: err = fmt.Errorf("Unknown inode: %d", op.Inode) @@ -116,3 +118,23 @@ func (fs *errorFS) GetInodeAttributes( return } + +// LOCKS_EXCLUDED(fs.mu) +func (fs *errorFS) LookUpInode( + ctx context.Context, + op *fuseops.LookUpInodeOp) (err error) { + if fs.transformError(op, &err) { + return + } + + // Is this a known inode? + if !(op.Parent == fuseops.RootInodeID && op.Name == "foo") { + err = syscall.ENOENT + return + } + + op.Entry.Child = fooInodeID + op.Entry.Attributes = fooAttrs + + return +} From 1ea2e8216595e04c7bf062a763a108ee9e8c6dd6 Mon Sep 17 00:00:00 2001 From: Aaron Jacobs Date: Tue, 4 Aug 2015 08:48:03 +1000 Subject: [PATCH 09/17] errorFS.OpenFile --- samples/errorfs/error_fs.go | 16 ++++++++++++++++ samples/errorfs/error_fs_test.go | 2 +- 2 files changed, 17 insertions(+), 1 deletion(-) diff --git a/samples/errorfs/error_fs.go b/samples/errorfs/error_fs.go index 7c1a315..db9e76f 100644 --- a/samples/errorfs/error_fs.go +++ b/samples/errorfs/error_fs.go @@ -138,3 +138,19 @@ func (fs *errorFS) LookUpInode( return } + +// LOCKS_EXCLUDED(fs.mu) +func (fs *errorFS) OpenFile( + ctx context.Context, + op *fuseops.OpenFileOp) (err error) { + if fs.transformError(op, &err) { + return + } + + if op.Inode != fooInodeID { + err = fmt.Errorf("Unsupported inode ID: %d", op.Inode) + return + } + + return +} diff --git a/samples/errorfs/error_fs_test.go b/samples/errorfs/error_fs_test.go index 726ffa1..85fb500 100644 --- a/samples/errorfs/error_fs_test.go +++ b/samples/errorfs/error_fs_test.go @@ -66,7 +66,7 @@ func (t *ErrorFSTest) OpenFile() { t.fs.SetError(reflect.TypeOf(&fuseops.OpenFileOp{}), syscall.EOWNERDEAD) _, err := os.Open(path.Join(t.Dir, "foo")) - ExpectThat(err, Error(HasSubstr("TODO"))) + ExpectThat(err, Error(MatchesRegexp("open.*: .*owner died"))) } func (t *ErrorFSTest) ReadFile() { From e5d377b5318eee2eaca98b529d093cb7a967d413 Mon Sep 17 00:00:00 2001 From: Aaron Jacobs Date: Tue, 4 Aug 2015 08:59:34 +1000 Subject: [PATCH 10/17] ErrorFSTest.ReadFile --- samples/errorfs/error_fs_test.go | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/samples/errorfs/error_fs_test.go b/samples/errorfs/error_fs_test.go index 85fb500..b8953d2 100644 --- a/samples/errorfs/error_fs_test.go +++ b/samples/errorfs/error_fs_test.go @@ -15,6 +15,7 @@ package errorfs_test import ( + "io/ioutil" "os" "path" "reflect" @@ -70,7 +71,15 @@ func (t *ErrorFSTest) OpenFile() { } func (t *ErrorFSTest) ReadFile() { - AssertTrue(false, "TODO") + t.fs.SetError(reflect.TypeOf(&fuseops.ReadFileOp{}), syscall.EOWNERDEAD) + + // Open + f, err := os.Open(path.Join(t.Dir, "foo")) + AssertEq(nil, err) + + // Read + _, err = ioutil.ReadAll(f) + ExpectThat(err, Error(MatchesRegexp("read.*: .*owner died"))) } func (t *ErrorFSTest) OpenDir() { From e6a4db9920bc47cd1ddbcb6a454a367d57d9f725 Mon Sep 17 00:00:00 2001 From: Aaron Jacobs Date: Tue, 4 Aug 2015 09:00:38 +1000 Subject: [PATCH 11/17] errorFS.ReadFile --- samples/errorfs/error_fs.go | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/samples/errorfs/error_fs.go b/samples/errorfs/error_fs.go index db9e76f..8f01f3e 100644 --- a/samples/errorfs/error_fs.go +++ b/samples/errorfs/error_fs.go @@ -154,3 +154,21 @@ func (fs *errorFS) OpenFile( return } + +// LOCKS_EXCLUDED(fs.mu) +func (fs *errorFS) ReadFile( + ctx context.Context, + op *fuseops.ReadFileOp) (err error) { + if fs.transformError(op, &err) { + return + } + + if op.Inode != fooInodeID || op.Offset != 0 { + err = fmt.Errorf("Unexpected request: %#v", op) + return + } + + op.BytesRead = copy(op.Dst, FooContents) + + return +} From e22f698dd31d154fe19a978f628c7dd69fc2e0f3 Mon Sep 17 00:00:00 2001 From: Aaron Jacobs Date: Tue, 4 Aug 2015 09:01:02 +1000 Subject: [PATCH 12/17] ErrorFSTest.OpenDir --- samples/errorfs/error_fs_test.go | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/samples/errorfs/error_fs_test.go b/samples/errorfs/error_fs_test.go index b8953d2..666c836 100644 --- a/samples/errorfs/error_fs_test.go +++ b/samples/errorfs/error_fs_test.go @@ -83,7 +83,10 @@ func (t *ErrorFSTest) ReadFile() { } func (t *ErrorFSTest) OpenDir() { - AssertTrue(false, "TODO") + t.fs.SetError(reflect.TypeOf(&fuseops.OpenDirOp{}), syscall.EOWNERDEAD) + + _, err := os.Open(t.Dir) + ExpectThat(err, Error(MatchesRegexp("open.*: .*owner died"))) } func (t *ErrorFSTest) ReadDir() { From 7943ab5bf4a3775f5d7e1c3552da5ad084e52c7f Mon Sep 17 00:00:00 2001 From: Aaron Jacobs Date: Tue, 4 Aug 2015 09:01:53 +1000 Subject: [PATCH 13/17] ErrorFSTest.ReadDir --- samples/errorfs/error_fs_test.go | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/samples/errorfs/error_fs_test.go b/samples/errorfs/error_fs_test.go index 666c836..063a44c 100644 --- a/samples/errorfs/error_fs_test.go +++ b/samples/errorfs/error_fs_test.go @@ -90,5 +90,13 @@ func (t *ErrorFSTest) OpenDir() { } func (t *ErrorFSTest) ReadDir() { - AssertTrue(false, "TODO") + t.fs.SetError(reflect.TypeOf(&fuseops.ReadDirOp{}), syscall.EOWNERDEAD) + + // Open + f, err := os.Open(t.Dir) + AssertEq(nil, err) + + // Read + _, err = f.Readdirnames(1) + ExpectThat(err, Error(MatchesRegexp("read.*: .*owner died"))) } From ad3a4634880e760fa7ce8f7a316b3daff63a0f07 Mon Sep 17 00:00:00 2001 From: Aaron Jacobs Date: Tue, 4 Aug 2015 09:03:22 +1000 Subject: [PATCH 14/17] Implemented dir methods. --- samples/errorfs/error_fs.go | 41 +++++++++++++++++++++++++++++++++++++ 1 file changed, 41 insertions(+) diff --git a/samples/errorfs/error_fs.go b/samples/errorfs/error_fs.go index 8f01f3e..359af08 100644 --- a/samples/errorfs/error_fs.go +++ b/samples/errorfs/error_fs.go @@ -172,3 +172,44 @@ func (fs *errorFS) ReadFile( return } + +// LOCKS_EXCLUDED(fs.mu) +func (fs *errorFS) OpenDir( + ctx context.Context, + op *fuseops.OpenDirOp) (err error) { + if fs.transformError(op, &err) { + return + } + + if op.Inode != fuseops.RootInodeID { + err = fmt.Errorf("Unsupported inode ID: %d", op.Inode) + return + } + + return +} + +// LOCKS_EXCLUDED(fs.mu) +func (fs *errorFS) ReadDir( + ctx context.Context, + op *fuseops.ReadDirOp) (err error) { + if fs.transformError(op, &err) { + return + } + + if op.Inode != fuseops.RootInodeID || op.Offset != 0 { + err = fmt.Errorf("Unexpected request: %#v", op) + return + } + + op.BytesRead = fuseutil.WriteDirent( + op.Dst, + fuseutil.Dirent{ + Offset: 0, + Inode: fooInodeID, + Name: "foo", + Type: fuseutil.DT_File, + }) + + return +} From 00b92df61c231bb4ce282188850d2efc45c0e34d Mon Sep 17 00:00:00 2001 From: Aaron Jacobs Date: Tue, 4 Aug 2015 02:19:21 +0000 Subject: [PATCH 15/17] Don't forget to close the opened files. --- samples/errorfs/error_fs_test.go | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/samples/errorfs/error_fs_test.go b/samples/errorfs/error_fs_test.go index 063a44c..9061388 100644 --- a/samples/errorfs/error_fs_test.go +++ b/samples/errorfs/error_fs_test.go @@ -66,7 +66,8 @@ func (t *ErrorFSTest) SetUp(ti *TestInfo) { func (t *ErrorFSTest) OpenFile() { t.fs.SetError(reflect.TypeOf(&fuseops.OpenFileOp{}), syscall.EOWNERDEAD) - _, err := os.Open(path.Join(t.Dir, "foo")) + f, err := os.Open(path.Join(t.Dir, "foo")) + defer f.Close() ExpectThat(err, Error(MatchesRegexp("open.*: .*owner died"))) } @@ -75,6 +76,7 @@ func (t *ErrorFSTest) ReadFile() { // Open f, err := os.Open(path.Join(t.Dir, "foo")) + defer f.Close() AssertEq(nil, err) // Read @@ -85,7 +87,8 @@ func (t *ErrorFSTest) ReadFile() { func (t *ErrorFSTest) OpenDir() { t.fs.SetError(reflect.TypeOf(&fuseops.OpenDirOp{}), syscall.EOWNERDEAD) - _, err := os.Open(t.Dir) + f, err := os.Open(t.Dir) + defer f.Close() ExpectThat(err, Error(MatchesRegexp("open.*: .*owner died"))) } @@ -94,6 +97,7 @@ func (t *ErrorFSTest) ReadDir() { // Open f, err := os.Open(t.Dir) + defer f.Close() AssertEq(nil, err) // Read From d205df31440fcfe807f6c8448b18f439912b2f74 Mon Sep 17 00:00:00 2001 From: Aaron Jacobs Date: Tue, 4 Aug 2015 12:21:34 +1000 Subject: [PATCH 16/17] Don't return long error responses to ReadDir and ReadFile. --- conversions.go | 18 ++++++++++++++---- 1 file changed, 14 insertions(+), 4 deletions(-) diff --git a/conversions.go b/conversions.go index 3c30d71..bc8470f 100644 --- a/conversions.go +++ b/conversions.go @@ -423,14 +423,24 @@ func (c *Connection) kernelResponse( h := m.OutHeader() h.Unique = fuseID - // Did the user return an error? Otherwise, fill in the rest of the response. + // If the user returned the error, fill in the error field of the outgoing + // message header. if opErr != nil { + m.OutHeader().Error = -int32(syscall.EIO) if errno, ok := opErr.(syscall.Errno); ok { m.OutHeader().Error = -int32(errno) - } else { - m.OutHeader().Error = -int32(syscall.EIO) } - } else { + + // Special case: for some types, convertInMessage grew the message in order + // to obtain a destination buffer. Make sure that we shrink back to just + // the header, because on OS X the kernel otherwise returns EINVAL when we + // attempt to write an error response with a length that extends beyond the + // header. + m.Shrink(uintptr(m.Len() - int(buffer.OutMessageInitialSize))) + } + + // Otherwise, fill in the rest of the response. + if opErr == nil { noResponse = c.kernelResponseForOp(m, op) } From 1e2d4abaf9df890afde03902e0bf12227267ef8a Mon Sep 17 00:00:00 2001 From: Aaron Jacobs Date: Tue, 4 Aug 2015 12:28:08 +1000 Subject: [PATCH 17/17] Don't send error responses to the kernel for forget and interrupt. It's not expecting them. --- conversions.go | 24 +++++++++++++++--------- 1 file changed, 15 insertions(+), 9 deletions(-) diff --git a/conversions.go b/conversions.go index bc8470f..a180884 100644 --- a/conversions.go +++ b/conversions.go @@ -423,6 +423,18 @@ func (c *Connection) kernelResponse( h := m.OutHeader() h.Unique = fuseID + // Special case: handle the ops for which the kernel expects no response. + // interruptOp . + switch op.(type) { + case *fuseops.ForgetInodeOp: + noResponse = true + return + + case *interruptOp: + noResponse = true + return + } + // If the user returned the error, fill in the error field of the outgoing // message header. if opErr != nil { @@ -441,7 +453,7 @@ func (c *Connection) kernelResponse( // Otherwise, fill in the rest of the response. if opErr == nil { - noResponse = c.kernelResponseForOp(m, op) + c.kernelResponseForOp(m, op) } h.Len = uint32(m.Len()) @@ -452,7 +464,7 @@ func (c *Connection) kernelResponse( // op. func (c *Connection) kernelResponseForOp( m *buffer.OutMessage, - op interface{}) (noResponse bool) { + op interface{}) { // Create the appropriate output message switch o := op.(type) { case *fuseops.LookUpInodeOp: @@ -474,9 +486,6 @@ func (c *Connection) kernelResponseForOp( o.AttributesExpiration) convertAttributes(o.Inode, &o.Attributes, &out.Attr) - case *fuseops.ForgetInodeOp: - noResponse = true - case *fuseops.MkDirOp: size := fusekernel.EntryOutSize(c.protocol) out := (*fusekernel.EntryOut)(m.Grow(size)) @@ -551,9 +560,6 @@ func (c *Connection) kernelResponseForOp( case *statFSOp: m.Grow(unsafe.Sizeof(fusekernel.StatfsOut{})) - case *interruptOp: - noResponse = true - case *initOp: out := (*fusekernel.InitOut)(m.Grow(unsafe.Sizeof(fusekernel.InitOut{}))) @@ -564,7 +570,7 @@ func (c *Connection) kernelResponseForOp( out.MaxWrite = o.MaxWrite default: - panic(fmt.Sprintf("Unknown op: %#v", op)) + panic(fmt.Sprintf("Unexpected op: %#v", op)) } return