From 06f1c0c61cbe1985fda1acb1b75c93874bbeac79 Mon Sep 17 00:00:00 2001 From: Nick Craig-Wood Date: Tue, 26 Jan 2021 17:44:24 +0000 Subject: [PATCH] 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 --- fs/operations/operations.go | 16 +++++++++++++--- fs/sync/sync.go | 6 +++++- 2 files changed, 18 insertions(+), 4 deletions(-) diff --git a/fs/operations/operations.go b/fs/operations/operations.go index e0b116cdf..1904de321 100644 --- a/fs/operations/operations.go +++ b/fs/operations/operations.go @@ -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) diff --git a/fs/sync/sync.go b/fs/sync/sync.go index eab41e775..59cb7233e 100644 --- a/fs/sync/sync.go +++ b/fs/sync/sync.go @@ -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)) + } } } }