Ensure items in srcEmptyDirs are actually empty
This commit is contained in:
parent
4009fb67c8
commit
737aed8412
1 changed files with 35 additions and 7 deletions
|
@ -5,6 +5,7 @@ import (
|
||||||
"context"
|
"context"
|
||||||
"fmt"
|
"fmt"
|
||||||
"sort"
|
"sort"
|
||||||
|
"strings"
|
||||||
"sync"
|
"sync"
|
||||||
|
|
||||||
"github.com/ncw/rclone/fs"
|
"github.com/ncw/rclone/fs"
|
||||||
|
@ -38,9 +39,9 @@ type syncCopyMove struct {
|
||||||
srcFilesResult chan error // error result of src listing
|
srcFilesResult chan error // error result of src listing
|
||||||
dstFilesResult chan error // error result of dst listing
|
dstFilesResult chan error // error result of dst listing
|
||||||
dstEmptyDirsMu sync.Mutex // protect dstEmptyDirs
|
dstEmptyDirsMu sync.Mutex // protect dstEmptyDirs
|
||||||
dstEmptyDirs []fs.DirEntry // potentially empty directories
|
dstEmptyDirs map[string]fs.DirEntry // potentially empty directories
|
||||||
srcEmptyDirsMu sync.Mutex // protect srcEmptyDirs
|
srcEmptyDirsMu sync.Mutex // protect srcEmptyDirs
|
||||||
srcEmptyDirs []fs.DirEntry // potentially empty directories
|
srcEmptyDirs map[string]fs.DirEntry // potentially empty directories
|
||||||
checkerWg sync.WaitGroup // wait for checkers
|
checkerWg sync.WaitGroup // wait for checkers
|
||||||
toBeChecked fs.ObjectPairChan // checkers channel
|
toBeChecked fs.ObjectPairChan // checkers channel
|
||||||
transfersWg sync.WaitGroup // wait for transfers
|
transfersWg sync.WaitGroup // wait for transfers
|
||||||
|
@ -72,6 +73,8 @@ func newSyncCopyMove(fdst, fsrc fs.Fs, deleteMode fs.DeleteMode, DoMove bool, de
|
||||||
srcFilesChan: make(chan fs.Object, fs.Config.Checkers+fs.Config.Transfers),
|
srcFilesChan: make(chan fs.Object, fs.Config.Checkers+fs.Config.Transfers),
|
||||||
srcFilesResult: make(chan error, 1),
|
srcFilesResult: make(chan error, 1),
|
||||||
dstFilesResult: make(chan error, 1),
|
dstFilesResult: make(chan error, 1),
|
||||||
|
dstEmptyDirs: make(map[string]fs.DirEntry),
|
||||||
|
srcEmptyDirs: make(map[string]fs.DirEntry),
|
||||||
toBeChecked: make(fs.ObjectPairChan, fs.Config.Transfers),
|
toBeChecked: make(fs.ObjectPairChan, fs.Config.Transfers),
|
||||||
toBeUploaded: make(fs.ObjectPairChan, fs.Config.Transfers),
|
toBeUploaded: make(fs.ObjectPairChan, fs.Config.Transfers),
|
||||||
deleteFilesCh: make(chan fs.Object, fs.Config.Checkers),
|
deleteFilesCh: make(chan fs.Object, fs.Config.Checkers),
|
||||||
|
@ -444,8 +447,8 @@ func (s *syncCopyMove) deleteFiles(checkSrcMap bool) error {
|
||||||
|
|
||||||
// This deletes the empty directories in the slice passed in. It
|
// This deletes the empty directories in the slice passed in. It
|
||||||
// ignores any errors deleting directories
|
// ignores any errors deleting directories
|
||||||
func deleteEmptyDirectories(f fs.Fs, entries fs.DirEntries) error {
|
func deleteEmptyDirectories(f fs.Fs, entriesMap map[string]fs.DirEntry) error {
|
||||||
if len(entries) == 0 {
|
if len(entriesMap) == 0 {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
if accounting.Stats.Errored() && !fs.Config.IgnoreErrors {
|
if accounting.Stats.Errored() && !fs.Config.IgnoreErrors {
|
||||||
|
@ -453,6 +456,10 @@ func deleteEmptyDirectories(f fs.Fs, entries fs.DirEntries) error {
|
||||||
return fs.ErrorNotDeletingDirs
|
return fs.ErrorNotDeletingDirs
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var entries fs.DirEntries
|
||||||
|
for _, entry := range entriesMap {
|
||||||
|
entries = append(entries, entry)
|
||||||
|
}
|
||||||
// Now delete the empty directories starting from the longest path
|
// Now delete the empty directories starting from the longest path
|
||||||
sort.Sort(entries)
|
sort.Sort(entries)
|
||||||
var errorCount int
|
var errorCount int
|
||||||
|
@ -482,6 +489,15 @@ func deleteEmptyDirectories(f fs.Fs, entries fs.DirEntries) error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func parentDirCheck(entries map[string]fs.DirEntry, entry fs.DirEntry) {
|
||||||
|
path := strings.Split(entry.Remote(), "/")
|
||||||
|
path = path[:len(path)-1]
|
||||||
|
parentDir := strings.Join(path, "/")
|
||||||
|
if _, ok := entries[parentDir]; ok {
|
||||||
|
delete(entries, parentDir)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// renameHash makes a string with the size and the hash for rename detection
|
// renameHash makes a string with the size and the hash for rename detection
|
||||||
//
|
//
|
||||||
// it may return an empty string in which case no hash could be made
|
// it may return an empty string in which case no hash could be made
|
||||||
|
@ -701,7 +717,7 @@ func (s *syncCopyMove) DstOnly(dst fs.DirEntry) (recurse bool) {
|
||||||
// Record directory as it is potentially empty and needs deleting
|
// Record directory as it is potentially empty and needs deleting
|
||||||
if s.fdst.Features().CanHaveEmptyDirectories {
|
if s.fdst.Features().CanHaveEmptyDirectories {
|
||||||
s.dstEmptyDirsMu.Lock()
|
s.dstEmptyDirsMu.Lock()
|
||||||
s.dstEmptyDirs = append(s.dstEmptyDirs, dst)
|
s.dstEmptyDirs[dst.Remote()] = dst
|
||||||
s.dstEmptyDirsMu.Unlock()
|
s.dstEmptyDirsMu.Unlock()
|
||||||
}
|
}
|
||||||
return true
|
return true
|
||||||
|
@ -719,6 +735,12 @@ func (s *syncCopyMove) SrcOnly(src fs.DirEntry) (recurse bool) {
|
||||||
}
|
}
|
||||||
switch x := src.(type) {
|
switch x := src.(type) {
|
||||||
case fs.Object:
|
case fs.Object:
|
||||||
|
// Remove parent directory from srcEmptyDirs
|
||||||
|
// since it's not really empty
|
||||||
|
s.srcEmptyDirsMu.Lock()
|
||||||
|
parentDirCheck(s.srcEmptyDirs, src)
|
||||||
|
s.srcEmptyDirsMu.Unlock()
|
||||||
|
|
||||||
if s.trackRenames {
|
if s.trackRenames {
|
||||||
// Save object to check for a rename later
|
// Save object to check for a rename later
|
||||||
select {
|
select {
|
||||||
|
@ -738,7 +760,8 @@ func (s *syncCopyMove) SrcOnly(src fs.DirEntry) (recurse bool) {
|
||||||
// Do the same thing to the entire contents of the directory
|
// Do the same thing to the entire contents of the directory
|
||||||
// Record the directory for deletion
|
// Record the directory for deletion
|
||||||
s.srcEmptyDirsMu.Lock()
|
s.srcEmptyDirsMu.Lock()
|
||||||
s.srcEmptyDirs = append(s.srcEmptyDirs, src)
|
parentDirCheck(s.srcEmptyDirs, src)
|
||||||
|
s.srcEmptyDirs[src.Remote()] = src
|
||||||
s.srcEmptyDirsMu.Unlock()
|
s.srcEmptyDirsMu.Unlock()
|
||||||
return true
|
return true
|
||||||
default:
|
default:
|
||||||
|
@ -751,6 +774,10 @@ func (s *syncCopyMove) SrcOnly(src fs.DirEntry) (recurse bool) {
|
||||||
func (s *syncCopyMove) Match(dst, src fs.DirEntry) (recurse bool) {
|
func (s *syncCopyMove) Match(dst, src fs.DirEntry) (recurse bool) {
|
||||||
switch srcX := src.(type) {
|
switch srcX := src.(type) {
|
||||||
case fs.Object:
|
case fs.Object:
|
||||||
|
s.srcEmptyDirsMu.Lock()
|
||||||
|
parentDirCheck(s.srcEmptyDirs, src)
|
||||||
|
s.srcEmptyDirsMu.Unlock()
|
||||||
|
|
||||||
if s.deleteMode == fs.DeleteModeOnly {
|
if s.deleteMode == fs.DeleteModeOnly {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
@ -773,7 +800,8 @@ func (s *syncCopyMove) Match(dst, src fs.DirEntry) (recurse bool) {
|
||||||
if ok {
|
if ok {
|
||||||
// Record the src directory for deletion
|
// Record the src directory for deletion
|
||||||
s.srcEmptyDirsMu.Lock()
|
s.srcEmptyDirsMu.Lock()
|
||||||
s.srcEmptyDirs = append(s.srcEmptyDirs, src)
|
parentDirCheck(s.srcEmptyDirs, src)
|
||||||
|
s.srcEmptyDirs[src.Remote()] = src
|
||||||
s.srcEmptyDirsMu.Unlock()
|
s.srcEmptyDirsMu.Unlock()
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue