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

nodefs: streaming directory reads

compile on darwin too
parent b02df882
...@@ -79,25 +79,6 @@ type DirStream interface { ...@@ -79,25 +79,6 @@ type DirStream interface {
Close() Close()
} }
// XXX names
type DirArray struct {
Entries []fuse.DirEntry
}
func (a *DirArray) HasNext() bool {
return len(a.Entries) > 0
}
func (a *DirArray) Next() (fuse.DirEntry, fuse.Status) {
e := a.Entries[0]
a.Entries = a.Entries[1:]
return e, fuse.OK
}
func (a *DirArray) Close() {
}
/* /*
NOSUBMIT: how to structure? NOSUBMIT: how to structure?
......
// 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 (
"io"
"os"
"github.com/hanwen/go-fuse/fuse"
)
// XXX names
type dirArray struct {
Entries []fuse.DirEntry
}
func (a *dirArray) HasNext() bool {
return len(a.Entries) > 0
}
func (a *dirArray) Next() (fuse.DirEntry, fuse.Status) {
e := a.Entries[0]
a.Entries = a.Entries[1:]
return e, fuse.OK
}
func (a *dirArray) Close() {
}
func NewLoopbackDirStream(nm string) (DirStream, fuse.Status) {
// XXX should implement streaming read to make sure the API works.
f, err := os.Open(nm)
if err != nil {
return nil, fuse.ToStatus(err)
}
defer f.Close()
var entries []fuse.DirEntry
for {
want := 100
infos, err := f.Readdir(want)
for _, info := range infos {
s := fuse.ToStatT(info)
if s == nil {
continue
}
entries = append(entries, fuse.DirEntry{
Name: info.Name(),
Mode: uint32(s.Mode),
Ino: s.Ino,
})
}
if len(infos) < want || err == io.EOF {
break
}
if err != nil {
return nil, fuse.ToStatus(err)
}
}
return &dirArray{entries}, fuse.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 (
"syscall"
"unsafe"
"github.com/hanwen/go-fuse/fuse"
)
type loopbackDirStream struct {
buf []byte
todo []byte
fd int
}
func NewLoopbackDirStream(name string) (DirStream, fuse.Status) {
fd, err := syscall.Open(name, syscall.O_DIRECTORY, 0755)
if err != nil {
return nil, fuse.ToStatus(err)
}
ds := &loopbackDirStream{
buf: make([]byte, 4096),
fd: fd,
}
if err := ds.load(); !err.Ok() {
ds.Close()
return nil, err
}
return ds, fuse.OK
}
func (ds *loopbackDirStream) Close() {
syscall.Close(ds.fd)
}
func (ds *loopbackDirStream) HasNext() bool {
return len(ds.todo) > 0
}
func (ds *loopbackDirStream) Next() (fuse.DirEntry, fuse.Status) {
de := (*syscall.Dirent)(unsafe.Pointer(&ds.todo[0]))
nameBytes := ds.todo[unsafe.Offsetof(syscall.Dirent{}.Name):de.Reclen]
ds.todo = ds.todo[de.Reclen:]
for l := len(nameBytes); l > 0; l-- {
if nameBytes[l-1] != 0 {
break
}
nameBytes = nameBytes[:l-1]
}
result := fuse.DirEntry{
Ino: de.Ino,
Mode: (uint32(de.Type) << 12),
Name: string(nameBytes),
}
return result, ds.load()
}
func (ds *loopbackDirStream) load() fuse.Status {
if len(ds.todo) > 0 {
return fuse.OK
}
n, err := syscall.Getdents(ds.fd, ds.buf)
if err != nil {
return fuse.ToStatus(err)
}
ds.todo = ds.buf[:n]
return fuse.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"
"time"
"github.com/hanwen/go-fuse/fuse"
)
// XXX fill out here.
func (f *loopbackFile) Allocate(ctx context.Context, off uint64, sz uint64, mode uint32) fuse.Status {
return fuse.ENOSYS
}
func (f *loopbackFile) Utimens(ctx context.Context, a *time.Time, m *time.Time) fuse.Status {
return fuse.ENOSYS
}
...@@ -6,7 +6,6 @@ package nodefs ...@@ -6,7 +6,6 @@ package nodefs
import ( import (
"context" "context"
"io"
"log" "log"
"os" "os"
"path/filepath" "path/filepath"
...@@ -181,7 +180,7 @@ func (n *loopbackNode) Create(ctx context.Context, name string, flags uint32, mo ...@@ -181,7 +180,7 @@ func (n *loopbackNode) Create(ctx context.Context, name string, flags uint32, mo
} }
node := n.rootNode.newLoopbackNode() node := n.rootNode.newLoopbackNode()
ch := n.inode().NewInode(node, st.Mode, idFromStat(&st)) ch := n.inode().NewInode(node, uint32(st.Mode), idFromStat(&st))
lf := newLoopbackFile(f) lf := newLoopbackFile(f)
n.mu.Lock() n.mu.Lock()
defer n.mu.Unlock() defer n.mu.Unlock()
...@@ -201,7 +200,7 @@ func (n *loopbackNode) Symlink(ctx context.Context, target, name string, out *fu ...@@ -201,7 +200,7 @@ func (n *loopbackNode) Symlink(ctx context.Context, target, name string, out *fu
return nil, fuse.ToStatus(err) return nil, fuse.ToStatus(err)
} }
node := n.rootNode.newLoopbackNode() node := n.rootNode.newLoopbackNode()
ch := n.inode().NewInode(node, st.Mode, idFromStat(&st)) ch := n.inode().NewInode(node, uint32(st.Mode), idFromStat(&st))
out.Attr.FromStat(&st) out.Attr.FromStat(&st)
return ch, fuse.OK return ch, fuse.OK
...@@ -221,7 +220,7 @@ func (n *loopbackNode) Link(ctx context.Context, target Operations, name string, ...@@ -221,7 +220,7 @@ func (n *loopbackNode) Link(ctx context.Context, target Operations, name string,
return nil, fuse.ToStatus(err) return nil, fuse.ToStatus(err)
} }
node := n.rootNode.newLoopbackNode() node := n.rootNode.newLoopbackNode()
ch := n.inode().NewInode(node, st.Mode, idFromStat(&st)) ch := n.inode().NewInode(node, uint32(st.Mode), idFromStat(&st))
out.Attr.FromStat(&st) out.Attr.FromStat(&st)
return ch, fuse.OK return ch, fuse.OK
...@@ -266,39 +265,7 @@ func (n *loopbackNode) OpenDir(ctx context.Context) fuse.Status { ...@@ -266,39 +265,7 @@ func (n *loopbackNode) OpenDir(ctx context.Context) fuse.Status {
} }
func (n *loopbackNode) ReadDir(ctx context.Context) (DirStream, fuse.Status) { func (n *loopbackNode) ReadDir(ctx context.Context) (DirStream, fuse.Status) {
// XXX should implement streaming read to make sure the API works. return NewLoopbackDirStream(n.path())
f, err := os.Open(n.path())
if err != nil {
return nil, fuse.ToStatus(err)
}
defer f.Close()
var entries []fuse.DirEntry
for {
want := 100
infos, err := f.Readdir(want)
for _, info := range infos {
s := fuse.ToStatT(info)
if s == nil {
continue
}
entries = append(entries, fuse.DirEntry{
Name: info.Name(),
Mode: uint32(s.Mode),
Ino: s.Ino,
})
}
if len(infos) < want || err == io.EOF {
break
}
if err != nil {
return nil, fuse.ToStatus(err)
}
}
return &DirArray{entries}, fuse.OK
} }
func (n *loopbackNode) fGetAttr(ctx context.Context, out *fuse.AttrOut) (fuse.Status, bool) { func (n *loopbackNode) fGetAttr(ctx context.Context, out *fuse.AttrOut) (fuse.Status, bool) {
......
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