moveto: fix case-insensitive same remote move
This commit is contained in:
parent
2793d4b4cc
commit
d2be792d5e
2 changed files with 74 additions and 2 deletions
|
@ -8,6 +8,7 @@ import (
|
|||
"fmt"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"math/rand"
|
||||
"path"
|
||||
"path/filepath"
|
||||
"sort"
|
||||
|
@ -423,8 +424,8 @@ func Move(fdst fs.Fs, dst fs.Object, remote string, src fs.Object) (newDst fs.Ob
|
|||
}
|
||||
// See if we have Move available
|
||||
if doMove := fdst.Features().Move; doMove != nil && (SameConfig(src.Fs(), fdst) || (SameRemoteType(src.Fs(), fdst) && fdst.Features().ServerSideAcrossConfigs)) {
|
||||
// Delete destination if it exists
|
||||
if dst != nil {
|
||||
// Delete destination if it exists and is not the same file as src (could be same file while seemingly different if the remote is case insensitive)
|
||||
if dst != nil && (!fdst.Features().CaseInsensitive || strings.ToLower(dst.Remote()) != strings.ToLower(src.Remote())) {
|
||||
err = DeleteFile(dst)
|
||||
if err != nil {
|
||||
return newDst, err
|
||||
|
@ -1478,6 +1479,31 @@ func moveOrCopyFile(fdst fs.Fs, fsrc fs.Fs, dstFileName string, srcFileName stri
|
|||
return err
|
||||
}
|
||||
|
||||
// Special case for changing case of a file on a case insensitive remote
|
||||
// This will move the file to a temporary name then
|
||||
// move it back to the intended destination. This is required
|
||||
// to avoid issues with certain remotes and avoid file deletion.
|
||||
if !cp && fdst.Name() == fsrc.Name() && fdst.Features().CaseInsensitive && dstFileName != srcFileName && strings.ToLower(dstFilePath) == strings.ToLower(srcFilePath) {
|
||||
// Create random name to temporarily move file to
|
||||
tmpObjName := dstFileName + "-rclone-move-" + random(8)
|
||||
_, err := fdst.NewObject(tmpObjName)
|
||||
if err != fs.ErrorObjectNotFound {
|
||||
if err == nil {
|
||||
return errors.New("found an already existing file with a randomly generated name. Try the operation again")
|
||||
}
|
||||
return errors.Wrap(err, "error while attempting to move file to a temporary location")
|
||||
}
|
||||
accounting.Stats.Transferring(srcFileName)
|
||||
tmpObj, err := Op(fdst, nil, tmpObjName, srcObj)
|
||||
if err != nil {
|
||||
accounting.Stats.DoneTransferring(srcFileName, false)
|
||||
return errors.Wrap(err, "error while moving file to temporary location")
|
||||
}
|
||||
_, err = Op(fdst, nil, dstFileName, tmpObj)
|
||||
accounting.Stats.DoneTransferring(srcFileName, err == nil)
|
||||
return err
|
||||
}
|
||||
|
||||
if NeedTransfer(dstObj, srcObj) {
|
||||
// If destination already exists, then we must move it into --backup-dir if required
|
||||
if dstObj != nil && fs.Config.BackupDir != "" {
|
||||
|
@ -1506,6 +1532,17 @@ func moveOrCopyFile(fdst fs.Fs, fsrc fs.Fs, dstFileName string, srcFileName stri
|
|||
return err
|
||||
}
|
||||
|
||||
// random generates a pseudorandom alphanumeric string
|
||||
func random(length int) string {
|
||||
randomOutput := make([]byte, length)
|
||||
possibleCharacters := "123567890abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"
|
||||
rand.Seed(time.Now().Unix())
|
||||
for i := range randomOutput {
|
||||
randomOutput[i] = possibleCharacters[rand.Intn(len(possibleCharacters))]
|
||||
}
|
||||
return string(randomOutput)
|
||||
}
|
||||
|
||||
// MoveFile moves a single file possibly to a new name
|
||||
func MoveFile(fdst fs.Fs, fsrc fs.Fs, dstFileName string, srcFileName string) (err error) {
|
||||
return moveOrCopyFile(fdst, fsrc, dstFileName, srcFileName, false)
|
||||
|
|
|
@ -739,6 +739,41 @@ func TestMoveFile(t *testing.T) {
|
|||
fstest.CheckItems(t, r.Fremote, file2)
|
||||
}
|
||||
|
||||
func TestCaseInsensitiveMoveFile(t *testing.T) {
|
||||
r := fstest.NewRun(t)
|
||||
defer r.Finalise()
|
||||
if !r.Fremote.Features().CaseInsensitive {
|
||||
return
|
||||
}
|
||||
|
||||
file1 := r.WriteFile("file1", "file1 contents", t1)
|
||||
fstest.CheckItems(t, r.Flocal, file1)
|
||||
|
||||
file2 := file1
|
||||
file2.Path = "sub/file2"
|
||||
|
||||
err := operations.MoveFile(r.Fremote, r.Flocal, file2.Path, file1.Path)
|
||||
require.NoError(t, err)
|
||||
fstest.CheckItems(t, r.Flocal)
|
||||
fstest.CheckItems(t, r.Fremote, file2)
|
||||
|
||||
r.WriteFile("file1", "file1 contents", t1)
|
||||
fstest.CheckItems(t, r.Flocal, file1)
|
||||
|
||||
err = operations.MoveFile(r.Fremote, r.Flocal, file2.Path, file1.Path)
|
||||
require.NoError(t, err)
|
||||
fstest.CheckItems(t, r.Flocal)
|
||||
fstest.CheckItems(t, r.Fremote, file2)
|
||||
|
||||
file2Capitalized := file2
|
||||
file2Capitalized.Path = "sub/File2"
|
||||
|
||||
err = operations.MoveFile(r.Fremote, r.Fremote, file2Capitalized.Path, file2.Path)
|
||||
require.NoError(t, err)
|
||||
fstest.CheckItems(t, r.Flocal)
|
||||
fstest.CheckItems(t, r.Fremote, file2Capitalized)
|
||||
}
|
||||
|
||||
func TestMoveFileBackupDir(t *testing.T) {
|
||||
r := fstest.NewRun(t)
|
||||
defer r.Finalise()
|
||||
|
|
Loading…
Reference in a new issue