Commit 8d47a84b authored by Jakob Unterwurzacher's avatar Jakob Unterwurzacher Committed by Han-Wen Nienhuys

nodefs: delay directory read till ReadDir

We used to read the directory already on OpenDir, which means that
we missed changes in the directory between a user's open() and
readdir() call.

https://github.com/hanwen/go-fuse/issues/252
parent 33711add
......@@ -53,13 +53,13 @@ func NewDirEntryList(data []byte, off uint64) *DirEntryList {
// AddDirEntry tries to add an entry, and reports whether it
// succeeded.
func (l *DirEntryList) AddDirEntry(e DirEntry) (bool, uint64) {
func (l *DirEntryList) AddDirEntry(e DirEntry) bool {
return l.Add(0, e.Name, e.Ino, e.Mode)
}
// Add adds a direntry to the DirEntryList, returning whether it
// succeeded.
func (l *DirEntryList) Add(prefix int, name string, inode uint64, mode uint32) (bool, uint64) {
func (l *DirEntryList) Add(prefix int, name string, inode uint64, mode uint32) bool {
if inode == 0 {
inode = FUSE_UNKNOWN_INO
}
......@@ -69,7 +69,7 @@ func (l *DirEntryList) Add(prefix int, name string, inode uint64, mode uint32) (
newLen := delta + oldLen
if newLen > l.size {
return false, l.offset
return false
}
l.buf = l.buf[:newLen]
oldLen += prefix
......@@ -87,20 +87,20 @@ func (l *DirEntryList) Add(prefix int, name string, inode uint64, mode uint32) (
}
l.offset = dirent.Off
return true, l.offset
return true
}
// AddDirLookupEntry is used for ReadDirPlus. It serializes a DirEntry
// and returns the space for entry. If no space is left, returns a nil
// pointer.
func (l *DirEntryList) AddDirLookupEntry(e DirEntry) (*EntryOut, uint64) {
func (l *DirEntryList) AddDirLookupEntry(e DirEntry) *EntryOut {
lastStart := len(l.buf)
ok, off := l.Add(int(unsafe.Sizeof(EntryOut{})), e.Name,
ok := l.Add(int(unsafe.Sizeof(EntryOut{})), e.Name,
e.Ino, e.Mode)
if !ok {
return nil, off
return nil
}
return (*EntryOut)(unsafe.Pointer(&l.buf[lastStart])), off
return (*EntryOut)(unsafe.Pointer(&l.buf[lastStart]))
}
func (l *DirEntryList) bytes() []byte {
......
......@@ -13,33 +13,30 @@ import (
type connectorDir struct {
node Node
inode *Inode
rawFS fuse.RawFileSystem
// Protect stream and lastOffset. These are written in case
// there is a seek on the directory.
mu sync.Mutex
stream []fuse.DirEntry
// lastOffset stores the last offset for a readdir. This lets
// readdir pick up changes to the directory made after opening
// it.
lastOffset uint64
}
func (d *connectorDir) ReadDir(input *fuse.ReadIn, out *fuse.DirEntryList) (code fuse.Status) {
d.mu.Lock()
defer d.mu.Unlock()
if d.stream == nil {
return fuse.OK
}
// rewinddir() should be as if reopening directory.
// TODO - test this.
if d.lastOffset > 0 && input.Offset == 0 {
if d.stream == nil || input.Offset == 0 {
d.stream, code = d.node.OpenDir(&input.Context)
if !code.Ok() {
return code
}
d.stream = append(d.stream, d.inode.getMountDirEntries()...)
d.stream = append(d.stream,
fuse.DirEntry{Mode: fuse.S_IFDIR, Name: "."},
fuse.DirEntry{Mode: fuse.S_IFDIR, Name: ".."})
}
if input.Offset > uint64(len(d.stream)) {
......@@ -53,8 +50,7 @@ func (d *connectorDir) ReadDir(input *fuse.ReadIn, out *fuse.DirEntryList) (code
log.Printf("got empty directory entry, mode %o.", e.Mode)
continue
}
ok, off := out.AddDirEntry(e)
d.lastOffset = off
ok := out.AddDirEntry(e)
if !ok {
break
}
......@@ -66,16 +62,16 @@ func (d *connectorDir) ReadDirPlus(input *fuse.ReadIn, out *fuse.DirEntryList) (
d.mu.Lock()
defer d.mu.Unlock()
if d.stream == nil {
return fuse.OK
}
// rewinddir() should be as if reopening directory.
if d.lastOffset > 0 && input.Offset == 0 {
if d.stream == nil || input.Offset == 0 {
d.stream, code = d.node.OpenDir(&input.Context)
if !code.Ok() {
return code
}
d.stream = append(d.stream, d.inode.getMountDirEntries()...)
d.stream = append(d.stream,
fuse.DirEntry{Mode: fuse.S_IFDIR, Name: "."},
fuse.DirEntry{Mode: fuse.S_IFDIR, Name: ".."})
}
if input.Offset > uint64(len(d.stream)) {
......@@ -91,7 +87,7 @@ func (d *connectorDir) ReadDirPlus(input *fuse.ReadIn, out *fuse.DirEntryList) (
// we have to be sure entry will fit if we try to add
// it, or we'll mess up the lookup counts.
entryDest, off := out.AddDirLookupEntry(e)
entryDest := out.AddDirLookupEntry(e)
if entryDest == nil {
break
}
......@@ -106,10 +102,8 @@ func (d *connectorDir) ReadDirPlus(input *fuse.ReadIn, out *fuse.DirEntryList) (
*entryDest = fuse.EntryOut{}
d.rawFS.Lookup(&input.InHeader, e.Name, entryDest)
d.lastOffset = off
}
return fuse.OK
}
type rawDir interface {
......
......@@ -161,16 +161,9 @@ func (c *rawBridge) GetAttr(input *fuse.GetAttrIn, out *fuse.AttrOut) (code fuse
func (c *rawBridge) OpenDir(input *fuse.OpenIn, out *fuse.OpenOut) (code fuse.Status) {
node := c.toInode(input.NodeId)
stream, err := node.fsInode.OpenDir(&input.Context)
if err != fuse.OK {
return err
}
stream = append(stream, node.getMountDirEntries()...)
de := &connectorDir{
inode: node,
node: node.Node(),
stream: append(stream,
fuse.DirEntry{Mode: fuse.S_IFDIR, Name: "."},
fuse.DirEntry{Mode: fuse.S_IFDIR, Name: ".."}),
rawFS: c,
}
h, opened := node.mount.registerFileHandle(node, de, nil, input.Flags)
......
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