From bbc33f6317a1220595ec9cf081d48c08ad288a75 Mon Sep 17 00:00:00 2001 From: Aaron Jacobs Date: Tue, 24 Mar 2015 14:21:55 +1100 Subject: [PATCH 01/19] Defined the Op interface. --- fuseops/ops.go | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/fuseops/ops.go b/fuseops/ops.go index a337710..e54022e 100644 --- a/fuseops/ops.go +++ b/fuseops/ops.go @@ -22,8 +22,22 @@ import ( "time" "github.com/jacobsa/bazilfuse" + "golang.org/x/net/context" ) +type Op interface { + // A context that can be used for long-running operations. + Context() context.Context + + // Repond to the operation with the supplied error. If there is no error, set + // any necessary output fields and then call Respond(nil). + Respond(error) +} + +//////////////////////////////////////////////////////////////////////// +// Setup +//////////////////////////////////////////////////////////////////////// + // Sent once when mounting the file system. It must succeed in order for the // mount to succeed. type InitOp struct { From 28f009d41b5534f0865c1626272615bdb32ceab0 Mon Sep 17 00:00:00 2001 From: Aaron Jacobs Date: Tue, 24 Mar 2015 14:24:00 +1100 Subject: [PATCH 02/19] Declared a conversion interface. --- fuseops/convert.go | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) create mode 100644 fuseops/convert.go diff --git a/fuseops/convert.go b/fuseops/convert.go new file mode 100644 index 0000000..21e466d --- /dev/null +++ b/fuseops/convert.go @@ -0,0 +1,26 @@ +// 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 fuseops contains implementations of the fuse.Op interface that may +// be returned by fuse.Connection.ReadOp. See documentation in that package for +// more. +package fuseops + +import "github.com/jacobsa/bazilfuse" + +// Convert the supplied bazilfuse request struct to an Op. +// +// This function is an implementation detail of the fuse package, and must not +// be called by anyone else. +func Convert(h *bazilfuse.Header) Op From 73732d4425972243863303ea71a9b122a2d5ad7f Mon Sep 17 00:00:00 2001 From: Aaron Jacobs Date: Tue, 24 Mar 2015 14:36:44 +1100 Subject: [PATCH 03/19] Refactored and started on Convert. --- fuseops/convert.go | 38 ++++++++++++++++++++++++++++++++++-- fuseops/ops.go | 48 +++++++++++++--------------------------------- 2 files changed, 49 insertions(+), 37 deletions(-) diff --git a/fuseops/convert.go b/fuseops/convert.go index 21e466d..9c381eb 100644 --- a/fuseops/convert.go +++ b/fuseops/convert.go @@ -17,10 +17,44 @@ // more. package fuseops -import "github.com/jacobsa/bazilfuse" +import ( + "github.com/jacobsa/bazilfuse" + "golang.org/x/net/context" +) // Convert the supplied bazilfuse request struct to an Op. // // This function is an implementation detail of the fuse package, and must not // be called by anyone else. -func Convert(h *bazilfuse.Header) Op +func Convert(r bazilfuse.Request) (o Op) { + var co *commonOp + + switch r.(type) { + case *bazilfuse.InitRequest: + to := &InitOp{} + o = to + co = &to.commonOp + + default: + panic("TODO") + } + + co.init(r) + return +} + +// A helper for embedding common behavior. +type commonOp struct { + ctx context.Context + r bazilfuse.Request +} + +func (o *commonOp) init(r bazilfuse.Request) + +func (o *commonOp) Header() OpHeader + +func (o *commonOp) Context() context.Context { + return o.ctx +} + +func (o *commonOp) Respond(err error) diff --git a/fuseops/ops.go b/fuseops/ops.go index e54022e..bd8e7ea 100644 --- a/fuseops/ops.go +++ b/fuseops/ops.go @@ -26,6 +26,9 @@ import ( ) type Op interface { + // Return the fields common to all operations. + Header() OpHeader + // A context that can be used for long-running operations. Context() context.Context @@ -41,7 +44,16 @@ type Op interface { // Sent once when mounting the file system. It must succeed in order for the // mount to succeed. type InitOp struct { - Header OpHeader + commonOp +} + +func (o *InitOp) Respond(err error) { + if err != nil { + o.commonOp.Respond(err) + return + } + + o.r.(*bazilfuse.InitRequest).Respond(&bazilfuse.InitResponse{}) } //////////////////////////////////////////////////////////////////////// @@ -51,8 +63,6 @@ type InitOp struct { // Look up a child by name within a parent directory. The kernel sends this // when resolving user paths to dentry structs, which are then cached. type LookUpInodeOp struct { - Header OpHeader - // The ID of the directory inode to which the child belongs. Parent InodeID @@ -76,8 +86,6 @@ type LookUpInodeOp struct { // inode attributes is stale. This is controlled by the AttributesExpiration // field of ChildInodeEntry, etc. type GetInodeAttributesOp struct { - Header OpHeader - // The inode of interest. Inode InodeID @@ -93,8 +101,6 @@ type GetInodeAttributesOp struct { // The kernel sends this for obvious cases like chmod(2), and for less obvious // cases like ftrunctate(2). type SetInodeAttributesOp struct { - Header OpHeader - // The inode of interest. Inode InodeID @@ -114,8 +120,6 @@ type SetInodeAttributesOp struct { // Forget an inode ID previously issued (e.g. by LookUpInode or MkDir). The // kernel sends this when removing an inode from its internal caches. type ForgetInodeOp struct { - Header OpHeader - // The inode to be forgotten. The kernel guarantees that the node ID will not // be used in further calls to the file system (unless it is reissued by the // file system). @@ -134,8 +138,6 @@ type ForgetInodeOp struct { // http://goo.gl/FZpLu5). But volatile file systems and paranoid non-volatile // file systems should check for the reasons described below on CreateFile. type MkDirOp struct { - Header OpHeader - // The ID of parent directory inode within which to create the child. Parent InodeID @@ -161,8 +163,6 @@ type MkDirOp struct { // course particularly applies to file systems that are volatile from the // kernel's point of view. type CreateFileOp struct { - Header OpHeader - // The ID of parent directory inode within which to create the child file. Parent InodeID @@ -199,8 +199,6 @@ type CreateFileOp struct { // // Sample implementation in ext2: ext2_rmdir (http://goo.gl/B9QmFf) type RmDirOp struct { - Header OpHeader - // The ID of parent directory inode, and the name of the directory being // removed within it. Parent InodeID @@ -213,8 +211,6 @@ type RmDirOp struct { // // Sample implementation in ext2: ext2_unlink (http://goo.gl/hY6r6C) type UnlinkOp struct { - Header OpHeader - // The ID of parent directory inode, and the name of the file being removed // within it. Parent InodeID @@ -232,8 +228,6 @@ type UnlinkOp struct { // user-space process. On OS X it may not be sent for every open(2) (cf. // https://github.com/osxfuse/osxfuse/issues/199). type OpenDirOp struct { - Header OpHeader - // The ID of the inode to be opened. Inode InodeID @@ -253,8 +247,6 @@ type OpenDirOp struct { // Read entries from a directory previously opened with OpenDir. type ReadDirOp struct { - Header OpHeader - // The directory inode that we are reading, and the handle previously // returned by OpenDir when opening that inode. Inode InodeID @@ -348,8 +340,6 @@ type ReadDirOp struct { // The kernel guarantees that the handle ID will not be used in further ops // sent to the file system (unless it is reissued by the file system). type ReleaseDirHandleOp struct { - Header OpHeader - // The handle ID to be released. The kernel guarantees that this ID will not // be used in further calls to the file system (unless it is reissued by the // file system). @@ -367,8 +357,6 @@ type ReleaseDirHandleOp struct { // process. On OS X it may not be sent for every open(2) // (cf.https://github.com/osxfuse/osxfuse/issues/199). type OpenFileOp struct { - Header OpHeader - // The ID of the inode to be opened. Inode InodeID @@ -391,8 +379,6 @@ type OpenFileOp struct { // some reads may be served by the page cache. See notes on WriteFileOp for // more. type ReadFileOp struct { - Header OpHeader - // The file inode that we are reading, and the handle previously returned by // CreateFile or OpenFile when opening that inode. Inode InodeID @@ -443,8 +429,6 @@ type ReadFileOp struct { // flush request. // type WriteFileOp struct { - Header OpHeader - // The file inode that we are modifying, and the handle previously returned // by CreateFile or OpenFile when opening that inode. Inode InodeID @@ -498,8 +482,6 @@ type WriteFileOp struct { // See also: FlushFileOp, which may perform a similar function when closing a // file (but which is not used in "real" file systems). type SyncFileOp struct { - Header OpHeader - // The file and handle being sync'd. Inode InodeID Handle HandleID @@ -553,8 +535,6 @@ type SyncFileOp struct { // to at least schedule a real flush, and maybe do it immediately in order to // return any errors that occur. type FlushFileOp struct { - Header OpHeader - // The file and handle being flushed. Inode InodeID Handle HandleID @@ -567,8 +547,6 @@ type FlushFileOp struct { // The kernel guarantees that the handle ID will not be used in further calls // to the file system (unless it is reissued by the file system). type ReleaseFileHandleOp struct { - Header OpHeader - // The handle ID to be released. The kernel guarantees that this ID will not // be used in further calls to the file system (unless it is reissued by the // file system). From e4d3d0aa5663b2cd9c6161b660be007329468e35 Mon Sep 17 00:00:00 2001 From: Aaron Jacobs Date: Tue, 24 Mar 2015 14:38:18 +1100 Subject: [PATCH 04/19] Implemented missing functions. --- fuseops/convert.go | 21 ++++++++++++++++++--- 1 file changed, 18 insertions(+), 3 deletions(-) diff --git a/fuseops/convert.go b/fuseops/convert.go index 9c381eb..60b88f4 100644 --- a/fuseops/convert.go +++ b/fuseops/convert.go @@ -49,12 +49,27 @@ type commonOp struct { r bazilfuse.Request } -func (o *commonOp) init(r bazilfuse.Request) +func (o *commonOp) init(r bazilfuse.Request) { + o.ctx = context.Background() + o.r = r +} -func (o *commonOp) Header() OpHeader +func (o *commonOp) Header() OpHeader { + bh := o.r.Hdr() + return OpHeader{ + Uid: bh.Uid, + Gid: bh.Gid, + } +} func (o *commonOp) Context() context.Context { return o.ctx } -func (o *commonOp) Respond(err error) +func (o *commonOp) Respond(err error) { + if err != nil { + panic("Expect non-nil here.") + } + + o.r.RespondError(err) +} From 18d288f1d9a52ef103ab36145b54b4dd57caf6da Mon Sep 17 00:00:00 2001 From: Aaron Jacobs Date: Tue, 24 Mar 2015 14:38:57 +1100 Subject: [PATCH 05/19] Implemented the default case. --- fuseops/convert.go | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/fuseops/convert.go b/fuseops/convert.go index 60b88f4..270f834 100644 --- a/fuseops/convert.go +++ b/fuseops/convert.go @@ -36,7 +36,8 @@ func Convert(r bazilfuse.Request) (o Op) { co = &to.commonOp default: - panic("TODO") + co = &commonOp{} + o = co } co.init(r) From 2a6cbb7bd3ca4a9cc48d5cca307365a8deeb1d36 Mon Sep 17 00:00:00 2001 From: Aaron Jacobs Date: Tue, 24 Mar 2015 14:40:58 +1100 Subject: [PATCH 06/19] Added stubs for all types. --- fuseops/convert.go | 85 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 85 insertions(+) diff --git a/fuseops/convert.go b/fuseops/convert.go index 270f834..b2b6c4c 100644 --- a/fuseops/convert.go +++ b/fuseops/convert.go @@ -35,6 +35,91 @@ func Convert(r bazilfuse.Request) (o Op) { o = to co = &to.commonOp + case *bazilfuse.InitRequest: + to := &LookUpInodeOp{} + o = to + co = &to.commonOp + + case *bazilfuse.InitRequest: + to := &GetInodeAttributesOp{} + o = to + co = &to.commonOp + + case *bazilfuse.InitRequest: + to := &SetInodeAttributesOp{} + o = to + co = &to.commonOp + + case *bazilfuse.InitRequest: + to := &ForgetInodeOp{} + o = to + co = &to.commonOp + + case *bazilfuse.InitRequest: + to := &MkDirOp{} + o = to + co = &to.commonOp + + case *bazilfuse.InitRequest: + to := &CreateFileOp{} + o = to + co = &to.commonOp + + case *bazilfuse.InitRequest: + to := &RmDirOp{} + o = to + co = &to.commonOp + + case *bazilfuse.InitRequest: + to := &UnlinkOp{} + o = to + co = &to.commonOp + + case *bazilfuse.InitRequest: + to := &OpenDirOp{} + o = to + co = &to.commonOp + + case *bazilfuse.InitRequest: + to := &ReadDirOp{} + o = to + co = &to.commonOp + + case *bazilfuse.InitRequest: + to := &ReleaseDirHandleOp{} + o = to + co = &to.commonOp + + case *bazilfuse.InitRequest: + to := &OpenFileOp{} + o = to + co = &to.commonOp + + case *bazilfuse.InitRequest: + to := &ReadFileOp{} + o = to + co = &to.commonOp + + case *bazilfuse.InitRequest: + to := &WriteFileOp{} + o = to + co = &to.commonOp + + case *bazilfuse.InitRequest: + to := &SyncFileOp{} + o = to + co = &to.commonOp + + case *bazilfuse.InitRequest: + to := &FlushFileOp{} + o = to + co = &to.commonOp + + case *bazilfuse.InitRequest: + to := &ReleaseFileHandleOp{} + o = to + co = &to.commonOp + default: co = &commonOp{} o = co From 2dfd8be1460cf675901695422744c48e4ec82305 Mon Sep 17 00:00:00 2001 From: Aaron Jacobs Date: Tue, 24 Mar 2015 14:41:51 +1100 Subject: [PATCH 07/19] Changed the contract. --- fuseops/convert.go | 8 ++++---- fuseops/ops.go | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/fuseops/convert.go b/fuseops/convert.go index b2b6c4c..27b9e62 100644 --- a/fuseops/convert.go +++ b/fuseops/convert.go @@ -22,7 +22,8 @@ import ( "golang.org/x/net/context" ) -// Convert the supplied bazilfuse request struct to an Op. +// Convert the supplied bazilfuse request struct to an Op, returning nil if it +// is unknown. // // This function is an implementation detail of the fuse package, and must not // be called by anyone else. @@ -121,8 +122,7 @@ func Convert(r bazilfuse.Request) (o Op) { co = &to.commonOp default: - co = &commonOp{} - o = co + return } co.init(r) @@ -152,7 +152,7 @@ func (o *commonOp) Context() context.Context { return o.ctx } -func (o *commonOp) Respond(err error) { +func (o *commonOp) respondErr(err error) { if err != nil { panic("Expect non-nil here.") } diff --git a/fuseops/ops.go b/fuseops/ops.go index bd8e7ea..6c628d9 100644 --- a/fuseops/ops.go +++ b/fuseops/ops.go @@ -49,7 +49,7 @@ type InitOp struct { func (o *InitOp) Respond(err error) { if err != nil { - o.commonOp.Respond(err) + o.commonOp.respondErr(err) return } From aba4e37d4097a4617212adc8bf5cb07418f5cfe2 Mon Sep 17 00:00:00 2001 From: Aaron Jacobs Date: Tue, 24 Mar 2015 14:45:35 +1100 Subject: [PATCH 08/19] Made everything an op. --- fuseops/ops.go | 187 +++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 187 insertions(+) diff --git a/fuseops/ops.go b/fuseops/ops.go index 6c628d9..e37e0b9 100644 --- a/fuseops/ops.go +++ b/fuseops/ops.go @@ -63,6 +63,8 @@ func (o *InitOp) Respond(err error) { // Look up a child by name within a parent directory. The kernel sends this // when resolving user paths to dentry structs, which are then cached. type LookUpInodeOp struct { + commonOp + // The ID of the directory inode to which the child belongs. Parent InodeID @@ -81,11 +83,22 @@ type LookUpInodeOp struct { Entry ChildInodeEntry } +func (o *LookUpInodeOp) Respond(err error) { + if err != nil { + o.commonOp.respondErr(err) + return + } + + panic("TODO") +} + // Refresh the attributes for an inode whose ID was previously returned in a // LookUpInodeOp. The kernel sends this when the FUSE VFS layer's cache of // inode attributes is stale. This is controlled by the AttributesExpiration // field of ChildInodeEntry, etc. type GetInodeAttributesOp struct { + commonOp + // The inode of interest. Inode InodeID @@ -96,11 +109,22 @@ type GetInodeAttributesOp struct { AttributesExpiration time.Time } +func (o *GetInodeAttributesOp) Respond(err error) { + if err != nil { + o.commonOp.respondErr(err) + return + } + + panic("TODO") +} + // Change attributes for an inode. // // The kernel sends this for obvious cases like chmod(2), and for less obvious // cases like ftrunctate(2). type SetInodeAttributesOp struct { + commonOp + // The inode of interest. Inode InodeID @@ -117,15 +141,35 @@ type SetInodeAttributesOp struct { AttributesExpiration time.Time } +func (o *SetInodeAttributesOp) Respond(err error) { + if err != nil { + o.commonOp.respondErr(err) + return + } + + panic("TODO") +} + // Forget an inode ID previously issued (e.g. by LookUpInode or MkDir). The // kernel sends this when removing an inode from its internal caches. type ForgetInodeOp struct { + commonOp + // The inode to be forgotten. The kernel guarantees that the node ID will not // be used in further calls to the file system (unless it is reissued by the // file system). ID InodeID } +func (o *ForgetInodeOp) Respond(err error) { + if err != nil { + o.commonOp.respondErr(err) + return + } + + panic("TODO") +} + //////////////////////////////////////////////////////////////////////// // Inode creation //////////////////////////////////////////////////////////////////////// @@ -138,6 +182,8 @@ type ForgetInodeOp struct { // http://goo.gl/FZpLu5). But volatile file systems and paranoid non-volatile // file systems should check for the reasons described below on CreateFile. type MkDirOp struct { + commonOp + // The ID of parent directory inode within which to create the child. Parent InodeID @@ -149,6 +195,15 @@ type MkDirOp struct { Entry ChildInodeEntry } +func (o *MkDirOp) Respond(err error) { + if err != nil { + o.commonOp.respondErr(err) + return + } + + panic("TODO") +} + // Create a file inode and open it. // // The kernel sends this when the user asks to open a file with the O_CREAT @@ -163,6 +218,8 @@ type MkDirOp struct { // course particularly applies to file systems that are volatile from the // kernel's point of view. type CreateFileOp struct { + commonOp + // The ID of parent directory inode within which to create the child file. Parent InodeID @@ -187,6 +244,15 @@ type CreateFileOp struct { Handle HandleID } +func (o *CreateFileOp) Respond(err error) { + if err != nil { + o.commonOp.respondErr(err) + return + } + + panic("TODO") +} + //////////////////////////////////////////////////////////////////////// // Unlinking //////////////////////////////////////////////////////////////////////// @@ -199,24 +265,46 @@ type CreateFileOp struct { // // Sample implementation in ext2: ext2_rmdir (http://goo.gl/B9QmFf) type RmDirOp struct { + commonOp + // The ID of parent directory inode, and the name of the directory being // removed within it. Parent InodeID Name string } +func (o *RmDirOp) Respond(err error) { + if err != nil { + o.commonOp.respondErr(err) + return + } + + panic("TODO") +} + // Unlink a file from its parent. If this brings the inode's link count to // zero, the inode should be deleted once the kernel sends ForgetInodeOp. It // may still be referenced before then if a user still has the file open. // // Sample implementation in ext2: ext2_unlink (http://goo.gl/hY6r6C) type UnlinkOp struct { + commonOp + // The ID of parent directory inode, and the name of the file being removed // within it. Parent InodeID Name string } +func (o *UnlinkOp) Respond(err error) { + if err != nil { + o.commonOp.respondErr(err) + return + } + + panic("TODO") +} + //////////////////////////////////////////////////////////////////////// // Directory handles //////////////////////////////////////////////////////////////////////// @@ -228,6 +316,8 @@ type UnlinkOp struct { // user-space process. On OS X it may not be sent for every open(2) (cf. // https://github.com/osxfuse/osxfuse/issues/199). type OpenDirOp struct { + commonOp + // The ID of the inode to be opened. Inode InodeID @@ -245,8 +335,19 @@ type OpenDirOp struct { Handle HandleID } +func (o *OpenDirOp) Respond(err error) { + if err != nil { + o.commonOp.respondErr(err) + return + } + + panic("TODO") +} + // Read entries from a directory previously opened with OpenDir. type ReadDirOp struct { + commonOp + // The directory inode that we are reading, and the handle previously // returned by OpenDir when opening that inode. Inode InodeID @@ -333,6 +434,15 @@ type ReadDirOp struct { Data []byte } +func (o *ReadDirOp) Respond(err error) { + if err != nil { + o.commonOp.respondErr(err) + return + } + + panic("TODO") +} + // Release a previously-minted directory handle. The kernel sends this when // there are no more references to an open directory: all file descriptors are // closed and all memory mappings are unmapped. @@ -340,12 +450,23 @@ type ReadDirOp struct { // The kernel guarantees that the handle ID will not be used in further ops // sent to the file system (unless it is reissued by the file system). type ReleaseDirHandleOp struct { + commonOp + // The handle ID to be released. The kernel guarantees that this ID will not // be used in further calls to the file system (unless it is reissued by the // file system). Handle HandleID } +func (o *ReleaseDirHandleOp) Respond(err error) { + if err != nil { + o.commonOp.respondErr(err) + return + } + + panic("TODO") +} + //////////////////////////////////////////////////////////////////////// // File handles //////////////////////////////////////////////////////////////////////// @@ -357,6 +478,8 @@ type ReleaseDirHandleOp struct { // process. On OS X it may not be sent for every open(2) // (cf.https://github.com/osxfuse/osxfuse/issues/199). type OpenFileOp struct { + commonOp + // The ID of the inode to be opened. Inode InodeID @@ -373,12 +496,23 @@ type OpenFileOp struct { Handle HandleID } +func (o *OpenFileOp) Respond(err error) { + if err != nil { + o.commonOp.respondErr(err) + return + } + + panic("TODO") +} + // Read data from a file previously opened with CreateFile or OpenFile. // // Note that this op is not sent for every call to read(2) by the end user; // some reads may be served by the page cache. See notes on WriteFileOp for // more. type ReadFileOp struct { + commonOp + // The file inode that we are reading, and the handle previously returned by // CreateFile or OpenFile when opening that inode. Inode InodeID @@ -400,6 +534,15 @@ type ReadFileOp struct { Data []byte } +func (o *ReadFileOp) Respond(err error) { + if err != nil { + o.commonOp.respondErr(err) + return + } + + panic("TODO") +} + // Write data to a file previously opened with CreateFile or OpenFile. // // When the user writes data using write(2), the write goes into the page @@ -429,6 +572,8 @@ type ReadFileOp struct { // flush request. // type WriteFileOp struct { + commonOp + // The file inode that we are modifying, and the handle previously returned // by CreateFile or OpenFile when opening that inode. Inode InodeID @@ -465,6 +610,15 @@ type WriteFileOp struct { Data []byte } +func (o *WriteFileOp) Respond(err error) { + if err != nil { + o.commonOp.respondErr(err) + return + } + + panic("TODO") +} + // Synchronize the current contents of an open file to storage. // // vfs.txt documents this as being called for by the fsync(2) system call @@ -482,11 +636,22 @@ type WriteFileOp struct { // See also: FlushFileOp, which may perform a similar function when closing a // file (but which is not used in "real" file systems). type SyncFileOp struct { + commonOp + // The file and handle being sync'd. Inode InodeID Handle HandleID } +func (o *SyncFileOp) Respond(err error) { + if err != nil { + o.commonOp.respondErr(err) + return + } + + panic("TODO") +} + // Flush the current state of an open file to storage upon closing a file // descriptor. // @@ -535,11 +700,22 @@ type SyncFileOp struct { // to at least schedule a real flush, and maybe do it immediately in order to // return any errors that occur. type FlushFileOp struct { + commonOp + // The file and handle being flushed. Inode InodeID Handle HandleID } +func (o *FlushFileOp) Respond(err error) { + if err != nil { + o.commonOp.respondErr(err) + return + } + + panic("TODO") +} + // Release a previously-minted file handle. The kernel calls this when there // are no more references to an open file: all file descriptors are closed // and all memory mappings are unmapped. @@ -547,8 +723,19 @@ type FlushFileOp struct { // The kernel guarantees that the handle ID will not be used in further calls // to the file system (unless it is reissued by the file system). type ReleaseFileHandleOp struct { + commonOp + // The handle ID to be released. The kernel guarantees that this ID will not // be used in further calls to the file system (unless it is reissued by the // file system). Handle HandleID } + +func (o *ReleaseFileHandleOp) Respond(err error) { + if err != nil { + o.commonOp.respondErr(err) + return + } + + panic("TODO") +} From ec64b2561c9051544a8505f6f22ab58b67fe9d21 Mon Sep 17 00:00:00 2001 From: Aaron Jacobs Date: Tue, 24 Mar 2015 14:46:31 +1100 Subject: [PATCH 09/19] Added helpful TODOs. --- fuseops/convert.go | 72 ++++++++++++++++++++++++++++++++++------------ 1 file changed, 54 insertions(+), 18 deletions(-) diff --git a/fuseops/convert.go b/fuseops/convert.go index 27b9e62..436244d 100644 --- a/fuseops/convert.go +++ b/fuseops/convert.go @@ -32,92 +32,128 @@ func Convert(r bazilfuse.Request) (o Op) { switch r.(type) { case *bazilfuse.InitRequest: - to := &InitOp{} + to := &InitOp{ + //TODO + } o = to co = &to.commonOp case *bazilfuse.InitRequest: - to := &LookUpInodeOp{} + to := &LookUpInodeOp{ + //TODO + } o = to co = &to.commonOp case *bazilfuse.InitRequest: - to := &GetInodeAttributesOp{} + to := &GetInodeAttributesOp{ + //TODO + } o = to co = &to.commonOp case *bazilfuse.InitRequest: - to := &SetInodeAttributesOp{} + to := &SetInodeAttributesOp{ + //TODO + } o = to co = &to.commonOp case *bazilfuse.InitRequest: - to := &ForgetInodeOp{} + to := &ForgetInodeOp{ + //TODO + } o = to co = &to.commonOp case *bazilfuse.InitRequest: - to := &MkDirOp{} + to := &MkDirOp{ + //TODO + } o = to co = &to.commonOp case *bazilfuse.InitRequest: - to := &CreateFileOp{} + to := &CreateFileOp{ + //TODO + } o = to co = &to.commonOp case *bazilfuse.InitRequest: - to := &RmDirOp{} + to := &RmDirOp{ + //TODO + } o = to co = &to.commonOp case *bazilfuse.InitRequest: - to := &UnlinkOp{} + to := &UnlinkOp{ + //TODO + } o = to co = &to.commonOp case *bazilfuse.InitRequest: - to := &OpenDirOp{} + to := &OpenDirOp{ + //TODO + } o = to co = &to.commonOp case *bazilfuse.InitRequest: - to := &ReadDirOp{} + to := &ReadDirOp{ + //TODO + } o = to co = &to.commonOp case *bazilfuse.InitRequest: - to := &ReleaseDirHandleOp{} + to := &ReleaseDirHandleOp{ + //TODO + } o = to co = &to.commonOp case *bazilfuse.InitRequest: - to := &OpenFileOp{} + to := &OpenFileOp{ + //TODO + } o = to co = &to.commonOp case *bazilfuse.InitRequest: - to := &ReadFileOp{} + to := &ReadFileOp{ + //TODO + } o = to co = &to.commonOp case *bazilfuse.InitRequest: - to := &WriteFileOp{} + to := &WriteFileOp{ + //TODO + } o = to co = &to.commonOp case *bazilfuse.InitRequest: - to := &SyncFileOp{} + to := &SyncFileOp{ + //TODO + } o = to co = &to.commonOp case *bazilfuse.InitRequest: - to := &FlushFileOp{} + to := &FlushFileOp{ + //TODO + } o = to co = &to.commonOp case *bazilfuse.InitRequest: - to := &ReleaseFileHandleOp{} + to := &ReleaseFileHandleOp{ + //TODO + } o = to co = &to.commonOp From 2167bec8a22102d93c136fd893a946e4f4b02791 Mon Sep 17 00:00:00 2001 From: Aaron Jacobs Date: Tue, 24 Mar 2015 14:48:19 +1100 Subject: [PATCH 10/19] Fixed switch cases. --- fuseops/convert.go | 75 ++++++++-------------------------------------- 1 file changed, 12 insertions(+), 63 deletions(-) diff --git a/fuseops/convert.go b/fuseops/convert.go index 436244d..75fa853 100644 --- a/fuseops/convert.go +++ b/fuseops/convert.go @@ -38,125 +38,74 @@ func Convert(r bazilfuse.Request) (o Op) { o = to co = &to.commonOp - case *bazilfuse.InitRequest: + case *bazilfuse.LookupRequest: to := &LookUpInodeOp{ //TODO } o = to co = &to.commonOp - case *bazilfuse.InitRequest: + case *bazilfuse.GetattrRequest: to := &GetInodeAttributesOp{ //TODO } o = to co = &to.commonOp - case *bazilfuse.InitRequest: + case *bazilfuse.SetattrRequest: to := &SetInodeAttributesOp{ //TODO } o = to co = &to.commonOp - case *bazilfuse.InitRequest: - to := &ForgetInodeOp{ - //TODO - } - o = to - co = &to.commonOp - - case *bazilfuse.InitRequest: + case *bazilfuse.MkdirRequest: to := &MkDirOp{ //TODO } o = to co = &to.commonOp - case *bazilfuse.InitRequest: + case *bazilfuse.CreateRequest: to := &CreateFileOp{ //TODO } o = to co = &to.commonOp - case *bazilfuse.InitRequest: - to := &RmDirOp{ + case *bazilfuse.RemoveRequest: //TODO - } - o = to - co = &to.commonOp - case *bazilfuse.InitRequest: - to := &UnlinkOp{ + case *bazilfuse.OpenRequest: //TODO - } - o = to - co = &to.commonOp - case *bazilfuse.InitRequest: - to := &OpenDirOp{ + case *bazilfuse.ReadRequest: //TODO - } - o = to - co = &to.commonOp - case *bazilfuse.InitRequest: - to := &ReadDirOp{ + case *bazilfuse.ReleaseRequest: //TODO - } - o = to - co = &to.commonOp - case *bazilfuse.InitRequest: - to := &ReleaseDirHandleOp{ - //TODO - } - o = to - co = &to.commonOp - - case *bazilfuse.InitRequest: - to := &OpenFileOp{ - //TODO - } - o = to - co = &to.commonOp - - case *bazilfuse.InitRequest: - to := &ReadFileOp{ - //TODO - } - o = to - co = &to.commonOp - - case *bazilfuse.InitRequest: + case *bazilfuse.WriteRequest: to := &WriteFileOp{ //TODO } o = to co = &to.commonOp - case *bazilfuse.InitRequest: + case *bazilfuse.FsyncRequest: to := &SyncFileOp{ //TODO } o = to co = &to.commonOp - case *bazilfuse.InitRequest: + case *bazilfuse.FlushRequest: to := &FlushFileOp{ //TODO } o = to co = &to.commonOp - case *bazilfuse.InitRequest: - to := &ReleaseFileHandleOp{ - //TODO - } - o = to - co = &to.commonOp - default: return } From 1cfd10be8751f47a33aea5c635fe3e459efbb8a3 Mon Sep 17 00:00:00 2001 From: Aaron Jacobs Date: Tue, 24 Mar 2015 14:48:42 +1100 Subject: [PATCH 11/19] Filled in LookUpInodeOp. --- fuseops/convert.go | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/fuseops/convert.go b/fuseops/convert.go index 75fa853..6454481 100644 --- a/fuseops/convert.go +++ b/fuseops/convert.go @@ -30,17 +30,16 @@ import ( func Convert(r bazilfuse.Request) (o Op) { var co *commonOp - switch r.(type) { + switch typed := r.(type) { case *bazilfuse.InitRequest: - to := &InitOp{ - //TODO - } + to := &InitOp{} o = to co = &to.commonOp case *bazilfuse.LookupRequest: to := &LookUpInodeOp{ - //TODO + Parent: InodeID(typed.Header.Node), + Name: typed.Name, } o = to co = &to.commonOp From e21d3254d43dfd02bf37500ad5285487f8dd7de6 Mon Sep 17 00:00:00 2001 From: Aaron Jacobs Date: Tue, 24 Mar 2015 14:49:27 +1100 Subject: [PATCH 12/19] Filled in more ops. --- fuseops/convert.go | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/fuseops/convert.go b/fuseops/convert.go index 6454481..b547aa8 100644 --- a/fuseops/convert.go +++ b/fuseops/convert.go @@ -46,28 +46,33 @@ func Convert(r bazilfuse.Request) (o Op) { case *bazilfuse.GetattrRequest: to := &GetInodeAttributesOp{ - //TODO + Inode: InodeID(typed.Header.Node), } o = to co = &to.commonOp case *bazilfuse.SetattrRequest: to := &SetInodeAttributesOp{ - //TODO + Inode: InodeID(typed.Header.Node), } o = to co = &to.commonOp case *bazilfuse.MkdirRequest: to := &MkDirOp{ - //TODO + Parent: InodeID(typed.Header.Node), + Name: typed.Name, + Mode: typed.Mode, } o = to co = &to.commonOp case *bazilfuse.CreateRequest: to := &CreateFileOp{ - //TODO + Parent: InodeID(typed.Header.Node), + Name: typed.Name, + Mode: typed.Mode, + Flags: typed.Flags, } o = to co = &to.commonOp From fe76354f67f62c80d9d605c0317f513013127c6c Mon Sep 17 00:00:00 2001 From: Aaron Jacobs Date: Tue, 24 Mar 2015 14:50:17 +1100 Subject: [PATCH 13/19] Filled in more ops. --- fuseops/convert.go | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) diff --git a/fuseops/convert.go b/fuseops/convert.go index b547aa8..81de9c0 100644 --- a/fuseops/convert.go +++ b/fuseops/convert.go @@ -91,21 +91,31 @@ func Convert(r bazilfuse.Request) (o Op) { case *bazilfuse.WriteRequest: to := &WriteFileOp{ - //TODO + Inode: InodeID(typed.Header.Node), + Handle: HandleID(typed.Handle), + Data: typed.Data, + Offset: typed.Offset, } o = to co = &to.commonOp case *bazilfuse.FsyncRequest: + // We don't currently support this for directories. + if typed.Dir { + return + } + to := &SyncFileOp{ - //TODO + Inode: InodeID(typed.Header.Node), + Handle: HandleID(typed.Handle), } o = to co = &to.commonOp case *bazilfuse.FlushRequest: to := &FlushFileOp{ - //TODO + Inode: InodeID(typed.Header.Node), + Handle: HandleID(typed.Handle), } o = to co = &to.commonOp From 505033377dc773018d8566193d9e02dfb8b0b59d Mon Sep 17 00:00:00 2001 From: Aaron Jacobs Date: Tue, 24 Mar 2015 14:51:07 +1100 Subject: [PATCH 14/19] Handle RemoveRequest. --- fuseops/convert.go | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/fuseops/convert.go b/fuseops/convert.go index 81de9c0..8ff0823 100644 --- a/fuseops/convert.go +++ b/fuseops/convert.go @@ -78,7 +78,21 @@ func Convert(r bazilfuse.Request) (o Op) { co = &to.commonOp case *bazilfuse.RemoveRequest: - //TODO + if typed.Dir { + to := &RmDirOp{ + Parent: InodeID(typed.Header.Node), + Name: typed.Name, + } + o = to + co = &to.commonOp + } else { + to := &UnlinkOp{ + Parent: InodeID(typed.Header.Node), + Name: typed.Name, + } + o = to + co = &to.commonOp + } case *bazilfuse.OpenRequest: //TODO From 537c4c3e0687c889b485e4eff552791dea09bbc7 Mon Sep 17 00:00:00 2001 From: Aaron Jacobs Date: Tue, 24 Mar 2015 14:56:41 +1100 Subject: [PATCH 15/19] Convert other types. --- fuseops/convert.go | 50 +++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 47 insertions(+), 3 deletions(-) diff --git a/fuseops/convert.go b/fuseops/convert.go index 8ff0823..743d0c0 100644 --- a/fuseops/convert.go +++ b/fuseops/convert.go @@ -95,13 +95,57 @@ func Convert(r bazilfuse.Request) (o Op) { } case *bazilfuse.OpenRequest: - //TODO + if typed.Dir { + to := &OpenDirOp{ + Inode: InodeID(typed.Header.Node), + Flags: typed.Flags, + } + o = to + co = &to.commonOp + } else { + to := &OpenFileOp{ + Inode: InodeID(typed.Header.Node), + Flags: typed.Flags, + } + o = to + co = &to.commonOp + } case *bazilfuse.ReadRequest: - //TODO + if typed.Dir { + to := &ReadDirOp{ + Inode: InodeID(typed.Header.Node), + Handle: HandleID(typed.Handle), + Offset: DirOffset(typed.Offset), + Size: typed.Size, + } + o = to + co = &to.commonOp + } else { + to := &ReadFileOp{ + Inode: InodeID(typed.Header.Node), + Handle: HandleID(typed.Handle), + Offset: typed.Offset, + Size: typed.Size, + } + o = to + co = &to.commonOp + } case *bazilfuse.ReleaseRequest: - //TODO + if typed.Dir { + to := &ReleaseDirHandleOp{ + Handle: HandleID(typed.Handle), + } + o = to + co = &to.commonOp + } else { + to := &ReadFileOp{ + Handle: HandleID(typed.Handle), + } + o = to + co = &to.commonOp + } case *bazilfuse.WriteRequest: to := &WriteFileOp{ From 9e25c19f66a05343555c8ce4851fe7794fdb8ac5 Mon Sep 17 00:00:00 2001 From: Aaron Jacobs Date: Tue, 24 Mar 2015 15:00:05 +1100 Subject: [PATCH 16/19] LookUpInodeOp.Respond --- fuseops/convert.go | 46 ++++++++++++++++++++++++++++++++++++++++++++++ fuseops/ops.go | 4 +++- 2 files changed, 49 insertions(+), 1 deletion(-) diff --git a/fuseops/convert.go b/fuseops/convert.go index 743d0c0..0b2b17b 100644 --- a/fuseops/convert.go +++ b/fuseops/convert.go @@ -18,6 +18,8 @@ package fuseops import ( + "time" + "github.com/jacobsa/bazilfuse" "golang.org/x/net/context" ) @@ -186,6 +188,50 @@ func Convert(r bazilfuse.Request) (o Op) { return } +func convertAttributes(inode InodeID, attr InodeAttributes) bazilfuse.Attr { + return bazilfuse.Attr{ + Inode: uint64(inode), + Size: attr.Size, + Mode: attr.Mode, + Nlink: uint32(attr.Nlink), + Atime: attr.Atime, + Mtime: attr.Mtime, + Ctime: attr.Ctime, + Crtime: attr.Crtime, + Uid: attr.Uid, + Gid: attr.Gid, + } +} + +// Convert an absolute cache expiration time to a relative time from now for +// consumption by fuse. +func convertExpirationTime(t time.Time) (d time.Duration) { + // Fuse represents durations as unsigned 64-bit counts of seconds and 32-bit + // counts of nanoseconds (cf. http://goo.gl/EJupJV). The bazil.org/fuse + // package converts time.Duration values to this form in a straightforward + // way (cf. http://goo.gl/FJhV8j). + // + // So negative durations are right out. There is no need to cap the positive + // magnitude, because 2^64 seconds is well longer than the 2^63 ns range of + // time.Duration. + d = t.Sub(time.Now()) + if d < 0 { + d = 0 + } + + return +} + +func convertChildInodeEntry( + in *ChildInodeEntry, + out *bazilfuse.LookupResponse) { + out.Node = bazilfuse.NodeID(in.Child) + out.Generation = uint64(in.Generation) + out.Attr = convertAttributes(in.Child, in.Attributes) + out.AttrValid = convertExpirationTime(in.AttributesExpiration) + out.EntryValid = convertExpirationTime(in.EntryExpiration) +} + // A helper for embedding common behavior. type commonOp struct { ctx context.Context diff --git a/fuseops/ops.go b/fuseops/ops.go index e37e0b9..29c6e99 100644 --- a/fuseops/ops.go +++ b/fuseops/ops.go @@ -89,7 +89,9 @@ func (o *LookUpInodeOp) Respond(err error) { return } - panic("TODO") + resp := bazilfuse.LookupResponse{} + convertChildInodeEntry(&o.Entry, &resp) + o.r.(*bazilfuse.LookupRequest).Respond(&resp) } // Refresh the attributes for an inode whose ID was previously returned in a From ccca7bbf356cbf867cda093f947e6d254066c844 Mon Sep 17 00:00:00 2001 From: Aaron Jacobs Date: Tue, 24 Mar 2015 15:00:59 +1100 Subject: [PATCH 17/19] GetInodeAttributesOp.Respond --- fuseops/ops.go | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/fuseops/ops.go b/fuseops/ops.go index 29c6e99..37ced1c 100644 --- a/fuseops/ops.go +++ b/fuseops/ops.go @@ -117,7 +117,12 @@ func (o *GetInodeAttributesOp) Respond(err error) { return } - panic("TODO") + resp := bazilfuse.GetattrResponse{ + Attr: convertAttributes(o.Inode, o.Attributes), + AttrValid: convertExpirationTime(o.AttributesExpiration), + } + + o.r.(*bazilfuse.GetattrRequest).Respond(&resp) } // Change attributes for an inode. From 630d02e199137a39e12e148147f087d6dffd39a1 Mon Sep 17 00:00:00 2001 From: Aaron Jacobs Date: Tue, 24 Mar 2015 15:02:27 +1100 Subject: [PATCH 18/19] More Respond methods. --- fuseops/ops.go | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/fuseops/ops.go b/fuseops/ops.go index 37ced1c..3d18f5a 100644 --- a/fuseops/ops.go +++ b/fuseops/ops.go @@ -154,7 +154,12 @@ func (o *SetInodeAttributesOp) Respond(err error) { return } - panic("TODO") + resp := bazilfuse.SetattrResponse{ + Attr: convertAttributes(o.Inode, o.Attributes), + AttrValid: convertExpirationTime(o.AttributesExpiration), + } + + o.r.(*bazilfuse.SetattrRequest).Respond(&resp) } // Forget an inode ID previously issued (e.g. by LookUpInode or MkDir). The @@ -174,7 +179,7 @@ func (o *ForgetInodeOp) Respond(err error) { return } - panic("TODO") + o.r.(*bazilfuse.ForgetRequest).Respond() } //////////////////////////////////////////////////////////////////////// @@ -208,7 +213,8 @@ func (o *MkDirOp) Respond(err error) { return } - panic("TODO") + resp := bazilfuse.MkdirResponse{} + o.r.(*bazilfuse.MkdirRequest).Respond(&resp) } // Create a file inode and open it. From 9952c9b462d305a4117e03a7b6ba7d673d9ade3d Mon Sep 17 00:00:00 2001 From: Aaron Jacobs Date: Tue, 24 Mar 2015 15:06:20 +1100 Subject: [PATCH 19/19] Finished Respond methods. --- fuseops/ops.go | 51 ++++++++++++++++++++++++++++++++++++++------------ 1 file changed, 39 insertions(+), 12 deletions(-) diff --git a/fuseops/ops.go b/fuseops/ops.go index 3d18f5a..8c020e1 100644 --- a/fuseops/ops.go +++ b/fuseops/ops.go @@ -263,7 +263,14 @@ func (o *CreateFileOp) Respond(err error) { return } - panic("TODO") + resp := bazilfuse.CreateResponse{ + OpenResponse: bazilfuse.OpenResponse{ + Handle: bazilfuse.HandleID(o.Handle), + }, + } + convertChildInodeEntry(&o.Entry, &resp.LookupResponse) + + o.r.(*bazilfuse.CreateRequest).Respond(&resp) } //////////////////////////////////////////////////////////////////////// @@ -292,7 +299,7 @@ func (o *RmDirOp) Respond(err error) { return } - panic("TODO") + o.r.(*bazilfuse.RemoveRequest).Respond() } // Unlink a file from its parent. If this brings the inode's link count to @@ -315,7 +322,7 @@ func (o *UnlinkOp) Respond(err error) { return } - panic("TODO") + o.r.(*bazilfuse.RemoveRequest).Respond() } //////////////////////////////////////////////////////////////////////// @@ -354,7 +361,11 @@ func (o *OpenDirOp) Respond(err error) { return } - panic("TODO") + resp := bazilfuse.OpenResponse{ + Handle: bazilfuse.HandleID(o.Handle), + } + + o.r.(*bazilfuse.OpenRequest).Respond(&resp) } // Read entries from a directory previously opened with OpenDir. @@ -453,7 +464,11 @@ func (o *ReadDirOp) Respond(err error) { return } - panic("TODO") + resp := bazilfuse.ReadResponse{ + Data: o.Data, + } + + o.r.(*bazilfuse.ReadRequest).Respond(&resp) } // Release a previously-minted directory handle. The kernel sends this when @@ -477,7 +492,7 @@ func (o *ReleaseDirHandleOp) Respond(err error) { return } - panic("TODO") + o.r.(*bazilfuse.ReleaseRequest).Respond() } //////////////////////////////////////////////////////////////////////// @@ -515,7 +530,11 @@ func (o *OpenFileOp) Respond(err error) { return } - panic("TODO") + resp := bazilfuse.OpenResponse{ + Handle: bazilfuse.HandleID(o.Handle), + } + + o.r.(*bazilfuse.OpenRequest).Respond(&resp) } // Read data from a file previously opened with CreateFile or OpenFile. @@ -553,7 +572,11 @@ func (o *ReadFileOp) Respond(err error) { return } - panic("TODO") + resp := bazilfuse.ReadResponse{ + Data: o.Data, + } + + o.r.(*bazilfuse.ReadRequest).Respond(&resp) } // Write data to a file previously opened with CreateFile or OpenFile. @@ -629,7 +652,11 @@ func (o *WriteFileOp) Respond(err error) { return } - panic("TODO") + resp := bazilfuse.WriteResponse{ + Size: len(o.Data), + } + + o.r.(*bazilfuse.WriteRequest).Respond(&resp) } // Synchronize the current contents of an open file to storage. @@ -662,7 +689,7 @@ func (o *SyncFileOp) Respond(err error) { return } - panic("TODO") + o.r.(*bazilfuse.FsyncRequest).Respond() } // Flush the current state of an open file to storage upon closing a file @@ -726,7 +753,7 @@ func (o *FlushFileOp) Respond(err error) { return } - panic("TODO") + o.r.(*bazilfuse.FlushRequest).Respond() } // Release a previously-minted file handle. The kernel calls this when there @@ -750,5 +777,5 @@ func (o *ReleaseFileHandleOp) Respond(err error) { return } - panic("TODO") + o.r.(*bazilfuse.ReleaseRequest).Respond() }