Skip to content

Commit

Permalink
Fix race condition between simultaneous build scripts creating symlinks
Browse files Browse the repository at this point in the history
  • Loading branch information
dtolnay committed Sep 24, 2021
1 parent 36d9ac1 commit 1dd71ca
Show file tree
Hide file tree
Showing 2 changed files with 26 additions and 2 deletions.
19 changes: 17 additions & 2 deletions gen/build/src/out.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
use crate::error::{Error, Result};
use crate::gen::fs;
use crate::paths;
use std::io;
use std::path::Path;

pub(crate) fn write(path: impl AsRef<Path>, content: &[u8]) -> Result<()> {
Expand Down Expand Up @@ -43,8 +44,22 @@ pub(crate) fn symlink_file(original: impl AsRef<Path>, link: impl AsRef<Path>) -
match paths::symlink_or_copy(original, link) {
// As long as symlink_or_copy succeeded, ignore any create_dir_all error.
Ok(()) => Ok(()),
// If create_dir_all and symlink_or_copy both failed, prefer the first error.
Err(err) => Err(Error::Fs(create_dir_error.unwrap_or(err))),
Err(err) => {
if err.kind() == io::ErrorKind::AlreadyExists {
// This is fine, a different simultaneous build script already
// created the same link or copy. The cxx_build target directory
// is laid out such that the same path never refers to two
// different targets during the same multi-crate build, so if
// some other build script already created the same path then we
// know it refers to the identical target that the current build
// script was trying to create.
Ok(())
} else {
// If create_dir_all and symlink_or_copy both failed, prefer the
// first error.
Err(Error::Fs(create_dir_error.unwrap_or(err)))
}
}
}
}

Expand Down
9 changes: 9 additions & 0 deletions gen/src/fs.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,15 @@ pub(crate) struct Error {
message: String,
}

impl Error {
pub fn kind(&self) -> io::ErrorKind {
match &self.source {
Some(io_error) => io_error.kind(),
None => io::ErrorKind::Other,
}
}
}

impl Display for Error {
fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
formatter.write_str(&self.message)
Expand Down

0 comments on commit 1dd71ca

Please sign in to comment.