Commit 24b35705 authored by Han-Wen Nienhuys's avatar Han-Wen Nienhuys

Implement renaming for directories.

parent ae675f73
......@@ -257,8 +257,6 @@ func (me *UnionFs) Promote(name string, srcResult branchResult) (code fuse.Statu
if srcResult.attr.IsRegular() {
code = fuse.CopyFile(sourceFs, writable, name, name)
} else if srcResult.attr.IsDirectory() {
code = writable.Mkdir(name, 0755)
} else if srcResult.attr.IsSymlink() {
link := ""
link, code = sourceFs.Readlink(name)
......@@ -267,6 +265,8 @@ func (me *UnionFs) Promote(name string, srcResult branchResult) (code fuse.Statu
} else {
code = writable.Symlink(link, name)
}
} else if srcResult.attr.IsDirectory() {
code = writable.Mkdir(name, 0755)
} else {
log.Println("Unknown file type:", srcResult.attr)
return fuse.ENOSYS
......@@ -694,20 +694,86 @@ func (me *UnionFs) OpenDir(directory string) (stream chan fuse.DirEntry, status
}
// recursivePromote promotes path, and if a directory, everything
// below that directory. It returns a list of all promoted paths.
func (me *UnionFs) recursivePromote(path string, pathResult branchResult) (names []string, code fuse.Status) {
names = []string{}
if pathResult.branch > 0 {
code = me.Promote(path, pathResult)
}
if code.Ok() {
names = append(names, path)
}
if code.Ok() && pathResult.attr.IsDirectory() {
var stream chan fuse.DirEntry
stream, code = me.OpenDir(path)
for e := range stream {
if !code.Ok() {
break
}
subnames := []string{}
p := filepath.Join(path, e.Name)
r := me.getBranch(p)
subnames, code = me.recursivePromote(p, r)
names = append(names, subnames...)
}
}
if !code.Ok() {
names = nil
}
return names, code
}
func (me *UnionFs) renameDirectory(srcResult branchResult, srcDir string, dstDir string) (code fuse.Status) {
names := []string{}
if code.Ok() {
names, code = me.recursivePromote(srcDir, srcResult)
}
if code.Ok() {
code = me.promoteDirsTo(dstDir)
}
if code.Ok() {
writable := me.fileSystems[0]
code = writable.Rename(srcDir, dstDir)
}
if code.Ok() {
for _, srcName := range names {
relative := strings.TrimLeft(srcName[len(srcDir):], string(filepath.Separator))
dst := filepath.Join(dstDir, relative)
me.removeDeletion(dst)
}
srcResult := me.getBranch(srcDir)
srcResult.branch = 0
me.branchCache.Set(dstDir, srcResult)
srcResult = me.branchCache.GetFresh(srcDir).(branchResult)
if srcResult.branch > 0 {
code = me.putDeletion(srcDir)
}
// TODO - should issue invalidations against promoted files?
}
return code
}
func (me *UnionFs) Rename(src string, dst string) (code fuse.Status) {
srcResult := me.getBranch(src)
code = srcResult.code
if code.Ok() {
code = srcResult.code
}
if srcResult.attr.IsDirectory() {
log.Println("rename directories unimplemented.")
// TODO - to rename a directory:
// * promote all files below the directory
// * execute a move in writable layer
// * issue invalidations against all promoted files.
return fuse.ENOSYS
return me.renameDirectory(srcResult, src, dst)
}
if code.Ok() && srcResult.branch > 0 {
code = me.Promote(src, srcResult)
}
......@@ -723,12 +789,8 @@ func (me *UnionFs) Rename(src string, dst string) (code fuse.Status) {
srcResult.branch = 0
me.branchCache.Set(dst, srcResult)
if srcResult.branch == 0 {
srcResult := me.branchCache.GetFresh(src)
if srcResult.(branchResult).branch > 0 {
code = me.putDeletion(src)
}
} else {
srcResult := me.branchCache.GetFresh(src)
if srcResult.(branchResult).branch > 0 {
code = me.putDeletion(src)
}
}
......
......@@ -409,7 +409,7 @@ func TestRename(t *testing.T) {
}
}
func disabledTestRenameDir(t *testing.T) {
func TestRenameDir(t *testing.T) {
wd, clean := setupUfs(t)
defer clean()
......@@ -431,7 +431,46 @@ func disabledTestRenameDir(t *testing.T) {
if err != nil || len(entries) != 1 || entries[0].Name != "subdir" {
t.Errorf("readdir(%s/mount/renamed) should have one entry: %v, err %v", wd, entries, err)
}
}
func TestRenameDirWithDeletions(t *testing.T) {
wd, clean := setupUfs(t)
defer clean()
err := os.MkdirAll(wd + "/ro/dir/subdir", 0755)
CheckSuccess(err)
err = ioutil.WriteFile(wd + "/ro/dir/file.txt", []byte{42}, 0644)
CheckSuccess(err)
err = ioutil.WriteFile(wd + "/ro/dir/subdir/file.txt", []byte{42}, 0644)
CheckSuccess(err)
if fi, _ := os.Lstat(wd + "/mount/dir/subdir/file.txt"); fi == nil || !fi.IsRegular() {
t.Fatalf("%s/mount/dir/subdir/file.txt should be file: %v", wd, fi)
}
err = os.Remove(wd + "/mount/dir/file.txt")
CheckSuccess(err)
err = os.Rename(wd + "/mount/dir", wd + "/mount/renamed")
CheckSuccess(err)
if fi, _ := os.Lstat(wd + "/mount/dir/subdir/file.txt"); fi != nil {
t.Fatalf("%s/mount/dir/subdir/file.txt should have disappeared: %v", wd, fi)
}
if fi, _ := os.Lstat(wd + "/mount/dir"); fi != nil {
t.Fatalf("%s/mount/dir should have disappeared: %v", wd, fi)
}
if fi, _ := os.Lstat(wd + "/mount/renamed"); fi == nil || !fi.IsDirectory() {
t.Fatalf("%s/mount/renamed should be directory: %v", wd, fi)
}
if fi, _ := os.Lstat(wd + "/mount/renamed/file.txt"); fi != nil {
t.Fatalf("%s/mount/renamed/file.txt should have disappeared %#v", wd, fi)
}
}
func TestRenameSymlink(t *testing.T) {
......
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