mirror of
https://github.com/rclone/rclone.git
synced 2024-11-07 17:14:44 +01:00
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
This commit is contained in:
parent
a4c4ddf052
commit
b47d6001a9
28
vfs/dir.go
28
vfs/dir.go
@ -312,12 +312,35 @@ func (d *Dir) _age(when time.Time) (age time.Duration, stale bool) {
|
|||||||
return
|
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
|
// rename should be called after the directory is renamed
|
||||||
//
|
//
|
||||||
// Reset the directory to new state, discarding all the objects and
|
// Reset the directory to new state, discarding all the objects and
|
||||||
// reading everything again
|
// reading everything again
|
||||||
func (d *Dir) rename(newParent *Dir, fsDir fs.Directory) {
|
func (d *Dir) rename(newParent *Dir, fsDir fs.Directory) {
|
||||||
d.ForgetAll()
|
d.ForgetAll()
|
||||||
|
|
||||||
d.modTimeMu.Lock()
|
d.modTimeMu.Lock()
|
||||||
d.modTime = fsDir.ModTime(context.TODO())
|
d.modTime = fsDir.ModTime(context.TODO())
|
||||||
d.modTimeMu.Unlock()
|
d.modTimeMu.Unlock()
|
||||||
@ -330,6 +353,9 @@ func (d *Dir) rename(newParent *Dir, fsDir fs.Directory) {
|
|||||||
d.read = time.Time{}
|
d.read = time.Time{}
|
||||||
d.mu.Unlock()
|
d.mu.Unlock()
|
||||||
|
|
||||||
|
// Rename any remaining items in the tree that we couldn't forget
|
||||||
|
d.renameTree(d.path)
|
||||||
|
|
||||||
// Rename in the cache
|
// Rename in the cache
|
||||||
if d.vfs.cache != nil && d.vfs.cache.DirExists(oldPath) {
|
if d.vfs.cache != nil && d.vfs.cache.DirExists(oldPath) {
|
||||||
if err := d.vfs.cache.DirRename(oldPath, newPath); err != nil {
|
if err := d.vfs.cache.DirRename(oldPath, newPath); err != nil {
|
||||||
@ -930,6 +956,7 @@ func (d *Dir) RemoveName(name string) error {
|
|||||||
|
|
||||||
// Rename the file
|
// Rename the file
|
||||||
func (d *Dir) Rename(oldName, newName string, destDir *Dir) error {
|
func (d *Dir) Rename(oldName, newName string, destDir *Dir) error {
|
||||||
|
// fs.Debugf(d, "BEFORE\n%s", d.dump())
|
||||||
if d.vfs.Opt.ReadOnly {
|
if d.vfs.Opt.ReadOnly {
|
||||||
return EROFS
|
return EROFS
|
||||||
}
|
}
|
||||||
@ -996,6 +1023,7 @@ func (d *Dir) Rename(oldName, newName string, destDir *Dir) error {
|
|||||||
destDir.addObject(oldNode)
|
destDir.addObject(oldNode)
|
||||||
|
|
||||||
// fs.Debugf(newPath, "Dir.Rename renamed from %q", oldPath)
|
// fs.Debugf(newPath, "Dir.Rename renamed from %q", oldPath)
|
||||||
|
// fs.Debugf(d, "AFTER\n%s", d.dump())
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user