move: fix data loss when moving the same object

This checks to see if IDs are the same of the source and destination
object before deleting one of them and potentially causing data loss.

See: https://forum.rclone.org/t/files-deleted-and-not-moved/21830
This commit is contained in:
Nick Craig-Wood 2021-01-26 17:44:24 +00:00
parent e6a9f005d6
commit 06f1c0c61c
2 changed files with 18 additions and 4 deletions

View File

@ -529,11 +529,21 @@ func Copy(ctx context.Context, f fs.Fs, dst fs.Object, remote string, src fs.Obj
// SameObject returns true if src and dst could be pointing to the
// same object.
func SameObject(src, dst fs.Object) bool {
if !SameConfig(src.Fs(), dst.Fs()) {
srcFs, dstFs := src.Fs(), dst.Fs()
if !SameConfig(srcFs, dstFs) {
// If same remote type then check ID of objects if available
doSrcID, srcIDOK := src.(fs.IDer)
doDstID, dstIDOK := dst.(fs.IDer)
if srcIDOK && dstIDOK && SameRemoteType(srcFs, dstFs) {
srcID, dstID := doSrcID.ID(), doDstID.ID()
if srcID != "" && srcID == dstID {
return true
}
}
return false
}
srcPath := path.Join(src.Fs().Root(), src.Remote())
dstPath := path.Join(dst.Fs().Root(), dst.Remote())
srcPath := path.Join(srcFs.Root(), src.Remote())
dstPath := path.Join(dstFs.Root(), dst.Remote())
if dst.Fs().Features().CaseInsensitive {
srcPath = strings.ToLower(srcPath)
dstPath = strings.ToLower(dstPath)

View File

@ -347,7 +347,11 @@ func (s *syncCopyMove) pairChecker(in *pipe, out *pipe, fraction int, wg *sync.W
// If moving need to delete the files we don't need to copy
if s.DoMove {
// Delete src if no error on copy
s.processError(operations.DeleteFile(s.ctx, src))
if operations.SameObject(src, pair.Dst) {
fs.Logf(src, "Not removing source file as it is the same file as the destination")
} else {
s.processError(operations.DeleteFile(s.ctx, src))
}
}
}
}