diff --git a/ops.go b/ops.go index 578e59c..38a9d9e 100644 --- a/ops.go +++ b/ops.go @@ -15,7 +15,7 @@ package fuse import ( - "fmt" + "syscall" "unsafe" "github.com/jacobsa/fuse/fuseops" @@ -23,352 +23,126 @@ import ( "github.com/jacobsa/fuse/internal/fusekernel" ) -type opCommon struct { -} +// Given an op, return the response that should be sent to the kernel. If the +// op requires no response, return a nil response. If the op is unknown, return +// an error that should be sent to the kernel. +func kernelResponse( + untyped fuseops.Op, + protocol fusekernel.Protocol) (b buffer.OutMessage, err error) { + switch o := untyped.(type) { + case *fuseops.LookUpInodeOp: + size := fusekernel.EntryOutSize(protocol) + b = buffer.NewOutMessage(size) + out := (*fusekernel.EntryOut)(b.Grow(size)) + convertChildInodeEntry(&o.wrapped.Entry, out) -//////////////////////////////////////////////////////////////////////// -// Inodes -//////////////////////////////////////////////////////////////////////// + case *fuseops.GetInodeAttributesOp: + size := fusekernel.AttrOutSize(o.protocol) + b = buffer.NewOutMessage(size) + out := (*fusekernel.AttrOut)(b.Grow(size)) + out.AttrValid, out.AttrValidNsec = convertExpirationTime(o.AttributesExpiration) + convertAttributes(o.Inode, &o.Attributes, &out.Attr) -type lookUpInodeOp struct { - opCommon - wrapped fuseops.LookUpInodeOp -} + case *fuseops.SetInodeAttributesOp: + size := fusekernel.AttrOutSize(o.protocol) + b = buffer.NewOutMessage(size) + out := (*fusekernel.AttrOut)(b.Grow(size)) + out.AttrValid, out.AttrValidNsec = convertExpirationTime(o.AttributesExpiration) + convertAttributes(o.Inode, &o.Attributes, &out.Attr) -func (o *lookUpInodeOp) kernelResponse( - protocol fusekernel.Protocol) (b buffer.OutMessage) { - size := fusekernel.EntryOutSize(protocol) - b = buffer.NewOutMessage(size) - out := (*fusekernel.EntryOut)(b.Grow(size)) - convertChildInodeEntry(&o.wrapped.Entry, out) - - return -} - -type getInodeAttributesOp struct { - opCommon - wrapped fuseops.GetInodeAttributesOp -} - -func (o *getInodeAttributesOp) kernelResponse() (b buffer.OutMessage) { - size := fusekernel.AttrOutSize(o.protocol) - b = buffer.NewOutMessage(size) - out := (*fusekernel.AttrOut)(b.Grow(size)) - out.AttrValid, out.AttrValidNsec = convertExpirationTime(o.AttributesExpiration) - convertAttributes(o.Inode, &o.Attributes, &out.Attr) - - return -} - -type setInodeAttributesOp struct { - opCommon - wrapped fuseops.SetInodeAttributesOp -} - -func (o *setInodeAttributesOp) kernelResponse() (b buffer.OutMessage) { - size := fusekernel.AttrOutSize(o.protocol) - b = buffer.NewOutMessage(size) - out := (*fusekernel.AttrOut)(b.Grow(size)) - out.AttrValid, out.AttrValidNsec = convertExpirationTime(o.AttributesExpiration) - convertAttributes(o.Inode, &o.Attributes, &out.Attr) - - return -} - -type forgetInodeOp struct { - opCommon - wrapped fuseops.ForgetInodeOp -} - -func (o *forgetInodeOp) kernelResponse() (b buffer.OutMessage) { - // No response. - return -} - -//////////////////////////////////////////////////////////////////////// -// Inode creation -//////////////////////////////////////////////////////////////////////// - -type mkDirOp struct { - opCommon - wrapped fuseops.MkDirOp -} - -func (o *mkDirOp) kernelResponse() (b buffer.OutMessage) { - size := fusekernel.EntryOutSize(o.protocol) - b = buffer.NewOutMessage(size) - out := (*fusekernel.EntryOut)(b.Grow(size)) - convertChildInodeEntry(&o.Entry, out) - - return -} - -type createFileOp struct { - opCommon - wrapped fuseops.CreateFileOp -} - -func (o *createFileOp) kernelResponse() (b buffer.OutMessage) { - eSize := fusekernel.EntryOutSize(o.protocol) - b = buffer.NewOutMessage(eSize + unsafe.Sizeof(fusekernel.OpenOut{})) - - e := (*fusekernel.EntryOut)(b.Grow(eSize)) - convertChildInodeEntry(&o.Entry, e) - - oo := (*fusekernel.OpenOut)(b.Grow(unsafe.Sizeof(fusekernel.OpenOut{}))) - oo.Fh = uint64(o.Handle) - - return -} - -type createSymlinkOp struct { - opCommon - wrapped fuseops.CreateSymlinkOp -} - -func (o *createSymlinkOp) kernelResponse() (b buffer.OutMessage) { - size := fusekernel.EntryOutSize(o.protocol) - b = buffer.NewOutMessage(size) - out := (*fusekernel.EntryOut)(b.Grow(size)) - convertChildInodeEntry(&o.Entry, out) - - return -} - -//////////////////////////////////////////////////////////////////////// -// Unlinking -//////////////////////////////////////////////////////////////////////// - -type renameOp struct { - opCommon - wrapped fuseops.RenameOp -} - -func (o *renameOp) kernelResponse() (b buffer.OutMessage) { - b = buffer.NewOutMessage(0) - return -} - -type rmDirOp struct { - opCommon - wrapped fuseops.RmDirOp -} - -func (o *rmDirOp) kernelResponse() (b buffer.OutMessage) { - b = buffer.NewOutMessage(0) - return -} - -type unlinkOp struct { - opCommon - wrapped fuseops.UnlinkOp -} - -func (o *unlinkOp) kernelResponse() (b buffer.OutMessage) { - b = buffer.NewOutMessage(0) - return -} - -//////////////////////////////////////////////////////////////////////// -// Directory handles -//////////////////////////////////////////////////////////////////////// - -type openDirOp struct { - opCommon - wrapped fuseops.OpenDirOp -} - -func (o *openDirOp) kernelResponse() (b buffer.OutMessage) { - b = buffer.NewOutMessage(unsafe.Sizeof(fusekernel.OpenOut{})) - out := (*fusekernel.OpenOut)(b.Grow(unsafe.Sizeof(fusekernel.OpenOut{}))) - out.Fh = uint64(o.Handle) - - return -} - -type readDirOp struct { - opCommon - wrapped fuseops.ReadDirOp -} - -func (o *readDirOp) kernelResponse() (b buffer.OutMessage) { - b = buffer.NewOutMessage(uintptr(len(o.Data))) - b.Append(o.Data) - return -} - -type releaseDirHandleOp struct { - opCommon - wrapped fuseops.ReleaseDirHandleOp -} - -func (o *releaseDirHandleOp) kernelResponse() (b buffer.OutMessage) { - b = buffer.NewOutMessage(0) - return -} - -//////////////////////////////////////////////////////////////////////// -// File handles -//////////////////////////////////////////////////////////////////////// - -type openFileOp struct { - opCommon - wrapped fuseops.OpenFileOp -} - -func (o *openFileOp) kernelResponse() (b buffer.OutMessage) { - b = buffer.NewOutMessage(unsafe.Sizeof(fusekernel.OpenOut{})) - out := (*fusekernel.OpenOut)(b.Grow(unsafe.Sizeof(fusekernel.OpenOut{}))) - out.Fh = uint64(o.Handle) - - return -} - -type readFileOp struct { - opCommon - wrapped fuseops.ReadFileOp -} - -func (o *readFileOp) kernelResponse() (b buffer.OutMessage) { - b = buffer.NewOutMessage(uintptr(len(o.Data))) - b.Append(o.Data) - return -} - -type writeFileOp struct { - opCommon - wrapped fuseops.WriteFileOp -} - -func (o *writeFileOp) kernelResponse() (b buffer.OutMessage) { - b = buffer.NewOutMessage(unsafe.Sizeof(fusekernel.WriteOut{})) - out := (*fusekernel.WriteOut)(b.Grow(unsafe.Sizeof(fusekernel.WriteOut{}))) - out.Size = uint32(len(o.Data)) - - return -} - -type syncFileOp struct { - opCommon - wrapped fuseops.SyncFileOp -} - -func (o *syncFileOp) kernelResponse() (b buffer.OutMessage) { - b = buffer.NewOutMessage(0) - return -} - -type flushFileOp struct { - opCommon - wrapped fuseops.FlushFileOp -} - -func (o *flushFileOp) kernelResponse() (b buffer.OutMessage) { - b = buffer.NewOutMessage(0) - return -} - -type releaseFileHandleOp struct { - opCommon - wrapped fuseops.ReleaseFileHandleOp -} - -func (o *releaseFileHandleOp) kernelResponse() (b buffer.OutMessage) { - b = buffer.NewOutMessage(0) - return -} - -// A sentinel used for unknown ops. The user is expected to respond with a -// non-nil error. -type unknownOp struct { - opCommon - opCode uint32 - inode fuseops.InodeID -} - -func (o *unknownOp) ShortDesc() string { - return fmt.Sprintf("(inode=%d)", o.opCode, o.inode) -} - -func (o *unknownOp) DebugString() string { - return o.ShortDesc() -} - -func (o *unknownOp) kernelResponse() (b buffer.OutMessage) { - panic(fmt.Sprintf( - "Expected an error response for unknown op: %s", - o.ShortDesc())) -} - -//////////////////////////////////////////////////////////////////////// -// Reading symlinks -//////////////////////////////////////////////////////////////////////// - -type readSymlinkOp struct { - opCommon - wrapped fuseops.ReadSymlinkOp -} - -func (o *readSymlinkOp) kernelResponse() (b buffer.OutMessage) { - b = buffer.NewOutMessage(uintptr(len(o.Target))) - b.AppendString(o.Target) - return -} - -//////////////////////////////////////////////////////////////////////// -// Internal -//////////////////////////////////////////////////////////////////////// - -// Common implementation for our "internal" ops that don't need to be pretty. -type internalOp struct { - opCommon -} - -func (o *internalOp) ShortDesc() string { return "" } -func (o *internalOp) DebugString() string { return "" } - -type internalStatFSOp struct { - internalOp -} - -func (o *internalStatFSOp) kernelResponse() (b buffer.OutMessage) { - b = buffer.NewOutMessage(unsafe.Sizeof(fusekernel.StatfsOut{})) - b.Grow(unsafe.Sizeof(fusekernel.StatfsOut{})) - - return -} - -type internalInterruptOp struct { - internalOp - FuseID uint64 -} - -func (o *internalInterruptOp) kernelResponse() (b buffer.OutMessage) { - panic("Shouldn't get here.") -} - -type internalInitOp struct { - internalOp - - // In - Kernel fusekernel.Protocol - - // Out - Library fusekernel.Protocol - MaxReadahead uint32 - Flags fusekernel.InitFlags - MaxWrite uint32 -} - -func (o *internalInitOp) kernelResponse() (b buffer.OutMessage) { - b = buffer.NewOutMessage(unsafe.Sizeof(fusekernel.InitOut{})) - out := (*fusekernel.InitOut)(b.Grow(unsafe.Sizeof(fusekernel.InitOut{}))) - - out.Major = o.Library.Major - out.Minor = o.Library.Minor - out.MaxReadahead = o.MaxReadahead - out.Flags = uint32(o.Flags) - out.MaxWrite = o.MaxWrite + case *fuseops.ForgetInodeOp: + // No response. + + case *fuseops.MkDirOp: + size := fusekernel.EntryOutSize(o.protocol) + b = buffer.NewOutMessage(size) + out := (*fusekernel.EntryOut)(b.Grow(size)) + convertChildInodeEntry(&o.Entry, out) + + case *fuseops.CreateFileOp: + eSize := fusekernel.EntryOutSize(o.protocol) + b = buffer.NewOutMessage(eSize + unsafe.Sizeof(fusekernel.OpenOut{})) + + e := (*fusekernel.EntryOut)(b.Grow(eSize)) + convertChildInodeEntry(&o.Entry, e) + + oo := (*fusekernel.OpenOut)(b.Grow(unsafe.Sizeof(fusekernel.OpenOut{}))) + oo.Fh = uint64(o.Handle) + + case *fuseops.CreateSymlinkOp: + size := fusekernel.EntryOutSize(o.protocol) + b = buffer.NewOutMessage(size) + out := (*fusekernel.EntryOut)(b.Grow(size)) + convertChildInodeEntry(&o.Entry, out) + + case *fuseops.RenameOp: + b = buffer.NewOutMessage(0) + + case *fuseops.RmDirOp: + b = buffer.NewOutMessage(0) + + case *fuseops.UnlinkOp: + b = buffer.NewOutMessage(0) + + case *fuseops.OpenDirOp: + b = buffer.NewOutMessage(unsafe.Sizeof(fusekernel.OpenOut{})) + out := (*fusekernel.OpenOut)(b.Grow(unsafe.Sizeof(fusekernel.OpenOut{}))) + out.Fh = uint64(o.Handle) + + case *fuseops.ReadDirOp: + b = buffer.NewOutMessage(uintptr(len(o.Data))) + b.Append(o.Data) + + case *fuseops.ReleaseDirHandleOp: + b = buffer.NewOutMessage(0) + + case *fuseops.OpenFileOp: + b = buffer.NewOutMessage(unsafe.Sizeof(fusekernel.OpenOut{})) + out := (*fusekernel.OpenOut)(b.Grow(unsafe.Sizeof(fusekernel.OpenOut{}))) + out.Fh = uint64(o.Handle) + + case *fuseops.ReadFileOp: + b = buffer.NewOutMessage(uintptr(len(o.Data))) + b.Append(o.Data) + + case *fuseops.WriteFileOp: + b = buffer.NewOutMessage(unsafe.Sizeof(fusekernel.WriteOut{})) + out := (*fusekernel.WriteOut)(b.Grow(unsafe.Sizeof(fusekernel.WriteOut{}))) + out.Size = uint32(len(o.Data)) + + case *fuseops.SyncFileOp: + b = buffer.NewOutMessage(0) + + case *fuseops.FlushFileOp: + b = buffer.NewOutMessage(0) + + case *fuseops.ReleaseFileHandleOp: + b = buffer.NewOutMessage(0) + + case *fuseops.ReadSymlinkOp: + b = buffer.NewOutMessage(uintptr(len(o.Target))) + b.AppendString(o.Target) + + case *internalStatFSOp: + b = buffer.NewOutMessage(unsafe.Sizeof(fusekernel.StatfsOut{})) + b.Grow(unsafe.Sizeof(fusekernel.StatfsOut{})) + + case *internalInterruptOp: + // No response. + + case *internalInitOp: + b = buffer.NewOutMessage(unsafe.Sizeof(fusekernel.InitOut{})) + out := (*fusekernel.InitOut)(b.Grow(unsafe.Sizeof(fusekernel.InitOut{}))) + + out.Major = o.Library.Major + out.Minor = o.Library.Minor + out.MaxReadahead = o.MaxReadahead + out.Flags = uint32(o.Flags) + out.MaxWrite = o.MaxWrite + + default: + err = syscall.ENOSYS + } return }