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

nodefs: add MemRegularFile, MemSymlink

utility classes for symlinks and regular files without backing store.
parent 0ba056ea
// Copyright 2019 the Go-FUSE Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package nodefs
import (
"context"
"syscall"
"github.com/hanwen/go-fuse/fuse"
)
// MemRegularFile is a filesystem node that holds a read-only data
// slice in memory.
type MemRegularFile struct {
Inode
Data []byte
Attr fuse.Attr
}
var _ = (Opener)((*MemRegularFile)(nil))
var _ = (Getattrer)((*MemRegularFile)(nil))
var _ = (Reader)((*MemRegularFile)(nil))
func (f *MemRegularFile) Open(ctx context.Context, flags uint32) (fh FileHandle, fuseFlags uint32, errno syscall.Errno) {
if flags&(syscall.O_RDWR) != 0 || flags&syscall.O_WRONLY != 0 {
return nil, 0, syscall.EPERM
}
return nil, fuse.FOPEN_KEEP_CACHE, OK
}
func (f *MemRegularFile) Getattr(ctx context.Context, fh FileHandle, out *fuse.AttrOut) syscall.Errno {
out.Attr = f.Attr
out.Mode ^= 0222
out.Attr.Size = uint64(len(f.Data))
return OK
}
func (f *MemRegularFile) Read(ctx context.Context, fh FileHandle, dest []byte, off int64) (fuse.ReadResult, syscall.Errno) {
end := int(off) + len(dest)
if end > len(f.Data) {
end = len(f.Data)
}
return fuse.ReadResultData(f.Data[:end]), OK
}
// MemSymlink is an inode holding a symlink in memory.
type MemSymlink struct {
Inode
Data []byte
}
var _ = (Readlinker)((*MemSymlink)(nil))
func (l *MemSymlink) Readlink(ctx context.Context) ([]byte, syscall.Errno) {
return l.Data, OK
}
// Copyright 2019 the Go-FUSE Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package nodefs
import (
"context"
"io/ioutil"
"os"
"syscall"
"testing"
"github.com/hanwen/go-fuse/fuse"
"github.com/hanwen/go-fuse/internal/testutil"
)
func testMount(t *testing.T, root InodeEmbedder, opts *Options) (string, func()) {
t.Helper()
mntDir := testutil.TempDir()
if opts == nil {
opts = &Options{
FirstAutomaticIno: 1,
}
}
opts.Debug = testutil.VerboseTest()
server, err := Mount(mntDir, root, opts)
if err != nil {
t.Fatal(err)
}
return mntDir, func() {
server.Unmount()
os.Remove(mntDir)
}
}
func TestDataFile(t *testing.T) {
want := "hello"
mntDir, clean := testMount(t, &Inode{}, &Options{
FirstAutomaticIno: 1,
OnAdd: func(ctx context.Context, root InodeEmbedder) {
n := root.EmbeddedInode()
ch := n.NewPersistentInode(
ctx,
&MemRegularFile{
Data: []byte(want),
},
NodeAttr{})
n.AddChild("file", ch, false)
},
})
defer clean()
c, err := ioutil.ReadFile(mntDir + "/file")
if err != nil {
t.Fatalf("ReadFile: %v", err)
}
if got := string(c); got != want {
t.Errorf("got %q want %q", got, want)
}
}
type SymlinkerRoot struct {
Inode
}
func (s *SymlinkerRoot) Symlink(ctx context.Context, target, name string, out *fuse.EntryOut) (*Inode, syscall.Errno) {
l := &MemSymlink{
Data: []byte(target),
}
ch := s.NewPersistentInode(ctx, l, NodeAttr{Mode: syscall.S_IFLNK})
return ch, 0
}
func TestDataSymlink(t *testing.T) {
root := &SymlinkerRoot{}
mntDir, clean := testMount(t, root, nil)
defer clean()
if err := syscall.Symlink("target", mntDir+"/link"); err != nil {
t.Fatalf("Symlink: %v", err)
}
if got, err := os.Readlink(mntDir + "/link"); err != nil {
t.Fatalf("Readlink: %v", err)
} else if want := "target"; got != want {
t.Errorf("Readlink: got %q want %q", got, want)
}
}
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