operations: make move and copy individual files obey --backup-dir

Before this change, when using rclone copy or move with --backup-dir
and the source was a single file, rclone would fail to use the backup
directory.

This change looks up the backup directory in the Fs cache and uses it
as appropriate.

This affects any commands which call operations.MoveFile or
operations.CopyFile which includes rclone move/moveto/copy/copyto
where the source is a single file.

Fixes #3219
This commit is contained in:
Nick Craig-Wood 2019-05-23 13:17:16 +01:00
parent 8ee6034b23
commit e7c20e0bce
2 changed files with 63 additions and 0 deletions

View File

@ -19,6 +19,7 @@ import (
"github.com/ncw/rclone/fs"
"github.com/ncw/rclone/fs/accounting"
"github.com/ncw/rclone/fs/cache"
"github.com/ncw/rclone/fs/fserrors"
"github.com/ncw/rclone/fs/fshttp"
"github.com/ncw/rclone/fs/hash"
@ -1475,6 +1476,22 @@ func moveOrCopyFile(fdst fs.Fs, fsrc fs.Fs, dstFileName string, srcFileName stri
}
if NeedTransfer(dstObj, srcObj) {
// If destination already exists, then we must move it into --backup-dir if required
if dstObj != nil && fs.Config.BackupDir != "" {
backupDir, err := cache.Get(fs.Config.BackupDir)
if err != nil {
return errors.Wrap(err, "creating Fs for --backup-dir failed")
}
remoteWithSuffix := SuffixName(dstObj.Remote())
overwritten, _ := backupDir.NewObject(remoteWithSuffix)
_, err = Move(backupDir, overwritten, remoteWithSuffix, dstObj)
if err != nil {
return errors.Wrap(err, "moving to --backup-dir failed")
}
// If successful zero out the dstObj as it is no longer there
dstObj = nil
}
_, err = Op(fdst, dstObj, dstFileName, srcObj)
} else {
accounting.Stats.Checking(srcFileName)

View File

@ -739,6 +739,29 @@ func TestMoveFile(t *testing.T) {
fstest.CheckItems(t, r.Fremote, file2)
}
func TestMoveFileBackupDir(t *testing.T) {
r := fstest.NewRun(t)
defer r.Finalise()
oldBackupDir := fs.Config.BackupDir
fs.Config.BackupDir = r.FremoteName + "/backup"
defer func() {
fs.Config.BackupDir = oldBackupDir
}()
file1 := r.WriteFile("dst/file1", "file1 contents", t1)
fstest.CheckItems(t, r.Flocal, file1)
file1old := r.WriteObject("dst/file1", "file1 contents old", t1)
fstest.CheckItems(t, r.Fremote, file1old)
err := operations.MoveFile(r.Fremote, r.Flocal, file1.Path, file1.Path)
require.NoError(t, err)
fstest.CheckItems(t, r.Flocal)
file1old.Path = "backup/dst/file1"
fstest.CheckItems(t, r.Fremote, file1old, file1)
}
func TestCopyFile(t *testing.T) {
r := fstest.NewRun(t)
defer r.Finalise()
@ -765,6 +788,29 @@ func TestCopyFile(t *testing.T) {
fstest.CheckItems(t, r.Fremote, file2)
}
func TestCopyFileBackupDir(t *testing.T) {
r := fstest.NewRun(t)
defer r.Finalise()
oldBackupDir := fs.Config.BackupDir
fs.Config.BackupDir = r.FremoteName + "/backup"
defer func() {
fs.Config.BackupDir = oldBackupDir
}()
file1 := r.WriteFile("dst/file1", "file1 contents", t1)
fstest.CheckItems(t, r.Flocal, file1)
file1old := r.WriteObject("dst/file1", "file1 contents old", t1)
fstest.CheckItems(t, r.Fremote, file1old)
err := operations.CopyFile(r.Fremote, r.Flocal, file1.Path, file1.Path)
require.NoError(t, err)
fstest.CheckItems(t, r.Flocal, file1)
file1old.Path = "backup/dst/file1"
fstest.CheckItems(t, r.Fremote, file1old, file1)
}
// testFsInfo is for unit testing fs.Info
type testFsInfo struct {
name string