From b47d6001a9126ce75f590496609d452e785ab4ce Mon Sep 17 00:00:00 2001 From: Nick Craig-Wood Date: Wed, 17 Mar 2021 15:01:35 +0000 Subject: [PATCH] vfs: fix directory renaming by renaming dirs cached in memory Before this change, if a directory was renamed and it or any children had virtual entries in it they weren't flushed. The consequence of this was that the directory path got out sync with the actual position of the directory in the tree, leading to listings of the old directory rather than the new one. The fix renames any directories remaining after the ForgetAll to have the correct path which fixes the problem. See: https://forum.rclone.org/t/after-a-directory-renmane-using-mv-files-are-not-visible-any-longer/22797 --- vfs/dir.go | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/vfs/dir.go b/vfs/dir.go index 083f93921..79a8d6537 100644 --- a/vfs/dir.go +++ b/vfs/dir.go @@ -312,12 +312,35 @@ func (d *Dir) _age(when time.Time) (age time.Duration, stale bool) { return } +// renameTree renames the directories under this directory +// +// path should be the desired path +func (d *Dir) renameTree(dirPath string) { + d.mu.Lock() + defer d.mu.Unlock() + + // Make sure the path is correct for each node + if d.path != dirPath { + fs.Debugf(d.path, "Renaming to %q", dirPath) + d.path = dirPath + d.entry = fs.NewDirCopy(context.TODO(), d.entry).SetRemote(dirPath) + } + + // Do the same to any child directories + for leaf, node := range d.items { + if dir, ok := node.(*Dir); ok { + dir.renameTree(path.Join(dirPath, leaf)) + } + } +} + // rename should be called after the directory is renamed // // Reset the directory to new state, discarding all the objects and // reading everything again func (d *Dir) rename(newParent *Dir, fsDir fs.Directory) { d.ForgetAll() + d.modTimeMu.Lock() d.modTime = fsDir.ModTime(context.TODO()) d.modTimeMu.Unlock() @@ -330,6 +353,9 @@ func (d *Dir) rename(newParent *Dir, fsDir fs.Directory) { d.read = time.Time{} d.mu.Unlock() + // Rename any remaining items in the tree that we couldn't forget + d.renameTree(d.path) + // Rename in the cache if d.vfs.cache != nil && d.vfs.cache.DirExists(oldPath) { if err := d.vfs.cache.DirRename(oldPath, newPath); err != nil { @@ -930,6 +956,7 @@ func (d *Dir) RemoveName(name string) error { // Rename the file func (d *Dir) Rename(oldName, newName string, destDir *Dir) error { + // fs.Debugf(d, "BEFORE\n%s", d.dump()) if d.vfs.Opt.ReadOnly { return EROFS } @@ -996,6 +1023,7 @@ func (d *Dir) Rename(oldName, newName string, destDir *Dir) error { destDir.addObject(oldNode) // fs.Debugf(newPath, "Dir.Rename renamed from %q", oldPath) + // fs.Debugf(d, "AFTER\n%s", d.dump()) return nil }