Commit 6551eff7 authored by Han-Wen Nienhuys's avatar Han-Wen Nienhuys

fuse/nodefs: support reading from and writing to Nodes directly.

parent ee39352d
...@@ -76,6 +76,11 @@ type Node interface { ...@@ -76,6 +76,11 @@ type Node interface {
// Create should return an open file, and the Inode for that file. // Create should return an open file, and the Inode for that file.
Create(name string, flags uint32, mode uint32, context *fuse.Context) (file File, child *Inode, code fuse.Status) Create(name string, flags uint32, mode uint32, context *fuse.Context) (file File, child *Inode, code fuse.Status)
// Open opens a file, and returns a File which is associated
// with a file handle. It is OK to return (nil, OK) here. In
// that case, the Node should implement Read or Write
// directly.
Open(flags uint32, context *fuse.Context) (file File, code fuse.Status) Open(flags uint32, context *fuse.Context) (file File, code fuse.Status)
OpenDir(context *fuse.Context) ([]fuse.DirEntry, fuse.Status) OpenDir(context *fuse.Context) ([]fuse.DirEntry, fuse.Status)
...@@ -86,6 +91,8 @@ type Node interface { ...@@ -86,6 +91,8 @@ type Node interface {
ListXAttr(context *fuse.Context) (attrs []string, code fuse.Status) ListXAttr(context *fuse.Context) (attrs []string, code fuse.Status)
// Attributes // Attributes
Read(file File, dest []byte, off int64, context *fuse.Context) (fuse.ReadResult, fuse.Status)
Write(file File, data []byte, off int64, context *fuse.Context) (written uint32, code fuse.Status)
GetAttr(out *fuse.Attr, file File, context *fuse.Context) (code fuse.Status) GetAttr(out *fuse.Attr, file File, context *fuse.Context) (code fuse.Status)
Chmod(file File, perms uint32, context *fuse.Context) (code fuse.Status) Chmod(file File, perms uint32, context *fuse.Context) (code fuse.Status)
Chown(file File, uid uint32, gid uint32, context *fuse.Context) (code fuse.Status) Chown(file File, uid uint32, gid uint32, context *fuse.Context) (code fuse.Status)
...@@ -96,7 +103,7 @@ type Node interface { ...@@ -96,7 +103,7 @@ type Node interface {
StatFs() *fuse.StatfsOut StatFs() *fuse.StatfsOut
} }
// A File object should be returned from FileSystem.Open and // A File object is returned from FileSystem.Open and
// FileSystem.Create. Include the NewDefaultFile return value into // FileSystem.Create. Include the NewDefaultFile return value into
// the struct to inherit a null implementation. // the struct to inherit a null implementation.
type File interface { type File interface {
......
...@@ -149,3 +149,17 @@ func (n *defaultNode) Utimens(file File, atime *time.Time, mtime *time.Time, con ...@@ -149,3 +149,17 @@ func (n *defaultNode) Utimens(file File, atime *time.Time, mtime *time.Time, con
func (n *defaultNode) Fallocate(file File, off uint64, size uint64, mode uint32, context *fuse.Context) (code fuse.Status) { func (n *defaultNode) Fallocate(file File, off uint64, size uint64, mode uint32, context *fuse.Context) (code fuse.Status) {
return fuse.ENOSYS return fuse.ENOSYS
} }
func (n *defaultNode) Read(file File, dest []byte, off int64, context *fuse.Context) (fuse.ReadResult, fuse.Status) {
if file != nil {
return file.Read(dest, off)
}
return nil, fuse.ENOSYS
}
func (n *defaultNode) Write(file File, data []byte, off int64, context *fuse.Context) (written uint32, code fuse.Status) {
if file != nil {
return file.Write(data, off)
}
return 0, fuse.ENOSYS
}
package nodefs
import (
"io/ioutil"
"testing"
"github.com/hanwen/go-fuse/fuse"
)
type nodeReadNode struct {
Node
data []byte
}
func newNodeReadNode(d []byte) *nodeReadNode {
return &nodeReadNode{NewDefaultNode(), d}
}
func (n *nodeReadNode) Open(flags uint32, context *fuse.Context) (file File, code fuse.Status) {
return nil, fuse.OK
}
func (n *nodeReadNode) Read(file File, dest []byte, off int64, context *fuse.Context) (fuse.ReadResult, fuse.Status) {
e := off + int64(len(dest))
if int(e) > len(n.data) {
e = int64(len(n.data))
}
return fuse.ReadResultData(n.data[off:int(e)]), fuse.OK
}
func (n *nodeReadNode) Lookup(out *fuse.Attr, name string, context *fuse.Context) (*Inode, fuse.Status) {
out.Mode = fuse.S_IFREG | 0644
out.Size = uint64(len(name))
ch := n.Inode().NewChild(name, false, newNodeReadNode([]byte(name)))
return ch, fuse.OK
}
func TestNodeRead(t *testing.T) {
dir, err := ioutil.TempDir("", "nodefs")
if err != nil {
t.Fatalf("TempDir: %v", err)
}
root := newNodeReadNode([]byte("root"))
s, _, err := MountRoot(dir, root, nil)
if err != nil {
t.Fatalf("MountRoot: %v", err)
}
s.SetDebug(true)
go s.Serve()
defer s.Unmount()
content, err := ioutil.ReadFile(dir + "/file")
if err != nil {
t.Fatalf("MountRoot: %v", err)
}
want := "file"
if string(content) != want {
t.Fatalf("got %q, want %q", content, want)
}
}
...@@ -75,8 +75,12 @@ func (m *fileSystemMount) fillAttr(out *fuse.AttrOut, nodeId uint64) { ...@@ -75,8 +75,12 @@ func (m *fileSystemMount) fillAttr(out *fuse.AttrOut, nodeId uint64) {
} }
func (m *fileSystemMount) getOpenedFile(h uint64) *openedFile { func (m *fileSystemMount) getOpenedFile(h uint64) *openedFile {
b := (*openedFile)(unsafe.Pointer(m.openFiles.Decode(h))) var b *openedFile
if m.connector.debug && b.WithFlags.Description != "" { if h != 0 {
b = (*openedFile)(unsafe.Pointer(m.openFiles.Decode(h)))
}
if b != nil && m.connector.debug && b.WithFlags.Description != "" {
log.Printf("File %d = %q", h, b.WithFlags.Description) log.Printf("File %d = %q", h, b.WithFlags.Description)
} }
return b return b
......
...@@ -164,7 +164,7 @@ func (c *rawBridge) ReadDirPlus(input *fuse.ReadIn, out *fuse.DirEntryList) fuse ...@@ -164,7 +164,7 @@ func (c *rawBridge) ReadDirPlus(input *fuse.ReadIn, out *fuse.DirEntryList) fuse
func (c *rawBridge) Open(input *fuse.OpenIn, out *fuse.OpenOut) (status fuse.Status) { func (c *rawBridge) Open(input *fuse.OpenIn, out *fuse.OpenOut) (status fuse.Status) {
node := c.toInode(input.NodeId) node := c.toInode(input.NodeId)
f, code := node.fsInode.Open(input.Flags, &input.Context) f, code := node.fsInode.Open(input.Flags, &input.Context)
if !code.Ok() { if !code.Ok() || f == nil {
return code return code
} }
h, opened := node.mount.registerFileHandle(node, nil, f, input.Flags) h, opened := node.mount.registerFileHandle(node, nil, f, input.Flags)
...@@ -344,14 +344,18 @@ func (c *rawBridge) Create(input *fuse.CreateIn, name string, out *fuse.CreateOu ...@@ -344,14 +344,18 @@ func (c *rawBridge) Create(input *fuse.CreateIn, name string, out *fuse.CreateOu
} }
func (c *rawBridge) Release(input *fuse.ReleaseIn) { func (c *rawBridge) Release(input *fuse.ReleaseIn) {
node := c.toInode(input.NodeId) if input.Fh != 0 {
opened := node.mount.unregisterFileHandle(input.Fh, node) node := c.toInode(input.NodeId)
opened.WithFlags.File.Release() opened := node.mount.unregisterFileHandle(input.Fh, node)
opened.WithFlags.File.Release()
}
} }
func (c *rawBridge) ReleaseDir(input *fuse.ReleaseIn) { func (c *rawBridge) ReleaseDir(input *fuse.ReleaseIn) {
node := c.toInode(input.NodeId) if input.Fh != 0 {
node.mount.unregisterFileHandle(input.Fh, node) node := c.toInode(input.NodeId)
node.mount.unregisterFileHandle(input.Fh, node)
}
} }
func (c *rawBridge) GetXAttrSize(header *fuse.InHeader, attribute string) (sz int, code fuse.Status) { func (c *rawBridge) GetXAttrSize(header *fuse.InHeader, attribute string) (sz int, code fuse.Status) {
...@@ -397,14 +401,25 @@ func (c *rawBridge) ListXAttr(header *fuse.InHeader) (data []byte, code fuse.Sta ...@@ -397,14 +401,25 @@ func (c *rawBridge) ListXAttr(header *fuse.InHeader) (data []byte, code fuse.Sta
func (c *rawBridge) Write(input *fuse.WriteIn, data []byte) (written uint32, code fuse.Status) { func (c *rawBridge) Write(input *fuse.WriteIn, data []byte) (written uint32, code fuse.Status) {
node := c.toInode(input.NodeId) node := c.toInode(input.NodeId)
opened := node.mount.getOpenedFile(input.Fh) opened := node.mount.getOpenedFile(input.Fh)
return opened.WithFlags.File.Write(data, int64(input.Offset))
var f File
if opened != nil {
f = opened.WithFlags.File
}
return node.Node().Write(f, data, int64(input.Offset), &input.Context)
} }
func (c *rawBridge) Read(input *fuse.ReadIn, buf []byte) (fuse.ReadResult, fuse.Status) { func (c *rawBridge) Read(input *fuse.ReadIn, buf []byte) (fuse.ReadResult, fuse.Status) {
node := c.toInode(input.NodeId) node := c.toInode(input.NodeId)
opened := node.mount.getOpenedFile(input.Fh) opened := node.mount.getOpenedFile(input.Fh)
return opened.WithFlags.File.Read(buf, int64(input.Offset)) var f File
if opened != nil {
f = opened.WithFlags.File
}
return node.Node().Read(f, buf, int64(input.Offset), &input.Context)
} }
func (c *rawBridge) StatFs(header *fuse.InHeader, out *fuse.StatfsOut) fuse.Status { func (c *rawBridge) StatFs(header *fuse.InHeader, out *fuse.StatfsOut) fuse.Status {
...@@ -420,5 +435,9 @@ func (c *rawBridge) StatFs(header *fuse.InHeader, out *fuse.StatfsOut) fuse.Stat ...@@ -420,5 +435,9 @@ func (c *rawBridge) StatFs(header *fuse.InHeader, out *fuse.StatfsOut) fuse.Stat
func (c *rawBridge) Flush(input *fuse.FlushIn) fuse.Status { func (c *rawBridge) Flush(input *fuse.FlushIn) fuse.Status {
node := c.toInode(input.NodeId) node := c.toInode(input.NodeId)
opened := node.mount.getOpenedFile(input.Fh) opened := node.mount.getOpenedFile(input.Fh)
return opened.WithFlags.File.Flush()
if opened != nil {
return opened.WithFlags.File.Flush()
}
return fuse.OK
} }
...@@ -719,3 +719,17 @@ func (n *pathInode) Fallocate(file nodefs.File, off uint64, size uint64, mode ui ...@@ -719,3 +719,17 @@ func (n *pathInode) Fallocate(file nodefs.File, off uint64, size uint64, mode ui
return code return code
} }
func (n *pathInode) Read(file nodefs.File, dest []byte, off int64, context *fuse.Context) (fuse.ReadResult, fuse.Status) {
if file != nil {
return file.Read(dest, off)
}
return nil, fuse.ENOSYS
}
func (n *pathInode) Write(file nodefs.File, data []byte, off int64, context *fuse.Context) (written uint32, code fuse.Status) {
if file != nil {
return file.Write(data, off)
}
return 0, fuse.ENOSYS
}
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment