From 605af72f06181409e8755365176417d8a4b27ceb Mon Sep 17 00:00:00 2001 From: Chris Denton Date: Sun, 20 Apr 2025 17:25:17 +0000 Subject: [PATCH] build_helper: try to rename dir before delete --- Cargo.lock | 1 + src/bootstrap/Cargo.lock | 7 +++++++ src/build_helper/Cargo.toml | 1 + src/build_helper/src/fs/mod.rs | 27 ++++++++++++++++++++++++++- 4 files changed, 35 insertions(+), 1 deletion(-) diff --git a/Cargo.lock b/Cargo.lock index 97a90a44a398e..b582177608135 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -332,6 +332,7 @@ dependencies = [ name = "build_helper" version = "0.1.0" dependencies = [ + "fastrand", "serde", "serde_derive", ] diff --git a/src/bootstrap/Cargo.lock b/src/bootstrap/Cargo.lock index 17ee4d610f958..be733b55b1206 100644 --- a/src/bootstrap/Cargo.lock +++ b/src/bootstrap/Cargo.lock @@ -82,6 +82,7 @@ dependencies = [ name = "build_helper" version = "0.1.0" dependencies = [ + "fastrand", "serde", "serde_derive", ] @@ -233,6 +234,12 @@ dependencies = [ "windows-sys 0.52.0", ] +[[package]] +name = "fastrand" +version = "2.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "37909eebbb50d72f9059c3b6d82c0463f2ff062c9e95845c43a6c9c0355411be" + [[package]] name = "fd-lock" version = "4.0.2" diff --git a/src/build_helper/Cargo.toml b/src/build_helper/Cargo.toml index 66894e1abc40e..802fbb754c02c 100644 --- a/src/build_helper/Cargo.toml +++ b/src/build_helper/Cargo.toml @@ -6,5 +6,6 @@ edition = "2021" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] +fastrand = "2.3.0" serde = "1" serde_derive = "1" diff --git a/src/build_helper/src/fs/mod.rs b/src/build_helper/src/fs/mod.rs index 123df76e6a2e9..babfd042f609c 100644 --- a/src/build_helper/src/fs/mod.rs +++ b/src/build_helper/src/fs/mod.rs @@ -1,4 +1,5 @@ //! Misc filesystem related helpers for use by bootstrap and tools. +use std::ffi::{OsStr, OsString}; use std::fs::Metadata; use std::path::Path; use std::{fs, io}; @@ -100,6 +101,30 @@ where pub fn remove_and_create_dir_all>(path: P) -> io::Result<()> { let path = path.as_ref(); - recursive_remove(path)?; + + // Attempt to rename the directory in case removing fails. + // We allow either the rename to fail or the remove to fail but not both. + let rm_path = rand_name(path.as_os_str()); + if fs::rename(path, &rm_path).is_err() { + // Rename failed, try to remove the original path + recursive_remove(&path)?; + } else { + // Rename succeeded, try to remove the renamed path + let _ = recursive_remove(&rm_path); + } fs::create_dir_all(path) } + +fn rand_name(prefix: &OsStr) -> OsString { + let mut name: OsString = prefix.into(); + name.push("-"); + let mut rand_suffix = [0; 8]; + for n in rand_suffix.iter_mut() { + *n = fastrand::alphanumeric() as u8; + } + // SAFETY: `fastrand::alphanumeric` only returns valid ascii. + // Since an `OsStr` is a superset of UTF-8, ascii must be a valid `OsStr`. + let ascii = unsafe { OsStr::from_encoded_bytes_unchecked(&rand_suffix) }; + name.push(ascii); + name +}