diff --git a/fuseutil/file_system.go b/fuseutil/file_system.go index 49eb1a7..fb359cb 100644 --- a/fuseutil/file_system.go +++ b/fuseutil/file_system.go @@ -26,39 +26,67 @@ import ( // loop" that switches on op types, instead receiving typed method calls // directly. // -// Each method should fill in appropriate response fields for the supplied op -// and return an error status, but not call Repand. +// Each method is responsible for calling Respond on the supplied op. // // See NotImplementedFileSystem for a convenient way to embed default // implementations for methods you don't care about. type FileSystem interface { - Init(*fuseops.InitOp) error - LookUpInode(*fuseops.LookUpInodeOp) error - GetInodeAttributes(*fuseops.GetInodeAttributesOp) error - SetInodeAttributes(*fuseops.SetInodeAttributesOp) error - ForgetInode(*fuseops.ForgetInodeOp) error - MkDir(*fuseops.MkDirOp) error - CreateFile(*fuseops.CreateFileOp) error - RmDir(*fuseops.RmDirOp) error - Unlink(*fuseops.UnlinkOp) error - OpenDir(*fuseops.OpenDirOp) error - ReadDir(*fuseops.ReadDirOp) error - ReleaseDirHandle(*fuseops.ReleaseDirHandleOp) error - OpenFile(*fuseops.OpenFileOp) error - ReadFile(*fuseops.ReadFileOp) error - WriteFile(*fuseops.WriteFileOp) error - SyncFile(*fuseops.SyncFileOp) error - FlushFile(*fuseops.FlushFileOp) error - ReleaseFileHandle(*fuseops.ReleaseFileHandleOp) error + Init(*fuseops.InitOp) + LookUpInode(*fuseops.LookUpInodeOp) + GetInodeAttributes(*fuseops.GetInodeAttributesOp) + SetInodeAttributes(*fuseops.SetInodeAttributesOp) + ForgetInode(*fuseops.ForgetInodeOp) + MkDir(*fuseops.MkDirOp) + CreateFile(*fuseops.CreateFileOp) + RmDir(*fuseops.RmDirOp) + Unlink(*fuseops.UnlinkOp) + OpenDir(*fuseops.OpenDirOp) + ReadDir(*fuseops.ReadDirOp) + ReleaseDirHandle(*fuseops.ReleaseDirHandleOp) + OpenFile(*fuseops.OpenFileOp) + ReadFile(*fuseops.ReadFileOp) + WriteFile(*fuseops.WriteFileOp) + SyncFile(*fuseops.SyncFileOp) + FlushFile(*fuseops.FlushFileOp) + ReleaseFileHandle(*fuseops.ReleaseFileHandleOp) } -// Create a fuse.Server that serves ops by calling the associated FileSystem -// method and then calling Op.Respond with the resulting error. Unsupported ops -// are responded to directly with ENOSYS. +// Create a fuse.Server that handles ops by calling the associated FileSystem +// method.Respond with the resulting error. Unsupported ops are responded to +// directly with ENOSYS. +// +// FileSystem methods are called ine exactly the order of supported ops +// received by the connection, on a single goroutine. The methods should +// probably not block, instead continuing long-running operations in the +// background. Note however that there are subtleties here: for example, you +// probably want to serialize the order of write and flush operations. func NewFileSystemServer(fs FileSystem) fuse.Server { return fileSystemServer{fs} } +// A convenience function that makes it easy to ensure you respond to an +// operation when a FileSystem method returns. Responds to op with the current +// value of *err. +// +// For example: +// +// func (fs *myFS) ReadFile(op *fuseops.ReadFileOp) { +// var err error +// defer fuseutil.RespondToOp(op, &err) +// +// if err = fs.frobnicate(); err != nil { +// err = fmt.Errorf("frobnicate: %v", err) +// return +// } +// +// // Lots more manipulation of err, and return paths. +// // [...] +// } +// +func RespondToOp(op fuseops.Op, err *error) { + op.Respond(*err) +} + type fileSystemServer struct { fs FileSystem } @@ -79,58 +107,58 @@ func (s fileSystemServer) ServeOps(c *fuse.Connection) { op.Respond(fuse.ENOSYS) case *fuseops.InitOp: - op.Respond(s.fs.Init(typed)) + s.fs.Init(typed) case *fuseops.LookUpInodeOp: - op.Respond(s.fs.LookUpInode(typed)) + s.fs.LookUpInode(typed) case *fuseops.GetInodeAttributesOp: - op.Respond(s.fs.GetInodeAttributes(typed)) + s.fs.GetInodeAttributes(typed) case *fuseops.SetInodeAttributesOp: - op.Respond(s.fs.SetInodeAttributes(typed)) + s.fs.SetInodeAttributes(typed) case *fuseops.ForgetInodeOp: - op.Respond(s.fs.ForgetInode(typed)) + s.fs.ForgetInode(typed) case *fuseops.MkDirOp: - op.Respond(s.fs.MkDir(typed)) + s.fs.MkDir(typed) case *fuseops.CreateFileOp: - op.Respond(s.fs.CreateFile(typed)) + s.fs.CreateFile(typed) case *fuseops.RmDirOp: - op.Respond(s.fs.RmDir(typed)) + s.fs.RmDir(typed) case *fuseops.UnlinkOp: - op.Respond(s.fs.Unlink(typed)) + s.fs.Unlink(typed) case *fuseops.OpenDirOp: - op.Respond(s.fs.OpenDir(typed)) + s.fs.OpenDir(typed) case *fuseops.ReadDirOp: - op.Respond(s.fs.ReadDir(typed)) + s.fs.ReadDir(typed) case *fuseops.ReleaseDirHandleOp: - op.Respond(s.fs.ReleaseDirHandle(typed)) + s.fs.ReleaseDirHandle(typed) case *fuseops.OpenFileOp: - op.Respond(s.fs.OpenFile(typed)) + s.fs.OpenFile(typed) case *fuseops.ReadFileOp: - op.Respond(s.fs.ReadFile(typed)) + s.fs.ReadFile(typed) case *fuseops.WriteFileOp: - op.Respond(s.fs.WriteFile(typed)) + s.fs.WriteFile(typed) case *fuseops.SyncFileOp: - op.Respond(s.fs.SyncFile(typed)) + s.fs.SyncFile(typed) case *fuseops.FlushFileOp: - op.Respond(s.fs.FlushFile(typed)) + s.fs.FlushFile(typed) case *fuseops.ReleaseFileHandleOp: - op.Respond(s.fs.ReleaseFileHandle(typed)) + s.fs.ReleaseFileHandle(typed) } } } diff --git a/fuseutil/not_implemented_file_system.go b/fuseutil/not_implemented_file_system.go index 57fd78b..feb17dd 100644 --- a/fuseutil/not_implemented_file_system.go +++ b/fuseutil/not_implemented_file_system.go @@ -19,7 +19,7 @@ import ( "github.com/jacobsa/fuse/fuseops" ) -// A FileSystem that returns fuse.ENOSYS for all methods. Embed this in your +// A FileSystem that responds to all ops with fuse.ENOSYS. Embed this in your // struct to inherit default implementations for the methods you don't care // about, ensuring your struct will continue to implement FileSystem even as // new methods are added. @@ -29,91 +29,91 @@ type NotImplementedFileSystem struct { var _ FileSystem = &NotImplementedFileSystem{} func (fs *NotImplementedFileSystem) Init( - op *fuseops.InitOp) error { - return fuse.ENOSYS + op *fuseops.InitOp) { + op.Respond(fuse.ENOSYS) } func (fs *NotImplementedFileSystem) LookUpInode( - op *fuseops.LookUpInodeOp) error { - return fuse.ENOSYS + op *fuseops.LookUpInodeOp) { + op.Respond(fuse.ENOSYS) } func (fs *NotImplementedFileSystem) GetInodeAttributes( - op *fuseops.GetInodeAttributesOp) error { - return fuse.ENOSYS + op *fuseops.GetInodeAttributesOp) { + op.Respond(fuse.ENOSYS) } func (fs *NotImplementedFileSystem) SetInodeAttributes( - op *fuseops.SetInodeAttributesOp) error { - return fuse.ENOSYS + op *fuseops.SetInodeAttributesOp) { + op.Respond(fuse.ENOSYS) } func (fs *NotImplementedFileSystem) ForgetInode( - op *fuseops.ForgetInodeOp) error { - return fuse.ENOSYS + op *fuseops.ForgetInodeOp) { + op.Respond(fuse.ENOSYS) } func (fs *NotImplementedFileSystem) MkDir( - op *fuseops.MkDirOp) error { - return fuse.ENOSYS + op *fuseops.MkDirOp) { + op.Respond(fuse.ENOSYS) } func (fs *NotImplementedFileSystem) CreateFile( - op *fuseops.CreateFileOp) error { - return fuse.ENOSYS + op *fuseops.CreateFileOp) { + op.Respond(fuse.ENOSYS) } func (fs *NotImplementedFileSystem) RmDir( - op *fuseops.RmDirOp) error { - return fuse.ENOSYS + op *fuseops.RmDirOp) { + op.Respond(fuse.ENOSYS) } func (fs *NotImplementedFileSystem) Unlink( - op *fuseops.UnlinkOp) error { - return fuse.ENOSYS + op *fuseops.UnlinkOp) { + op.Respond(fuse.ENOSYS) } func (fs *NotImplementedFileSystem) OpenDir( - op *fuseops.OpenDirOp) error { - return fuse.ENOSYS + op *fuseops.OpenDirOp) { + op.Respond(fuse.ENOSYS) } func (fs *NotImplementedFileSystem) ReadDir( - op *fuseops.ReadDirOp) error { - return fuse.ENOSYS + op *fuseops.ReadDirOp) { + op.Respond(fuse.ENOSYS) } func (fs *NotImplementedFileSystem) ReleaseDirHandle( - op *fuseops.ReleaseDirHandleOp) error { - return fuse.ENOSYS + op *fuseops.ReleaseDirHandleOp) { + op.Respond(fuse.ENOSYS) } func (fs *NotImplementedFileSystem) OpenFile( - op *fuseops.OpenFileOp) error { - return fuse.ENOSYS + op *fuseops.OpenFileOp) { + op.Respond(fuse.ENOSYS) } func (fs *NotImplementedFileSystem) ReadFile( - op *fuseops.ReadFileOp) error { - return fuse.ENOSYS + op *fuseops.ReadFileOp) { + op.Respond(fuse.ENOSYS) } func (fs *NotImplementedFileSystem) WriteFile( - op *fuseops.WriteFileOp) error { - return fuse.ENOSYS + op *fuseops.WriteFileOp) { + op.Respond(fuse.ENOSYS) } func (fs *NotImplementedFileSystem) SyncFile( - op *fuseops.SyncFileOp) error { - return fuse.ENOSYS + op *fuseops.SyncFileOp) { + op.Respond(fuse.ENOSYS) } func (fs *NotImplementedFileSystem) FlushFile( - op *fuseops.FlushFileOp) error { - return fuse.ENOSYS + op *fuseops.FlushFileOp) { + op.Respond(fuse.ENOSYS) } func (fs *NotImplementedFileSystem) ReleaseFileHandle( - op *fuseops.ReleaseFileHandleOp) error { - return fuse.ENOSYS + op *fuseops.ReleaseFileHandleOp) { + op.Respond(fuse.ENOSYS) } diff --git a/samples/cachingfs/caching_fs.go b/samples/cachingfs/caching_fs.go index c3f6c0f..d2b0224 100644 --- a/samples/cachingfs/caching_fs.go +++ b/samples/cachingfs/caching_fs.go @@ -239,13 +239,19 @@ func (fs *cachingFS) SetMtime(mtime time.Time) { //////////////////////////////////////////////////////////////////////// func (fs *cachingFS) Init( - op *fuseops.InitOp) (err error) { + op *fuseops.InitOp) { + var err error + defer fuseutil.RespondToOp(op, &err) + return } // LOCKS_EXCLUDED(fs.mu) func (fs *cachingFS) LookUpInode( - op *fuseops.LookUpInodeOp) (err error) { + op *fuseops.LookUpInodeOp) { + var err error + defer fuseutil.RespondToOp(op, &err) + fs.mu.Lock() defer fs.mu.Unlock() @@ -299,7 +305,10 @@ func (fs *cachingFS) LookUpInode( // LOCKS_EXCLUDED(fs.mu) func (fs *cachingFS) GetInodeAttributes( - op *fuseops.GetInodeAttributesOp) (err error) { + op *fuseops.GetInodeAttributesOp) { + var err error + defer fuseutil.RespondToOp(op, &err) + fs.mu.Lock() defer fs.mu.Unlock() @@ -328,11 +337,17 @@ func (fs *cachingFS) GetInodeAttributes( } func (fs *cachingFS) OpenDir( - op *fuseops.OpenDirOp) (err error) { + op *fuseops.OpenDirOp) { + var err error + defer fuseutil.RespondToOp(op, &err) + return } func (fs *cachingFS) OpenFile( - op *fuseops.OpenFileOp) (err error) { + op *fuseops.OpenFileOp) { + var err error + defer fuseutil.RespondToOp(op, &err) + return } diff --git a/samples/flushfs/flush_fs.go b/samples/flushfs/flush_fs.go index fe0310c..e497e31 100644 --- a/samples/flushfs/flush_fs.go +++ b/samples/flushfs/flush_fs.go @@ -93,12 +93,18 @@ func (fs *flushFS) barAttributes() fuseops.InodeAttributes { //////////////////////////////////////////////////////////////////////// func (fs *flushFS) Init( - op *fuseops.InitOp) (err error) { + op *fuseops.InitOp) { + var err error + defer fuseutil.RespondToOp(op, &err) + return } func (fs *flushFS) LookUpInode( - op *fuseops.LookUpInodeOp) (err error) { + op *fuseops.LookUpInodeOp) { + var err error + defer fuseutil.RespondToOp(op, &err) + fs.mu.Lock() defer fs.mu.Unlock() @@ -131,7 +137,10 @@ func (fs *flushFS) LookUpInode( } func (fs *flushFS) GetInodeAttributes( - op *fuseops.GetInodeAttributesOp) (err error) { + op *fuseops.GetInodeAttributesOp) { + var err error + defer fuseutil.RespondToOp(op, &err) + fs.mu.Lock() defer fs.mu.Unlock() @@ -155,7 +164,10 @@ func (fs *flushFS) GetInodeAttributes( } func (fs *flushFS) OpenFile( - op *fuseops.OpenFileOp) (err error) { + op *fuseops.OpenFileOp) { + var err error + defer fuseutil.RespondToOp(op, &err) + fs.mu.Lock() defer fs.mu.Unlock() @@ -169,7 +181,10 @@ func (fs *flushFS) OpenFile( } func (fs *flushFS) ReadFile( - op *fuseops.ReadFileOp) (err error) { + op *fuseops.ReadFileOp) { + var err error + defer fuseutil.RespondToOp(op, &err) + fs.mu.Lock() defer fs.mu.Unlock() @@ -186,7 +201,10 @@ func (fs *flushFS) ReadFile( } func (fs *flushFS) WriteFile( - op *fuseops.WriteFileOp) (err error) { + op *fuseops.WriteFileOp) { + var err error + defer fuseutil.RespondToOp(op, &err) + fs.mu.Lock() defer fs.mu.Unlock() @@ -209,7 +227,10 @@ func (fs *flushFS) WriteFile( } func (fs *flushFS) SyncFile( - op *fuseops.SyncFileOp) (err error) { + op *fuseops.SyncFileOp) { + var err error + defer fuseutil.RespondToOp(op, &err) + fs.mu.Lock() defer fs.mu.Unlock() @@ -218,7 +239,10 @@ func (fs *flushFS) SyncFile( } func (fs *flushFS) FlushFile( - op *fuseops.FlushFileOp) (err error) { + op *fuseops.FlushFileOp) { + var err error + defer fuseutil.RespondToOp(op, &err) + fs.mu.Lock() defer fs.mu.Unlock() @@ -227,7 +251,10 @@ func (fs *flushFS) FlushFile( } func (fs *flushFS) OpenDir( - op *fuseops.OpenDirOp) (err error) { + op *fuseops.OpenDirOp) { + var err error + defer fuseutil.RespondToOp(op, &err) + fs.mu.Lock() defer fs.mu.Unlock() diff --git a/samples/hellofs/hello_fs.go b/samples/hellofs/hello_fs.go index f0722d5..d33769c 100644 --- a/samples/hellofs/hello_fs.go +++ b/samples/hellofs/hello_fs.go @@ -147,11 +147,17 @@ func (fs *helloFS) patchAttributes( attr.Crtime = now } -func (fs *helloFS) Init(op *fuseops.InitOp) (err error) { +func (fs *helloFS) Init(op *fuseops.InitOp) { + var err error + defer fuseutil.RespondToOp(op, &err) + return } -func (fs *helloFS) LookUpInode(op *fuseops.LookUpInodeOp) (err error) { +func (fs *helloFS) LookUpInode(op *fuseops.LookUpInodeOp) { + var err error + defer fuseutil.RespondToOp(op, &err) + // Find the info for the parent. parentInfo, ok := gInodeInfo[op.Parent] if !ok { @@ -176,7 +182,10 @@ func (fs *helloFS) LookUpInode(op *fuseops.LookUpInodeOp) (err error) { } func (fs *helloFS) GetInodeAttributes( - op *fuseops.GetInodeAttributesOp) (err error) { + op *fuseops.GetInodeAttributesOp) { + var err error + defer fuseutil.RespondToOp(op, &err) + // Find the info for this inode. info, ok := gInodeInfo[op.Inode] if !ok { @@ -194,13 +203,19 @@ func (fs *helloFS) GetInodeAttributes( } func (fs *helloFS) OpenDir( - op *fuseops.OpenDirOp) (err error) { + op *fuseops.OpenDirOp) { + var err error + defer fuseutil.RespondToOp(op, &err) + // Allow opening any directory. return } func (fs *helloFS) ReadDir( - op *fuseops.ReadDirOp) (err error) { + op *fuseops.ReadDirOp) { + var err error + defer fuseutil.RespondToOp(op, &err) + // Find the info for this inode. info, ok := gInodeInfo[op.Inode] if !ok { @@ -236,13 +251,19 @@ func (fs *helloFS) ReadDir( } func (fs *helloFS) OpenFile( - op *fuseops.OpenFileOp) (err error) { + op *fuseops.OpenFileOp) { + var err error + defer fuseutil.RespondToOp(op, &err) + // Allow opening any file. return } func (fs *helloFS) ReadFile( - op *fuseops.ReadFileOp) (err error) { + op *fuseops.ReadFileOp) { + var err error + defer fuseutil.RespondToOp(op, &err) + // Let io.ReaderAt deal with the semantics. reader := strings.NewReader("Hello, world!") diff --git a/samples/memfs/fs.go b/samples/memfs/fs.go index 879c539..552b41b 100644 --- a/samples/memfs/fs.go +++ b/samples/memfs/fs.go @@ -200,12 +200,18 @@ func (fs *memFS) deallocateInode(id fuseops.InodeID) { //////////////////////////////////////////////////////////////////////// func (fs *memFS) Init( - op *fuseops.InitOp) (err error) { + op *fuseops.InitOp) { + var err error + defer fuseutil.RespondToOp(op, &err) + return } func (fs *memFS) LookUpInode( - op *fuseops.LookUpInodeOp) (err error) { + op *fuseops.LookUpInodeOp) { + var err error + defer fuseutil.RespondToOp(op, &err) + fs.mu.RLock() defer fs.mu.RUnlock() @@ -237,7 +243,10 @@ func (fs *memFS) LookUpInode( } func (fs *memFS) GetInodeAttributes( - op *fuseops.GetInodeAttributesOp) (err error) { + op *fuseops.GetInodeAttributesOp) { + var err error + defer fuseutil.RespondToOp(op, &err) + fs.mu.RLock() defer fs.mu.RUnlock() @@ -256,7 +265,10 @@ func (fs *memFS) GetInodeAttributes( } func (fs *memFS) SetInodeAttributes( - op *fuseops.SetInodeAttributesOp) (err error) { + op *fuseops.SetInodeAttributesOp) { + var err error + defer fuseutil.RespondToOp(op, &err) + fs.mu.RLock() defer fs.mu.RUnlock() @@ -278,7 +290,10 @@ func (fs *memFS) SetInodeAttributes( } func (fs *memFS) MkDir( - op *fuseops.MkDirOp) (err error) { + op *fuseops.MkDirOp) { + var err error + defer fuseutil.RespondToOp(op, &err) + fs.mu.Lock() defer fs.mu.Unlock() @@ -315,7 +330,10 @@ func (fs *memFS) MkDir( } func (fs *memFS) CreateFile( - op *fuseops.CreateFileOp) (err error) { + op *fuseops.CreateFileOp) { + var err error + defer fuseutil.RespondToOp(op, &err) + fs.mu.Lock() defer fs.mu.Unlock() @@ -359,7 +377,10 @@ func (fs *memFS) CreateFile( } func (fs *memFS) RmDir( - op *fuseops.RmDirOp) (err error) { + op *fuseops.RmDirOp) { + var err error + defer fuseutil.RespondToOp(op, &err) + fs.mu.Lock() defer fs.mu.Unlock() @@ -394,7 +415,10 @@ func (fs *memFS) RmDir( } func (fs *memFS) Unlink( - op *fuseops.UnlinkOp) (err error) { + op *fuseops.UnlinkOp) { + var err error + defer fuseutil.RespondToOp(op, &err) + fs.mu.Lock() defer fs.mu.Unlock() @@ -423,7 +447,10 @@ func (fs *memFS) Unlink( } func (fs *memFS) OpenDir( - op *fuseops.OpenDirOp) (err error) { + op *fuseops.OpenDirOp) { + var err error + defer fuseutil.RespondToOp(op, &err) + fs.mu.RLock() defer fs.mu.RUnlock() @@ -441,7 +468,10 @@ func (fs *memFS) OpenDir( } func (fs *memFS) ReadDir( - op *fuseops.ReadDirOp) (err error) { + op *fuseops.ReadDirOp) { + var err error + defer fuseutil.RespondToOp(op, &err) + fs.mu.RLock() defer fs.mu.RUnlock() @@ -460,7 +490,10 @@ func (fs *memFS) ReadDir( } func (fs *memFS) OpenFile( - op *fuseops.OpenFileOp) (err error) { + op *fuseops.OpenFileOp) { + var err error + defer fuseutil.RespondToOp(op, &err) + fs.mu.RLock() defer fs.mu.RUnlock() @@ -478,7 +511,10 @@ func (fs *memFS) OpenFile( } func (fs *memFS) ReadFile( - op *fuseops.ReadFileOp) (err error) { + op *fuseops.ReadFileOp) { + var err error + defer fuseutil.RespondToOp(op, &err) + fs.mu.RLock() defer fs.mu.RUnlock() @@ -500,7 +536,10 @@ func (fs *memFS) ReadFile( } func (fs *memFS) WriteFile( - op *fuseops.WriteFileOp) (err error) { + op *fuseops.WriteFileOp) { + var err error + defer fuseutil.RespondToOp(op, &err) + fs.mu.RLock() defer fs.mu.RUnlock()