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

newunionfs: hide DELETIONS

parent 17598b8b
...@@ -37,6 +37,8 @@ type unionFSNode struct { ...@@ -37,6 +37,8 @@ type unionFSNode struct {
const delDir = "DELETIONS" const delDir = "DELETIONS"
var delDirHash = filePathHash(delDir)
func (r *unionFSRoot) allMarkers(result map[string]struct{}) syscall.Errno { func (r *unionFSRoot) allMarkers(result map[string]struct{}) syscall.Errno {
dir := filepath.Join(r.roots[0], delDir) dir := filepath.Join(r.roots[0], delDir)
...@@ -184,6 +186,10 @@ func (n *unionFSNode) Setattr(ctx context.Context, fh nodefs.FileHandle, in *fus ...@@ -184,6 +186,10 @@ func (n *unionFSNode) Setattr(ctx context.Context, fh nodefs.FileHandle, in *fus
var _ = (nodefs.Creater)((*unionFSNode)(nil)) var _ = (nodefs.Creater)((*unionFSNode)(nil))
func (n *unionFSNode) Create(ctx context.Context, name string, flags uint32, mode uint32, out *fuse.EntryOut) (*nodefs.Inode, nodefs.FileHandle, uint32, syscall.Errno) { func (n *unionFSNode) Create(ctx context.Context, name string, flags uint32, mode uint32, out *fuse.EntryOut) (*nodefs.Inode, nodefs.FileHandle, uint32, syscall.Errno) {
if n.IsRoot() && name == delDir {
return nil, nil, 0, syscall.EPERM
}
var st syscall.Stat_t var st syscall.Stat_t
dirName, idx := n.getBranch(&st) dirName, idx := n.getBranch(&st)
if idx > 0 { if idx > 0 {
...@@ -255,6 +261,10 @@ func (n *unionFSNode) Getattr(ctx context.Context, fh nodefs.FileHandle, out *fu ...@@ -255,6 +261,10 @@ func (n *unionFSNode) Getattr(ctx context.Context, fh nodefs.FileHandle, out *fu
var _ = (nodefs.Lookuper)((*unionFSNode)(nil)) var _ = (nodefs.Lookuper)((*unionFSNode)(nil))
func (n *unionFSNode) Lookup(ctx context.Context, name string, out *fuse.EntryOut) (*nodefs.Inode, syscall.Errno) { func (n *unionFSNode) Lookup(ctx context.Context, name string, out *fuse.EntryOut) (*nodefs.Inode, syscall.Errno) {
if n.IsRoot() && name == delDir {
return nil, syscall.ENOENT
}
var st syscall.Stat_t var st syscall.Stat_t
p := filepath.Join(n.Path(nil), name) p := filepath.Join(n.Path(nil), name)
...@@ -325,7 +335,7 @@ var _ = (nodefs.Readdirer)((*unionFSNode)(nil)) ...@@ -325,7 +335,7 @@ var _ = (nodefs.Readdirer)((*unionFSNode)(nil))
func (n *unionFSNode) Readdir(ctx context.Context) (nodefs.DirStream, syscall.Errno) { func (n *unionFSNode) Readdir(ctx context.Context) (nodefs.DirStream, syscall.Errno) {
root := n.root() root := n.root()
markers := map[string]struct{}{} markers := map[string]struct{}{delDirHash: struct{}{}}
// ignore error: assume no markers // ignore error: assume no markers
root.allMarkers(markers) root.allMarkers(markers)
...@@ -336,7 +346,6 @@ func (n *unionFSNode) Readdir(ctx context.Context) (nodefs.DirStream, syscall.Er ...@@ -336,7 +346,6 @@ func (n *unionFSNode) Readdir(ctx context.Context) (nodefs.DirStream, syscall.Er
// deepest root first. // deepest root first.
readRoot(root.roots[len(root.roots)-i-1], dir, names) readRoot(root.roots[len(root.roots)-i-1], dir, names)
} }
result := make([]fuse.DirEntry, 0, len(names)) result := make([]fuse.DirEntry, 0, len(names))
for nm, mode := range names { for nm, mode := range names {
marker := filePathHash(filepath.Join(dir, nm)) marker := filePathHash(filepath.Join(dir, nm))
......
...@@ -132,6 +132,15 @@ func TestDeleteMarker(t *testing.T) { ...@@ -132,6 +132,15 @@ func TestDeleteMarker(t *testing.T) {
} }
} }
func TestCreateDeletions(t *testing.T) {
tc := newTestCase(t, true)
defer tc.Clean()
if _, err := syscall.Creat(filepath.Join(tc.mnt, delDir), 0644); err != syscall.EPERM {
t.Fatalf("got err %v, want EPERM", err)
}
}
func TestCreate(t *testing.T) { func TestCreate(t *testing.T) {
tc := newTestCase(t, true) tc := newTestCase(t, true)
defer tc.Clean() defer tc.Clean()
...@@ -197,6 +206,35 @@ func TestDeleteRevert(t *testing.T) { ...@@ -197,6 +206,35 @@ func TestDeleteRevert(t *testing.T) {
} }
} }
func TestReaddirRoot(t *testing.T) {
tc := newTestCase(t, true)
defer tc.Clean()
if err := os.Remove(tc.mnt + "/dir/ro-file"); err != nil {
t.Fatalf("Remove: %v", err)
}
f, err := os.Open(tc.mnt)
if err != nil {
t.Fatalf("Open: %v", err)
}
defer f.Close()
names, err := f.Readdirnames(-1)
if err != nil {
t.Fatalf("Readdirnames: %v", err)
}
got := map[string]bool{}
want := map[string]bool{"dir": true}
for _, nm := range names {
got[nm] = true
}
if !reflect.DeepEqual(want, got) {
t.Errorf("got %v want %v", got, want)
}
}
func TestReaddir(t *testing.T) { func TestReaddir(t *testing.T) {
tc := newTestCase(t, true) tc := newTestCase(t, true)
defer tc.Clean() defer tc.Clean()
......
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