Commit 6b4bb98b authored by Han-Wen Nienhuys's avatar Han-Wen Nienhuys

nodefs: Mkdir/Mknod/Rmdir/Unlink

parent 74f62108
...@@ -87,6 +87,11 @@ type Node interface { ...@@ -87,6 +87,11 @@ type Node interface {
// pair. // pair.
Lookup(ctx context.Context, name string, out *fuse.EntryOut) (*Inode, fuse.Status) 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) 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) 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 ...@@ -6,6 +6,7 @@ package nodefs
import ( import (
"context" "context"
"log"
"sync" "sync"
"time" "time"
...@@ -89,6 +90,61 @@ func (b *rawBridge) Lookup(header *fuse.InHeader, name string, out *fuse.EntryOu ...@@ -89,6 +90,61 @@ func (b *rawBridge) Lookup(header *fuse.InHeader, name string, out *fuse.EntryOu
return code 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) lockNodes(parent, child)
parent.setEntry(name, child) parent.setEntry(name, child)
b.mu.Lock() b.mu.Lock()
...@@ -99,9 +155,6 @@ func (b *rawBridge) Lookup(header *fuse.InHeader, name string, out *fuse.EntryOu ...@@ -99,9 +155,6 @@ func (b *rawBridge) Lookup(header *fuse.InHeader, name string, out *fuse.EntryOu
out.Generation = b.nodes[out.NodeId].generation out.Generation = b.nodes[out.NodeId].generation
b.mu.Unlock() b.mu.Unlock()
unlockNodes(parent, child) unlockNodes(parent, child)
b.setEntryOutTimeout(out)
return fuse.OK
} }
func (b *rawBridge) setEntryOutTimeout(out *fuse.EntryOut) { func (b *rawBridge) setEntryOutTimeout(out *fuse.EntryOut) {
...@@ -155,11 +208,15 @@ func (b *rawBridge) Create(input *fuse.CreateIn, name string, out *fuse.CreateOu ...@@ -155,11 +208,15 @@ func (b *rawBridge) Create(input *fuse.CreateIn, name string, out *fuse.CreateOu
b.mu.Unlock() b.mu.Unlock()
unlockNode2(parent, child) unlockNode2(parent, child)
b.setEntryOutTimeout(out) b.setEntryOutTimeout(&out.EntryOut)
out.OpenFlags = flags out.OpenFlags = flags
f.GetAttr(ctx, &out.Attr) 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 return fuse.OK
} }
...@@ -269,22 +326,6 @@ func (b *rawBridge) SetAttr(input *fuse.SetAttrIn, out *fuse.AttrOut) (code fuse ...@@ -269,22 +326,6 @@ func (b *rawBridge) SetAttr(input *fuse.SetAttrIn, out *fuse.AttrOut) (code fuse
return code 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) { func (b *rawBridge) Rename(input *fuse.RenameIn, oldName string, newName string) (code fuse.Status) {
return fuse.ENOSYS return fuse.ENOSYS
} }
......
...@@ -62,6 +62,59 @@ func (n *loopbackNode) Lookup(ctx context.Context, name string, out *fuse.EntryO ...@@ -62,6 +62,59 @@ func (n *loopbackNode) Lookup(ctx context.Context, name string, out *fuse.EntryO
return ch, fuse.OK 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) { 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) p := filepath.Join(n.path(), name)
......
...@@ -88,7 +88,8 @@ func TestBasic(t *testing.T) { ...@@ -88,7 +88,8 @@ func TestBasic(t *testing.T) {
tc.writeOrig("file", "hello", 0644) tc.writeOrig("file", "hello", 0644)
fi, err := os.Lstat(tc.mntDir + "/file") fn := tc.mntDir + "/file"
fi, err := os.Lstat(fn)
if err != nil { if err != nil {
t.Fatalf("Lstat: %v", err) t.Fatalf("Lstat: %v", err)
} }
...@@ -101,6 +102,14 @@ func TestBasic(t *testing.T) { ...@@ -101,6 +102,14 @@ func TestBasic(t *testing.T) {
if got, want := stat.Mode, uint32(fuse.S_IFREG|0644); got != want { if got, want := stat.Mode, uint32(fuse.S_IFREG|0644); got != want {
t.Errorf("got mode %o, want %o", 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) { func TestFile(t *testing.T) {
...@@ -216,3 +225,22 @@ func TestFileFdLeak(t *testing.T) { ...@@ -216,3 +225,22 @@ func TestFileFdLeak(t *testing.T) {
t.Errorf("found %d used file handles, should be <= 3", got) 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