Commit 037f7b0e authored by Han-Wen Nienhuys's avatar Han-Wen Nienhuys

nodefs: symlink/readlink.

parent f8379610
......@@ -60,4 +60,8 @@ To decide
* cancellation through context.Context (standard, more GC overhead)
or a custom context (could reuse across requests.)?
* Readlink return: []byte or string ?
* Should Operations.Lookup return *Inode or Operations ?
* Should bridge.Lookup() add the child, bridge.Unlink remove the child, etc.?
......@@ -105,7 +105,8 @@ type Operations interface {
Unlink(ctx context.Context, name string) fuse.Status
Rename(ctx context.Context, name string, newParent Operations, newName string, flags uint32) fuse.Status
Create(ctx context.Context, name string, flags uint32, mode uint32) (node *Inode, fh FileHandle, fuseFlags uint32, code fuse.Status)
Symlink(ctx context.Context, target, name string, out *fuse.EntryOut) (node *Inode, code fuse.Status)
Readlink(ctx context.Context) (string, fuse.Status)
Open(ctx context.Context, flags uint32) (fh FileHandle, fuseFlags uint32, code fuse.Status)
Read(ctx context.Context, f FileHandle, dest []byte, off int64) (fuse.ReadResult, fuse.Status)
......
......@@ -374,12 +374,27 @@ func (b *rawBridge) Link(input *fuse.LinkIn, filename string, out *fuse.EntryOut
return fuse.ENOSYS
}
func (b *rawBridge) Symlink(header *fuse.InHeader, pointedTo string, linkName string, out *fuse.EntryOut) (code fuse.Status) {
return fuse.ENOSYS
func (b *rawBridge) Symlink(header *fuse.InHeader, target string, name string, out *fuse.EntryOut) (code fuse.Status) {
log.Println("symlink1")
parent, _ := b.inode(header.NodeId, 0)
child, code := parent.node.Symlink(context.TODO(), target, name, out)
if !code.Ok() {
return code
}
b.addNewChild(parent, name, child, nil, out)
b.setEntryOutTimeout(out)
return fuse.OK
}
func (b *rawBridge) Readlink(header *fuse.InHeader) (out []byte, code fuse.Status) {
return nil, fuse.ENOSYS
n, _ := b.inode(header.NodeId, 0)
result, code := n.node.Readlink(context.TODO())
if !code.Ok() {
return nil, code
}
return []byte(result), fuse.OK
}
func (b *rawBridge) Access(input *fuse.AccessIn) (code fuse.Status) {
......
......@@ -6,6 +6,7 @@ package nodefs
import (
"context"
"log"
"time"
"github.com/hanwen/go-fuse/fuse"
......@@ -57,6 +58,15 @@ func (n *DefaultOperations) Read(ctx context.Context, f FileHandle, dest []byte,
return nil, fuse.ENOSYS
}
func (n *DefaultOperations) Symlink(ctx context.Context, target, name string, out *fuse.EntryOut) (node *Inode, code fuse.Status) {
log.Println("defsyml")
return nil, fuse.ENOSYS
}
func (n *DefaultOperations) Readlink(ctx context.Context) (string, fuse.Status) {
return "", fuse.ENOSYS
}
func (n *DefaultOperations) Fsync(ctx context.Context, f FileHandle, flags uint32) fuse.Status {
if f != nil {
return f.Fsync(ctx, flags)
......
......@@ -6,6 +6,7 @@ package nodefs
import (
"context"
"log"
"os"
"path/filepath"
"sync"
......@@ -14,6 +15,8 @@ import (
"github.com/hanwen/go-fuse/fuse"
)
var _ = log.Printf
type loopbackRoot struct {
loopbackNode
......@@ -183,6 +186,40 @@ func (n *loopbackNode) Create(ctx context.Context, name string, flags uint32, mo
return ch, lf, 0, fuse.OK
}
func (n *loopbackNode) Symlink(ctx context.Context, target, name string, out *fuse.EntryOut) (*Inode, fuse.Status) {
p := filepath.Join(n.path(), name)
err := syscall.Symlink(target, p)
if err != nil {
return nil, fuse.ToStatus(err)
}
st := syscall.Stat_t{}
if syscall.Lstat(p, &st); err != nil {
syscall.Unlink(p)
return nil, fuse.ToStatus(err)
}
node := n.rootNode.newLoopbackNode()
ch := n.inode().NewInode(node, st.Mode, idFromStat(&st))
out.Attr.FromStat(&st)
return ch, fuse.OK
}
func (n *loopbackNode) Readlink(ctx context.Context) (string, fuse.Status) {
p := n.path()
for l := 256; ; l *= 2 {
buf := make([]byte, l)
sz, err := syscall.Readlink(p, buf)
if err != nil {
return "", fuse.ToStatus(err)
}
if sz < len(buf) {
return string(buf[:sz]), fuse.OK
}
}
}
func (n *loopbackNode) Open(ctx context.Context, flags uint32) (fh FileHandle, fuseFlags uint32, code fuse.Status) {
p := n.path()
f, err := os.OpenFile(p, int(flags), 0)
......
......@@ -407,3 +407,20 @@ func TestParallelFileOpen(t *testing.T) {
}
wg.Wait()
}
func TestSymlink(t *testing.T) {
tc := newTestCase(t)
defer tc.Clean()
fn := tc.mntDir + "/link"
target := "target"
if err := os.Symlink(target, fn); err != nil {
t.Fatalf("Symlink: %v", err)
}
if got, err := os.Readlink(fn); err != nil {
t.Fatalf("Readlink: %v", err)
} else if got != target {
t.Errorf("Readlink: got %q, want %q", got, target)
}
}
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