diff --git a/afero_test.go b/afero_test.go index e2c13624..9292280f 100644 --- a/afero_test.go +++ b/afero_test.go @@ -247,6 +247,31 @@ func TestRename(t *testing.T) { } } +func TestRenameDirectory(t *testing.T) { + fs := NewMemMapFs() + tmp := testDir(fs) + srcDir := filepath.Join(tmp, "src") + srcPath := filepath.Join(srcDir, testName) + destDir := filepath.Join(tmp, "dest") + destPath := filepath.Join(destDir, testName) + + if _, err := fs.Create(srcPath); err != nil { + t.Errorf("%s: create %q failed: %v", fs.Name(), srcPath, err) + } + + if err := fs.Rename(srcDir, destDir); err != nil { + t.Errorf("%s: rename %q to %q failed: %v", fs.Name(), srcDir, destDir, err) + } + + if _, err := fs.Stat(srcPath); err == nil { + t.Errorf("File %q was not removed due to rename to %q", srcPath, destPath) + } + + if _, err := fs.Stat(destPath); err != nil { + t.Errorf("File %q was not present after rename from %q", destPath, srcPath) + } +} + func TestRemove(t *testing.T) { for _, fs := range Fss { diff --git a/mem/file.go b/mem/file.go index 7af2fb56..05d3612f 100644 --- a/mem/file.go +++ b/mem/file.go @@ -99,6 +99,14 @@ func GetFileInfo(f *FileData) *FileInfo { return &FileInfo{f} } +func GetDirFiles(f *FileData) []*FileData { + if f.memDir != nil { + return f.memDir.Files() + } + + return []*FileData{} +} + func (f *File) Open() error { atomic.StoreInt64(&f.at, 0) atomic.StoreInt64(&f.readDirCount, 0) diff --git a/memmap.go b/memmap.go index 09498e70..ab1986c7 100644 --- a/memmap.go +++ b/memmap.go @@ -57,6 +57,53 @@ func (m *MemMapFs) Create(name string) (File, error) { return mem.NewFileHandle(file), nil } +func (m *MemMapFs) unRegisterChildren(dirName string) ([]*mem.FileData, error) { + dir, err := m.lockfreeOpen(dirName) + if err != nil { + return nil, err + } + + children := mem.GetDirFiles(dir) + for _, file := range children { + fileName := file.Name() + file.Lock() + delete(m.getData(), fileName) + mem.RemoveFromMemDir(dir, file) + file.Unlock() + } + + return children, nil +} + +func (m *MemMapFs) registerChildren( + oldDirName string, + newDirName string, + children []*mem.FileData, +) error { + dir, err := m.lockfreeOpen(newDirName) + if err != nil { + return err + } + + for _, file := range children { + oldFileName := file.Name() + newFileName := strings.Replace( + oldFileName, + oldDirName, + newDirName, + 1, + ) + mem.ChangeFileName(file, newFileName) + + file.Lock() + m.getData()[newFileName] = file + mem.AddToMemDir(dir, file) + file.Unlock() + } + + return nil +} + func (m *MemMapFs) unRegisterWithParent(fileName string) error { f, err := m.lockfreeOpen(fileName) if err != nil { @@ -296,9 +343,11 @@ func (m *MemMapFs) Rename(oldname, newname string) error { m.mu.Lock() m.unRegisterWithParent(oldname) fileData := m.getData()[oldname] + children, _ := m.unRegisterChildren(oldname) delete(m.getData(), oldname) mem.ChangeFileName(fileData, newname) m.getData()[newname] = fileData + m.registerChildren(oldname, newname, children) m.registerWithParent(fileData) m.mu.Unlock() m.mu.RLock()