Commit f73926e3 authored by Han-Wen Nienhuys's avatar Han-Wen Nienhuys

nodefs: don't pass root into Options.OnAdd

Add an example for constructing an in-memory file system
parent 1e3484e9
...@@ -453,5 +453,5 @@ type Options struct { ...@@ -453,5 +453,5 @@ type Options struct {
// OnAdd is an alternative way to specify the OnAdd // OnAdd is an alternative way to specify the OnAdd
// functionality of the root node. // functionality of the root node.
OnAdd func(ctx context.Context, root InodeEmbedder) OnAdd func(ctx context.Context)
} }
...@@ -188,7 +188,7 @@ func NewNodeFS(root InodeEmbedder, opts *Options) fuse.RawFileSystem { ...@@ -188,7 +188,7 @@ func NewNodeFS(root InodeEmbedder, opts *Options) fuse.RawFileSystem {
bridge.files = []*fileEntry{{}} bridge.files = []*fileEntry{{}}
if opts.OnAdd != nil { if opts.OnAdd != nil {
opts.OnAdd(context.Background(), root) opts.OnAdd(context.Background())
} else if oa, ok := root.(OnAdder); ok { } else if oa, ok := root.(OnAdder); ok {
oa.OnAdd(context.Background()) oa.OnAdd(context.Background())
} }
......
...@@ -38,9 +38,10 @@ func testMount(t *testing.T, root InodeEmbedder, opts *Options) (string, func()) ...@@ -38,9 +38,10 @@ func testMount(t *testing.T, root InodeEmbedder, opts *Options) (string, func())
func TestDataFile(t *testing.T) { func TestDataFile(t *testing.T) {
want := "hello" want := "hello"
mntDir, clean := testMount(t, &Inode{}, &Options{ root := &Inode{}
mntDir, clean := testMount(t, root, &Options{
FirstAutomaticIno: 1, FirstAutomaticIno: 1,
OnAdd: func(ctx context.Context, root InodeEmbedder) { OnAdd: func(ctx context.Context) {
n := root.EmbeddedInode() n := root.EmbeddedInode()
ch := n.NewPersistentInode( ch := n.NewPersistentInode(
ctx, ctx,
......
...@@ -9,7 +9,7 @@ import ( ...@@ -9,7 +9,7 @@ import (
"bytes" "bytes"
"context" "context"
"io/ioutil" "io/ioutil"
"os" "log"
"path/filepath" "path/filepath"
"reflect" "reflect"
"strings" "strings"
...@@ -18,7 +18,6 @@ import ( ...@@ -18,7 +18,6 @@ import (
"testing" "testing"
"github.com/hanwen/go-fuse/fuse" "github.com/hanwen/go-fuse/fuse"
"github.com/hanwen/go-fuse/internal/testutil"
) )
var testData = map[string]string{ var testData = map[string]string{
...@@ -62,20 +61,10 @@ func TestZipFS(t *testing.T) { ...@@ -62,20 +61,10 @@ func TestZipFS(t *testing.T) {
t.Fatal(err) t.Fatal(err)
} }
root := &zipRoot{r: r} root := &zipRoot{zr: r}
mntDir, clean := testMount(t, root, nil)
defer clean()
mntDir := testutil.TempDir()
defer os.Remove(mntDir)
server, err := Mount(mntDir, root, &Options{
MountOptions: fuse.MountOptions{
Debug: testutil.VerboseTest(),
},
FirstAutomaticIno: 1,
})
if err != nil {
t.Fatal(err)
}
defer server.Unmount()
for k, v := range testData { for k, v := range testData {
c, err := ioutil.ReadFile(filepath.Join(mntDir, k)) c, err := ioutil.ReadFile(filepath.Join(mntDir, k))
if err != nil { if err != nil {
...@@ -104,6 +93,33 @@ func TestZipFS(t *testing.T) { ...@@ -104,6 +93,33 @@ func TestZipFS(t *testing.T) {
} }
} }
func TestZipFSOnAdd(t *testing.T) {
zipBytes := createZip(testData)
r, err := zip.NewReader(&byteReaderAt{zipBytes}, int64(len(zipBytes)))
if err != nil {
t.Fatal(err)
}
zr := &zipRoot{zr: r}
root := &Inode{}
mnt, clean := testMount(t, root, &Options{
OnAdd: func(ctx context.Context) {
root.AddChild("sub",
root.NewPersistentInode(ctx, zr, NodeAttr{Mode: syscall.S_IFDIR}), false)
},
})
defer clean()
c, err := ioutil.ReadFile(mnt + "/sub/dir/subdir/subfile")
if err != nil {
t.Fatal("ReadFile", err)
}
if got, want := string(c), "content3"; got != want {
t.Errorf("got %q, want %q", got, want)
}
}
// zipFile is a file read from a zip archive. // zipFile is a file read from a zip archive.
type zipFile struct { type zipFile struct {
Inode Inode
...@@ -160,7 +176,7 @@ func (zf *zipFile) Read(ctx context.Context, f FileHandle, dest []byte, off int6 ...@@ -160,7 +176,7 @@ func (zf *zipFile) Read(ctx context.Context, f FileHandle, dest []byte, off int6
type zipRoot struct { type zipRoot struct {
Inode Inode
r *zip.Reader zr *zip.Reader
} }
var _ = (OnAdder)((*zipRoot)(nil)) var _ = (OnAdder)((*zipRoot)(nil))
...@@ -170,7 +186,7 @@ func (zr *zipRoot) OnAdd(ctx context.Context) { ...@@ -170,7 +186,7 @@ func (zr *zipRoot) OnAdd(ctx context.Context) {
// then construct a tree. We construct the entire tree, and // then construct a tree. We construct the entire tree, and
// we don't want parts of the tree to disappear when the // we don't want parts of the tree to disappear when the
// kernel is short on memory, so we use persistent inodes. // kernel is short on memory, so we use persistent inodes.
for _, f := range zr.r.File { for _, f := range zr.zr.File {
dir, base := filepath.Split(f.Name) dir, base := filepath.Split(f.Name)
p := &zr.Inode p := &zr.Inode
...@@ -191,3 +207,50 @@ func (zr *zipRoot) OnAdd(ctx context.Context) { ...@@ -191,3 +207,50 @@ func (zr *zipRoot) OnAdd(ctx context.Context) {
p.AddChild(base, ch, true) p.AddChild(base, ch, true)
} }
} }
// ExampleNewPersistentInode shows how to create a in-memory file
// system a prefabricated tree.
func ExampleNewPersistentInode() {
mntDir, _ := ioutil.TempDir("", "")
files := map[string]string{
"file": "content",
"subdir/other-file": "content",
}
root := &Inode{}
server, err := Mount(mntDir, root, &Options{
MountOptions: fuse.MountOptions{Debug: true},
OnAdd: func(ctx context.Context) {
for name, content := range files {
dir, base := filepath.Split(name)
p := root
for _, component := range strings.Split(dir, "/") {
if len(component) == 0 {
continue
}
ch := p.GetChild(component)
if ch == nil {
ch = p.NewPersistentInode(ctx, &Inode{},
NodeAttr{Mode: syscall.S_IFDIR})
p.AddChild(component, ch, true)
}
p = ch
}
child := p.NewPersistentInode(ctx, &MemRegularFile{
Data: []byte(content),
}, NodeAttr{})
p.AddChild(base, child, true)
}
},
})
if err != nil {
log.Panic(err)
}
log.Printf("Mounted on %s", mntDir)
log.Printf("Unmount by calling 'fusermount -u %s'", mntDir)
server.Wait()
}
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