// Like kernelResponse, but assumes the user replied with a nil error to the // op. func (c *Connection) kernelResponseForOp( m *buffer.OutMessage, op interface{}) { // Create the appropriate output message switch o := op.(type) { case *fuseops.LookUpInodeOp: size := fusekernel.EntryOutSize(c.protocol) out := (*fusekernel.EntryOut)(m.Grow(size)) convertChildInodeEntry(&o.Entry, out) case *fuseops.GetInodeAttributesOp: size := fusekernel.AttrOutSize(c.protocol) out := (*fusekernel.AttrOut)(m.Grow(size)) out.AttrValid, out.AttrValidNsec = convertExpirationTime( o.AttributesExpiration) convertAttributes(o.Inode, &o.Attributes, &out.Attr) case *fuseops.SetInodeAttributesOp: size := fusekernel.AttrOutSize(c.protocol) out := (*fusekernel.AttrOut)(m.Grow(size)) out.AttrValid, out.AttrValidNsec = convertExpirationTime( o.AttributesExpiration) convertAttributes(o.Inode, &o.Attributes, &out.Attr) case *fuseops.MkDirOp: size := fusekernel.EntryOutSize(c.protocol) out := (*fusekernel.EntryOut)(m.Grow(size)) convertChildInodeEntry(&o.Entry, out) case *fuseops.CreateFileOp: eSize := fusekernel.EntryOutSize(c.protocol) e := (*fusekernel.EntryOut)(m.Grow(eSize)) convertChildInodeEntry(&o.Entry, e) oo := (*fusekernel.OpenOut)(m.Grow(unsafe.Sizeof(fusekernel.OpenOut{}))) oo.Fh = uint64(o.Handle) case *fuseops.CreateSymlinkOp: size := fusekernel.EntryOutSize(c.protocol) out := (*fusekernel.EntryOut)(m.Grow(size)) convertChildInodeEntry(&o.Entry, out) case *fuseops.RenameOp: // Empty response case *fuseops.RmDirOp: // Empty response case *fuseops.UnlinkOp: // Empty response case *fuseops.OpenDirOp: out := (*fusekernel.OpenOut)(m.Grow(unsafe.Sizeof(fusekernel.OpenOut{}))) out.Fh = uint64(o.Handle) case *fuseops.ReadDirOp: // convertInMessage already set up the destination buffer to be at the end // of the out message. We need only shrink to the right size based on how // much the user read. m.ShrinkTo(buffer.OutMessageInitialSize + uintptr(o.BytesRead)) case *fuseops.ReleaseDirHandleOp: // Empty response case *fuseops.OpenFileOp: out := (*fusekernel.OpenOut)(m.Grow(unsafe.Sizeof(fusekernel.OpenOut{}))) out.Fh = uint64(o.Handle) if o.KeepPageCache { out.OpenFlags |= uint32(fusekernel.OpenKeepCache) } case *fuseops.ReadFileOp: // convertInMessage already set up the destination buffer to be at the end // of the out message. We need only shrink to the right size based on how // much the user read. m.ShrinkTo(buffer.OutMessageInitialSize + uintptr(o.BytesRead)) case *fuseops.WriteFileOp: out := (*fusekernel.WriteOut)(m.Grow(unsafe.Sizeof(fusekernel.WriteOut{}))) out.Size = uint32(len(o.Data)) case *fuseops.SyncFileOp: // Empty response case *fuseops.FlushFileOp: // Empty response case *fuseops.ReleaseFileHandleOp: // Empty response case *fuseops.ReadSymlinkOp: m.AppendString(o.Target) case *statFSOp: m.Grow(unsafe.Sizeof(fusekernel.StatfsOut{})) case *initOp: out := (*fusekernel.InitOut)(m.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: panic(fmt.Sprintf("Unexpected op: %#v", op)) } return }
// Like kernelResponse, but assumes the user replied with a nil error to the // op. func (c *Connection) kernelResponseForOp( m *buffer.OutMessage, op interface{}) { // Create the appropriate output message switch o := op.(type) { case *fuseops.LookUpInodeOp: size := fusekernel.EntryOutSize(c.protocol) out := (*fusekernel.EntryOut)(m.Grow(size)) convertChildInodeEntry(&o.Entry, out) case *fuseops.GetInodeAttributesOp: size := fusekernel.AttrOutSize(c.protocol) out := (*fusekernel.AttrOut)(m.Grow(size)) out.AttrValid, out.AttrValidNsec = convertExpirationTime( o.AttributesExpiration) convertAttributes(o.Inode, &o.Attributes, &out.Attr) case *fuseops.SetInodeAttributesOp: size := fusekernel.AttrOutSize(c.protocol) out := (*fusekernel.AttrOut)(m.Grow(size)) out.AttrValid, out.AttrValidNsec = convertExpirationTime( o.AttributesExpiration) convertAttributes(o.Inode, &o.Attributes, &out.Attr) case *fuseops.MkDirOp: size := fusekernel.EntryOutSize(c.protocol) out := (*fusekernel.EntryOut)(m.Grow(size)) convertChildInodeEntry(&o.Entry, out) case *fuseops.CreateFileOp: eSize := fusekernel.EntryOutSize(c.protocol) e := (*fusekernel.EntryOut)(m.Grow(eSize)) convertChildInodeEntry(&o.Entry, e) oo := (*fusekernel.OpenOut)(m.Grow(unsafe.Sizeof(fusekernel.OpenOut{}))) oo.Fh = uint64(o.Handle) case *fuseops.CreateSymlinkOp: size := fusekernel.EntryOutSize(c.protocol) out := (*fusekernel.EntryOut)(m.Grow(size)) convertChildInodeEntry(&o.Entry, out) case *fuseops.RenameOp: // Empty response case *fuseops.RmDirOp: // Empty response case *fuseops.UnlinkOp: // Empty response case *fuseops.OpenDirOp: out := (*fusekernel.OpenOut)(m.Grow(unsafe.Sizeof(fusekernel.OpenOut{}))) out.Fh = uint64(o.Handle) case *fuseops.ReadDirOp: // convertInMessage already set up the destination buffer to be at the end // of the out message. We need only shrink to the right size based on how // much the user read. m.ShrinkTo(buffer.OutMessageInitialSize + uintptr(o.BytesRead)) case *fuseops.ReleaseDirHandleOp: // Empty response case *fuseops.OpenFileOp: out := (*fusekernel.OpenOut)(m.Grow(unsafe.Sizeof(fusekernel.OpenOut{}))) out.Fh = uint64(o.Handle) if o.KeepPageCache { out.OpenFlags |= uint32(fusekernel.OpenKeepCache) } case *fuseops.ReadFileOp: // convertInMessage already set up the destination buffer to be at the end // of the out message. We need only shrink to the right size based on how // much the user read. m.ShrinkTo(buffer.OutMessageInitialSize + uintptr(o.BytesRead)) case *fuseops.WriteFileOp: out := (*fusekernel.WriteOut)(m.Grow(unsafe.Sizeof(fusekernel.WriteOut{}))) out.Size = uint32(len(o.Data)) case *fuseops.SyncFileOp: // Empty response case *fuseops.FlushFileOp: // Empty response case *fuseops.ReleaseFileHandleOp: // Empty response case *fuseops.ReadSymlinkOp: m.AppendString(o.Target) case *fuseops.StatFSOp: out := (*fusekernel.StatfsOut)(m.Grow(unsafe.Sizeof(fusekernel.StatfsOut{}))) out.St.Blocks = o.Blocks out.St.Bfree = o.BlocksFree out.St.Bavail = o.BlocksAvailable out.St.Files = o.Inodes out.St.Ffree = o.InodesFree // The posix spec for sys/statvfs.h (http://goo.gl/LktgrF) defines the // following fields of statvfs, among others: // // f_bsize File system block size. // f_frsize Fundamental file system block size. // f_blocks Total number of blocks on file system in units of f_frsize. // // It appears as though f_bsize was the only thing supported by most unixes // originally, but then f_frsize was added when new sorts of file systems // came about. Quoth The Linux Programming Interface by Michael Kerrisk // (https://goo.gl/5LZMxQ): // // For most Linux file systems, the values of f_bsize and f_frsize are // the same. However, some file systems support the notion of block // fragments, which can be used to allocate a smaller unit of storage // at the end of the file if if a full block is not required. This // avoids the waste of space that would otherwise occur if a full block // was allocated. On such file systems, f_frsize is the size of a // fragment, and f_bsize is the size of a whole block. (The notion of // fragments in UNIX file systems first appeared in the early 1980s // with the 4.2BSD Fast File System.) // // Confusingly, it appears as though osxfuse surfaces fuse_kstatfs::bsize // as statfs::f_iosize (of advisory use only), and fuse_kstatfs::frsize as // statfs::f_bsize (which affects free space display in the Finder). out.St.Bsize = o.IoSize out.St.Frsize = o.BlockSize case *initOp: out := (*fusekernel.InitOut)(m.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: panic(fmt.Sprintf("Unexpected op: %#v", op)) } return }