From aaacfa51a079b4a136b3c13ac2ba07add8488014 Mon Sep 17 00:00:00 2001 From: Nick Craig-Wood Date: Tue, 9 May 2023 15:29:55 +0100 Subject: [PATCH] sftp: fix move to allow overwriting existing files Before this change rclone used a normal SFTP rename if present to implement Move. However the normal SFTP rename won't overwrite existing files. This fixes it to either use the POSIX rename extension ("posix-rename@openssh.com") or to delete the source first before renaming using the normal SFTP rename. This isn't normally a problem as rclone always removes any existing objects first, however to implement non --inplace operations we do require overwriting an existing file. --- backend/sftp/sftp.go | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/backend/sftp/sftp.go b/backend/sftp/sftp.go index 3554343b8..6338534bf 100644 --- a/backend/sftp/sftp.go +++ b/backend/sftp/sftp.go @@ -1329,10 +1329,17 @@ func (f *Fs) Move(ctx context.Context, src fs.Object, remote string) (fs.Object, if err != nil { return nil, fmt.Errorf("Move: %w", err) } - err = c.sftpClient.Rename( - srcObj.path(), - path.Join(f.absRoot, remote), - ) + srcPath, dstPath := srcObj.path(), path.Join(f.absRoot, remote) + if _, ok := c.sftpClient.HasExtension("posix-rename@openssh.com"); ok { + err = c.sftpClient.PosixRename(srcPath, dstPath) + } else { + // If haven't got PosixRename then remove source first before renaming + err = c.sftpClient.Remove(dstPath) + if err != nil && !errors.Is(err, iofs.ErrNotExist) { + fs.Errorf(f, "Move: Failed to remove existing file %q: %v", dstPath, err) + } + err = c.sftpClient.Rename(srcPath, dstPath) + } f.putSftpConnection(&c, err) if err != nil { return nil, fmt.Errorf("Move Rename failed: %w", err)