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

nodefs: symlink/readlink.

parent f8379610
...@@ -60,4 +60,8 @@ To decide ...@@ -60,4 +60,8 @@ To decide
* cancellation through context.Context (standard, more GC overhead) * cancellation through context.Context (standard, more GC overhead)
or a custom context (could reuse across requests.)? 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 { ...@@ -105,7 +105,8 @@ type Operations interface {
Unlink(ctx context.Context, name string) fuse.Status Unlink(ctx context.Context, name string) fuse.Status
Rename(ctx context.Context, name string, newParent Operations, newName string, flags uint32) 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) 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) 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) 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 ...@@ -374,12 +374,27 @@ func (b *rawBridge) Link(input *fuse.LinkIn, filename string, out *fuse.EntryOut
return fuse.ENOSYS return fuse.ENOSYS
} }
func (b *rawBridge) Symlink(header *fuse.InHeader, pointedTo string, linkName string, out *fuse.EntryOut) (code fuse.Status) { func (b *rawBridge) Symlink(header *fuse.InHeader, target string, name string, out *fuse.EntryOut) (code fuse.Status) {
return fuse.ENOSYS 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) { 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) { func (b *rawBridge) Access(input *fuse.AccessIn) (code fuse.Status) {
......
...@@ -6,6 +6,7 @@ package nodefs ...@@ -6,6 +6,7 @@ package nodefs
import ( import (
"context" "context"
"log"
"time" "time"
"github.com/hanwen/go-fuse/fuse" "github.com/hanwen/go-fuse/fuse"
...@@ -57,6 +58,15 @@ func (n *DefaultOperations) Read(ctx context.Context, f FileHandle, dest []byte, ...@@ -57,6 +58,15 @@ func (n *DefaultOperations) Read(ctx context.Context, f FileHandle, dest []byte,
return nil, fuse.ENOSYS 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 { func (n *DefaultOperations) Fsync(ctx context.Context, f FileHandle, flags uint32) fuse.Status {
if f != nil { if f != nil {
return f.Fsync(ctx, flags) return f.Fsync(ctx, flags)
......
...@@ -6,6 +6,7 @@ package nodefs ...@@ -6,6 +6,7 @@ package nodefs
import ( import (
"context" "context"
"log"
"os" "os"
"path/filepath" "path/filepath"
"sync" "sync"
...@@ -14,6 +15,8 @@ import ( ...@@ -14,6 +15,8 @@ import (
"github.com/hanwen/go-fuse/fuse" "github.com/hanwen/go-fuse/fuse"
) )
var _ = log.Printf
type loopbackRoot struct { type loopbackRoot struct {
loopbackNode loopbackNode
...@@ -183,6 +186,40 @@ func (n *loopbackNode) Create(ctx context.Context, name string, flags uint32, mo ...@@ -183,6 +186,40 @@ func (n *loopbackNode) Create(ctx context.Context, name string, flags uint32, mo
return ch, lf, 0, fuse.OK 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) { func (n *loopbackNode) Open(ctx context.Context, flags uint32) (fh FileHandle, fuseFlags uint32, code fuse.Status) {
p := n.path() p := n.path()
f, err := os.OpenFile(p, int(flags), 0) f, err := os.OpenFile(p, int(flags), 0)
......
...@@ -407,3 +407,20 @@ func TestParallelFileOpen(t *testing.T) { ...@@ -407,3 +407,20 @@ func TestParallelFileOpen(t *testing.T) {
} }
wg.Wait() 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