Commit 15ae7b59 authored by Han-Wen Nienhuys's avatar Han-Wen Nienhuys

newunionfs: implement Readdir

parent 1bba2c11
......@@ -37,6 +37,29 @@ type unionFSNode struct {
const delDir = "DELETIONS"
func (r *unionFSRoot) allMarkers(result map[string]struct{}) syscall.Errno {
dir := filepath.Join(r.roots[0], delDir)
ds, errno := nodefs.NewLoopbackDirStream(dir)
if errno != 0 {
return errno
}
defer ds.Close()
for ds.HasNext() {
e, errno := ds.Next()
if errno != 0 {
return errno
}
if e.Mode != syscall.S_IFREG {
continue
}
result[e.Name] = struct{}{}
}
return 0
}
func (r *unionFSRoot) rmMarker(name string) syscall.Errno {
err := syscall.Unlink(r.markerPath(name))
if err != nil {
......@@ -297,6 +320,54 @@ func (n *unionFSNode) Readlink(ctx context.Context) ([]byte, syscall.Errno) {
return buf[:count], 0
}
var _ = (nodefs.Readdirer)((*unionFSNode)(nil))
func (n *unionFSNode) Readdir(ctx context.Context) (nodefs.DirStream, syscall.Errno) {
root := n.root()
markers := map[string]struct{}{}
// ignore error: assume no markers
root.allMarkers(markers)
dir := n.Path(nil)
names := map[string]uint32{}
for i := range root.roots {
// deepest root first.
readRoot(root.roots[len(root.roots)-i-1], dir, names)
}
result := make([]fuse.DirEntry, 0, len(names))
for nm, mode := range names {
marker := filePathHash(filepath.Join(dir, nm))
if _, ok := markers[marker]; ok {
continue
}
result = append(result, fuse.DirEntry{
Name: nm,
Mode: mode,
})
}
return nodefs.NewListDirStream(result), 0
}
func readRoot(root string, dir string, result map[string]uint32) {
ds, errno := nodefs.NewLoopbackDirStream(filepath.Join(root, dir))
if errno != 0 {
return
}
defer ds.Close()
for ds.HasNext() {
e, errno := ds.Next()
if errno != 0 {
return
}
result[e.Name] = e.Mode
}
}
// getBranch returns the root where we can find the given file. It
// will check the deletion markers in roots[0].
func (n *unionFSNode) getBranch(st *syscall.Stat_t) (string, int) {
......
......@@ -9,6 +9,7 @@ import (
"io/ioutil"
"os"
"path/filepath"
"reflect"
"syscall"
"testing"
......@@ -196,6 +197,41 @@ func TestDeleteRevert(t *testing.T) {
}
}
func TestReaddir(t *testing.T) {
tc := newTestCase(t, true)
defer tc.Clean()
if err := ioutil.WriteFile(tc.ro+"/dir/file2", nil, 0644); err != nil {
t.Fatalf("WriteFile: %v", err)
}
if err := os.Mkdir(tc.rw+"/dir", 0755); err != nil {
t.Fatalf("Mkdir: %v", err)
}
if err := ioutil.WriteFile(tc.rw+"/dir/file3", nil, 0644); err != nil {
t.Fatalf("WriteFile: %v", err)
}
if err := os.Remove(tc.mnt + "/dir/ro-file"); err != nil {
t.Fatalf("Remove: %v", err)
}
res, err := ioutil.ReadDir(tc.mnt + "/dir")
if err != nil {
t.Fatalf("ReadDir: %v", err)
}
got := map[string]bool{}
want := map[string]bool{
"file2": true,
"file3": true,
}
for _, fi := range res {
got[fi.Name()] = true
}
if !reflect.DeepEqual(want, got) {
t.Errorf("got %v want %v", got, want)
}
}
func TestPosix(t *testing.T) {
cases := []string{
"SymlinkReadlink",
......@@ -207,7 +243,7 @@ func TestPosix(t *testing.T) {
// "NlinkZero",
"ParallelFileOpen",
// "Link",
// "ReadDir",
"ReadDir",
}
for _, nm := range cases {
......
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