Skip to content

Commit

Permalink
Merge pull request #2410 from StarryInternet/issue-1239
Browse files Browse the repository at this point in the history
Fallback to copy when rename causes cross-link error
  • Loading branch information
rbtcollins authored Aug 10, 2020
2 parents 6399370 + d847b54 commit df179c3
Show file tree
Hide file tree
Showing 2 changed files with 44 additions and 0 deletions.
8 changes: 8 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -726,6 +726,14 @@ currently can define only `default_toolchain`.
- `RUSTUP_NO_BACKTRACE`
Disables backtraces on non-panic errors even when `RUST_BACKTRACE` is set.

- `RUSTUP_PERMIT_COPY_RENAME`
*unstable* When set, allows rustup to fall-back to copying files if attempts to
`rename` result in an cross-device link errors. These errors occur on OverlayFS,
which is used by [Docker][dc]. This feature sacrifices some transactions protections
and may be removed at any point. Linux only.

[dc]: (https://docs.docker.com/storage/storagedriver/overlayfs-driver/#modifying-files-or-directories)

## Other installation methods

The primary installation method, as described at https://rustup.rs, differs by platform:
Expand Down
36 changes: 36 additions & 0 deletions src/utils/utils.rs
Original file line number Diff line number Diff line change
Expand Up @@ -593,6 +593,30 @@ pub fn toolchain_sort<T: AsRef<str>>(v: &mut Vec<T>) {
});
}

fn copy_and_delete<'a, N>(
name: &'static str,
src: &'a Path,
dest: &'a Path,
notify_handler: &'a dyn Fn(N),
) -> Result<()>
where
N: From<Notification<'a>>,
{
// https://github.com/rust-lang/rustup/issues/1239
// This uses std::fs::copy() instead of the faster std::fs::rename() to
// avoid cross-device link errors.
if src.is_dir() {
copy_dir(src, dest, notify_handler).and(remove_dir_all::remove_dir_all(src).chain_err(
|| ErrorKind::RemovingDirectory {
name,
path: PathBuf::from(src),
},
))
} else {
copy_file(src, dest).and(remove_file(name, src))
}
}

fn rename<'a, N>(
name: &'static str,
src: &'a Path,
Expand All @@ -606,6 +630,8 @@ where
// 21 fib steps from 1 sums to ~28 seconds, hopefully more than enough
// for our previous poor performance that avoided the race condition with
// McAfee and Norton.
#[cfg(target_os = "linux")]
use libc::EXDEV;
retry(
Fibonacci::from_millis(1).map(jitter).take(26),
|| match fs::rename(src, dest) {
Expand All @@ -615,6 +641,16 @@ where
notify_handler(Notification::RenameInUse(&src, &dest).into());
OperationResult::Retry(e)
}
#[cfg(target_os = "linux")]
io::ErrorKind::Other
if process().var_os("RUSTUP_PERMIT_COPY_RENAME").is_some()
&& Some(EXDEV) == e.raw_os_error() =>
{
match copy_and_delete(name, src, dest, notify_handler) {
Ok(()) => OperationResult::Ok(()),
Err(_) => OperationResult::Err(e),
}
}
_ => OperationResult::Err(e),
},
},
Expand Down

0 comments on commit df179c3

Please sign in to comment.