Commit 29229b42 authored by Han-Wen Nienhuys's avatar Han-Wen Nienhuys

nodefs: Mkdir/Mknod/Rmdir/Unlink

parent df38958b
......@@ -87,6 +87,11 @@ type Node interface {
// pair.
Lookup(ctx context.Context, name string, out *fuse.EntryOut) (*Inode, fuse.Status)
Mkdir(ctx context.Context, name string, mode uint32, out *fuse.EntryOut) (*Inode, fuse.Status)
Mknod(ctx context.Context, name string, mode uint32, dev uint32, out *fuse.EntryOut) (*Inode, fuse.Status)
Rmdir(ctx context.Context, name string) fuse.Status
Unlink(ctx context.Context, name string) fuse.Status
Open(ctx context.Context, flags uint32) (fh File, fuseFlags uint32, code fuse.Status)
Create(ctx context.Context, name string, flags uint32, mode uint32) (node *Inode, fh File, fuseFlags uint32, code fuse.Status)
......
......@@ -6,6 +6,7 @@ package nodefs
import (
"context"
"log"
"sync"
"time"
......@@ -89,6 +90,61 @@ func (b *rawBridge) Lookup(header *fuse.InHeader, name string, out *fuse.EntryOu
return code
}
b.addNewChild(parent, name, child, out)
b.setEntryOutTimeout(out)
return fuse.OK
}
func (b *rawBridge) Rmdir(header *fuse.InHeader, name string) fuse.Status {
parent, _ := b.inode(header.NodeId, 0)
code := parent.node.Rmdir(context.TODO(), name)
if code.Ok() {
parent.RmChild(name)
}
return code
}
func (b *rawBridge) Unlink(header *fuse.InHeader, name string) fuse.Status {
parent, _ := b.inode(header.NodeId, 0)
code := parent.node.Unlink(context.TODO(), name)
if code.Ok() {
parent.RmChild(name)
}
return code
}
func (b *rawBridge) Mkdir(input *fuse.MkdirIn, name string, out *fuse.EntryOut) (code fuse.Status) {
parent, _ := b.inode(input.NodeId, 0)
child, code := parent.node.Mkdir(context.TODO(), name, input.Mode, out)
if !code.Ok() {
return code
}
if out.Attr.Mode&^07777 != fuse.S_IFDIR {
log.Panicf("Mkdir: mode must be S_IFDIR (%o), got %o", fuse.S_IFDIR, out.Attr.Mode)
}
b.addNewChild(parent, name, child, out)
b.setEntryOutTimeout(out)
return fuse.OK
}
func (b *rawBridge) Mknod(input *fuse.MknodIn, name string, out *fuse.EntryOut) (code fuse.Status) {
parent, _ := b.inode(input.NodeId, 0)
child, code := parent.node.Mknod(context.TODO(), name, input.Mode, input.Rdev, out)
if !code.Ok() {
return code
}
b.addNewChild(parent, name, child, out)
b.setEntryOutTimeout(out)
return fuse.OK
}
func (b *rawBridge) addNewChild(parent *Inode, name string, child *Inode, out *fuse.EntryOut) {
lockNodes(parent, child)
parent.setEntry(name, child)
b.mu.Lock()
......@@ -99,9 +155,6 @@ func (b *rawBridge) Lookup(header *fuse.InHeader, name string, out *fuse.EntryOu
out.Generation = b.nodes[out.NodeId].generation
b.mu.Unlock()
unlockNodes(parent, child)
b.setEntryOutTimeout(out)
return fuse.OK
}
func (b *rawBridge) setEntryOutTimeout(out *fuse.EntryOut) {
......@@ -155,11 +208,15 @@ func (b *rawBridge) Create(input *fuse.CreateIn, name string, out *fuse.CreateOu
b.mu.Unlock()
unlockNode2(parent, child)
b.setEntryOutTimeout(out)
b.setEntryOutTimeout(&out.EntryOut)
out.OpenFlags = flags
f.GetAttr(ctx, &out.Attr)
if out.Attr.Mode&^07777 != fuse.S_IFREG {
log.Panicf("Create: mode must be S_IFREG (%o), got %o", fuse.S_IFREG, out.Attr.Mode)
}
return fuse.OK
}
......@@ -269,22 +326,6 @@ func (b *rawBridge) SetAttr(input *fuse.SetAttrIn, out *fuse.AttrOut) (code fuse
return code
}
func (b *rawBridge) Mknod(input *fuse.MknodIn, name string, out *fuse.EntryOut) (code fuse.Status) {
return fuse.ENOSYS
}
func (b *rawBridge) Mkdir(input *fuse.MkdirIn, name string, out *fuse.EntryOut) (code fuse.Status) {
return fuse.ENOSYS
}
func (b *rawBridge) Unlink(header *fuse.InHeader, name string) (code fuse.Status) {
return fuse.ENOSYS
}
func (b *rawBridge) Rmdir(header *fuse.InHeader, name string) (code fuse.Status) {
return fuse.ENOSYS
}
func (b *rawBridge) Rename(input *fuse.RenameIn, oldName string, newName string) (code fuse.Status) {
return fuse.ENOSYS
}
......
......@@ -62,6 +62,59 @@ func (n *loopbackNode) Lookup(ctx context.Context, name string, out *fuse.EntryO
return ch, fuse.OK
}
func (n *loopbackNode) Mknod(ctx context.Context, name string, mode, rdev uint32, out *fuse.EntryOut) (*Inode, fuse.Status) {
p := filepath.Join(n.path(), name)
err := syscall.Mknod(p, mode, int(rdev))
if err != nil {
return nil, fuse.ToStatus(err)
}
st := syscall.Stat_t{}
if err := syscall.Lstat(p, &st); err != nil {
syscall.Rmdir(p)
return nil, fuse.ToStatus(err)
}
out.Attr.FromStat(&st)
node := &loopbackNode{rootNode: n.rootNode}
ch := n.inode().NewInode(node, out.Attr.Mode, out.Attr.Ino)
return ch, fuse.OK
}
func (n *loopbackNode) Mkdir(ctx context.Context, name string, mode uint32, out *fuse.EntryOut) (*Inode, fuse.Status) {
// NOSUBMIT what about umask
p := filepath.Join(n.path(), name)
err := os.Mkdir(p, os.FileMode(mode))
if err != nil {
return nil, fuse.ToStatus(err)
}
st := syscall.Stat_t{}
if err := syscall.Lstat(p, &st); err != nil {
syscall.Rmdir(p)
return nil, fuse.ToStatus(err)
}
out.Attr.FromStat(&st)
node := &loopbackNode{rootNode: n.rootNode}
ch := n.inode().NewInode(node, out.Attr.Mode, out.Attr.Ino)
return ch, fuse.OK
}
func (n *loopbackNode) Rmdir(ctx context.Context, name string) fuse.Status {
p := filepath.Join(n.path(), name)
err := syscall.Rmdir(p)
return fuse.ToStatus(err)
}
func (n *loopbackNode) Unlink(ctx context.Context, name string) fuse.Status {
p := filepath.Join(n.path(), name)
err := syscall.Unlink(p)
return fuse.ToStatus(err)
}
func (n *loopbackNode) Create(ctx context.Context, name string, flags uint32, mode uint32) (inode *Inode, fh File, fuseFlags uint32, code fuse.Status) {
p := filepath.Join(n.path(), name)
......
......@@ -88,7 +88,8 @@ func TestBasic(t *testing.T) {
tc.writeOrig("file", "hello", 0644)
fi, err := os.Lstat(tc.mntDir + "/file")
fn := tc.mntDir + "/file"
fi, err := os.Lstat(fn)
if err != nil {
t.Fatalf("Lstat: %v", err)
}
......@@ -101,6 +102,14 @@ func TestBasic(t *testing.T) {
if got, want := stat.Mode, uint32(fuse.S_IFREG|0644); got != want {
t.Errorf("got mode %o, want %o", got, want)
}
if err := os.Remove(fn); err != nil {
t.Errorf("Remove: %v", err)
}
if fi, err := os.Lstat(fn); err == nil {
t.Errorf("Lstat after remove: got file %v", fi)
}
}
func TestFile(t *testing.T) {
......@@ -216,3 +225,22 @@ func TestFileFdLeak(t *testing.T) {
t.Errorf("found %d used file handles, should be <= 3", got)
}
}
func TestMkdir(t *testing.T) {
tc := newTestCase(t)
defer tc.Clean()
if err := os.Mkdir(tc.mntDir+"/dir", 0755); err != nil {
t.Fatalf("Mkdir: %v", err)
}
if fi, err := os.Lstat(tc.mntDir + "/dir"); err != nil {
t.Fatalf("Lstat %v", err)
} else if !fi.IsDir() {
t.Fatalf("is not a directory")
}
if err := os.Remove(tc.mntDir + "/dir"); err != nil {
t.Fatalf("Remove: %v", err)
}
}
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