--- /dev/null
+From 4db00fe229f08b06feeee552ae53af9f49c25048 Mon Sep 17 00:00:00 2001
+From: Luca Barbato <lu_zero@gentoo.org>
+Date: Fri, 10 May 2024 16:38:19 +0200
+Subject: [PATCH] Use an helper to move the files
+
+In case the source is not in the same filesystem.
+---
+ src/bootstrap/src/core/build_steps/dist.rs | 6 ++++--
+ src/bootstrap/src/core/download.rs | 6 +++---
+ src/bootstrap/src/utils/helpers.rs | 15 +++++++++++++++
+ src/bootstrap/src/utils/tarball.rs | 4 ++--
+ 4 files changed, 24 insertions(+), 7 deletions(-)
+
+--- a/src/bootstrap/src/core/build_steps/dist.rs
++++ b/src/bootstrap/src/core/build_steps/dist.rs
+@@ -26,7 +26,9 @@ use crate::core::build_steps::tool::{sel
+ use crate::core::builder::{Builder, Kind, RunConfig, ShouldRun, Step};
+ use crate::core::config::TargetSelection;
+ use crate::utils::channel;
+-use crate::utils::helpers::{exe, is_dylib, output, t, target_supports_cranelift_backend, timeit};
++use crate::utils::helpers::{
++ exe, is_dylib, move_file, output, t, target_supports_cranelift_backend, timeit,
++};
+ use crate::utils::tarball::{GeneratedTarball, OverlayKind, Tarball};
+ use crate::{Compiler, DependencyType, Mode, LLVM_TOOLS};
+
+@@ -1993,7 +1995,7 @@ impl Step for Extended {
+ builder.run(&mut cmd);
+
+ if !builder.config.dry_run() {
+- t!(fs::rename(exe.join(&filename), distdir(builder).join(&filename)));
++ t!(move_file(exe.join(&filename), distdir(builder).join(&filename)));
+ }
+ }
+ }
+--- a/src/bootstrap/src/core/download.rs
++++ b/src/bootstrap/src/core/download.rs
+@@ -12,7 +12,7 @@ use build_helper::ci::CiEnv;
+ use xz2::bufread::XzDecoder;
+
+ use crate::core::config::RustfmtMetadata;
+-use crate::utils::helpers::{check_run, exe, program_out_of_date};
++use crate::utils::helpers::{check_run, exe, move_file, program_out_of_date};
+ use crate::{core::build_steps::llvm::detect_llvm_sha, utils::helpers::hex_encode};
+ use crate::{t, Config};
+
+@@ -209,7 +209,7 @@ impl Config {
+ None => panic!("no protocol in {url}"),
+ }
+ t!(
+- std::fs::rename(&tempfile, dest_path),
++ move_file(&tempfile, dest_path),
+ format!("failed to rename {tempfile:?} to {dest_path:?}")
+ );
+ }
+@@ -313,7 +313,7 @@ impl Config {
+ if src_path.is_dir() && dst_path.exists() {
+ continue;
+ }
+- t!(fs::rename(src_path, dst_path));
++ t!(move_file(src_path, dst_path));
+ }
+ let dst_dir = dst.join(directory_prefix);
+ if dst_dir.exists() {
+--- a/src/bootstrap/src/utils/helpers.rs
++++ b/src/bootstrap/src/utils/helpers.rs
+@@ -150,6 +150,21 @@ pub fn symlink_dir(config: &Config, orig
+ }
+ }
+
++/// Rename a file if from and to are in the same filesystem or
++/// copy and remove the file otherwise
++pub fn move_file<P: AsRef<Path>, Q: AsRef<Path>>(from: P, to: Q) -> io::Result<()> {
++ match fs::rename(&from, &to) {
++ // FIXME: Once `ErrorKind::CrossesDevices` is stabilized use
++ // if e.kind() == io::ErrorKind::CrossesDevices {
++ #[cfg(unix)]
++ Err(e) if e.raw_os_error() == Some(libc::EXDEV) => {
++ std::fs::copy(&from, &to)?;
++ std::fs::remove_file(&from)
++ }
++ r => r,
++ }
++}
++
+ pub fn forcing_clang_based_tests() -> bool {
+ if let Some(var) = env::var_os("RUSTBUILD_FORCE_CLANG_BASED_TESTS") {
+ match &var.to_string_lossy().to_lowercase()[..] {
+--- a/src/bootstrap/src/utils/tarball.rs
++++ b/src/bootstrap/src/utils/tarball.rs
+@@ -6,7 +6,7 @@ use std::{
+ use crate::core::builder::Builder;
+ use crate::core::{build_steps::dist::distdir, builder::Kind};
+ use crate::utils::channel;
+-use crate::utils::helpers::t;
++use crate::utils::helpers::{move_file, t};
+
+ #[derive(Copy, Clone)]
+ pub(crate) enum OverlayKind {
+@@ -269,7 +269,7 @@ impl<'a> Tarball<'a> {
+ // name, not "image". We rename the image directory just before passing
+ // into rust-installer.
+ let dest = self.temp_dir.join(self.package_name());
+- t!(std::fs::rename(&self.image_dir, &dest));
++ t!(move_file(&self.image_dir, &dest));
+
+ self.run(|this, cmd| {
+ let distdir = distdir(this.builder);