Skip to content

If creating a temporary directory fails with permission denied then retry with backoff #140086

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Apr 26, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion Cargo.lock
Original file line number Diff line number Diff line change
Expand Up @@ -3740,6 +3740,9 @@ dependencies = [
[[package]]
name = "rustc_fs_util"
version = "0.0.0"
dependencies = [
"tempfile",
]

[[package]]
name = "rustc_graphviz"
Expand Down Expand Up @@ -4052,7 +4055,6 @@ dependencies = [
"rustc_session",
"rustc_span",
"rustc_target",
"tempfile",
"tracing",
]

Expand Down
4 changes: 2 additions & 2 deletions compiler/rustc_codegen_ssa/src/back/archive.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,9 +13,9 @@ use object::read::archive::ArchiveFile;
use object::read::macho::FatArch;
use rustc_data_structures::fx::FxIndexSet;
use rustc_data_structures::memmap::Mmap;
use rustc_fs_util::TempDirBuilder;
use rustc_session::Session;
use rustc_span::Symbol;
use tempfile::Builder as TempFileBuilder;
use tracing::trace;

use super::metadata::search_for_section;
Expand Down Expand Up @@ -501,7 +501,7 @@ impl<'a> ArArchiveBuilder<'a> {
// it creates. We need it to be the default mode for back compat reasons however. (See
// #107495) To handle this we are telling tempfile to create a temporary directory instead
// and then inside this directory create a file using File::create.
let archive_tmpdir = TempFileBuilder::new()
let archive_tmpdir = TempDirBuilder::new()
.suffix(".temp-archive")
.tempdir_in(output.parent().unwrap_or_else(|| Path::new("")))
.map_err(|err| {
Expand Down
5 changes: 2 additions & 3 deletions compiler/rustc_codegen_ssa/src/back/link.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ use rustc_data_structures::fx::FxIndexSet;
use rustc_data_structures::memmap::Mmap;
use rustc_data_structures::temp_dir::MaybeTempDir;
use rustc_errors::{DiagCtxtHandle, LintDiagnostic};
use rustc_fs_util::{fix_windows_verbatim_for_gcc, try_canonicalize};
use rustc_fs_util::{TempDirBuilder, fix_windows_verbatim_for_gcc, try_canonicalize};
use rustc_hir::def_id::{CrateNum, LOCAL_CRATE};
use rustc_macros::LintDiagnostic;
use rustc_metadata::fs::{METADATA_FILENAME, copy_to_stdout, emit_wrapper_file};
Expand Down Expand Up @@ -48,7 +48,6 @@ use rustc_target::spec::{
LinkerFeatures, LinkerFlavor, LinkerFlavorCli, Lld, PanicStrategy, RelocModel, RelroLevel,
SanitizerSet, SplitDebuginfo,
};
use tempfile::Builder as TempFileBuilder;
use tracing::{debug, info, warn};

use super::archive::{ArchiveBuilder, ArchiveBuilderBuilder};
Expand Down Expand Up @@ -100,7 +99,7 @@ pub fn link_binary(
});

if outputs.outputs.should_link() {
let tmpdir = TempFileBuilder::new()
let tmpdir = TempDirBuilder::new()
.prefix("rustc")
.tempdir()
.unwrap_or_else(|error| sess.dcx().emit_fatal(errors::CreateTempDir { error }));
Expand Down
1 change: 1 addition & 0 deletions compiler/rustc_fs_util/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -5,4 +5,5 @@ edition = "2024"

[dependencies]
# tidy-alphabetical-start
tempfile = "3.7.1"
# tidy-alphabetical-end
46 changes: 44 additions & 2 deletions compiler/rustc_fs_util/src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
use std::ffi::CString;
use std::ffi::{CString, OsStr};
use std::path::{Path, PathBuf, absolute};
use std::{fs, io};
use std::{env, fs, io};

use tempfile::TempDir;

// Unfortunately, on windows, it looks like msvcrt.dll is silently translating
// verbatim paths under the hood to non-verbatim paths! This manifests itself as
Expand Down Expand Up @@ -102,3 +104,43 @@ pub fn path_to_c_string(p: &Path) -> CString {
pub fn try_canonicalize<P: AsRef<Path>>(path: P) -> io::Result<PathBuf> {
fs::canonicalize(&path).or_else(|_| absolute(&path))
}

pub struct TempDirBuilder<'a, 'b> {
builder: tempfile::Builder<'a, 'b>,
}

impl<'a, 'b> TempDirBuilder<'a, 'b> {
pub fn new() -> Self {
Self { builder: tempfile::Builder::new() }
}

pub fn prefix<S: AsRef<OsStr> + ?Sized>(&mut self, prefix: &'a S) -> &mut Self {
self.builder.prefix(prefix);
self
}

pub fn suffix<S: AsRef<OsStr> + ?Sized>(&mut self, suffix: &'b S) -> &mut Self {
self.builder.suffix(suffix);
self
}

pub fn tempdir_in<P: AsRef<Path>>(&self, dir: P) -> io::Result<TempDir> {
let dir = dir.as_ref();
// On Windows in CI, we had been getting fairly frequent "Access is denied"
// errors when creating temporary directories.
// So this implements a simple retry with backoff loop.
#[cfg(windows)]
for wait in 1..11 {
match self.builder.tempdir_in(dir) {
Err(e) if e.kind() == io::ErrorKind::PermissionDenied => {}
t => return t,
}
std::thread::sleep(std::time::Duration::from_millis(1 << wait));
}
self.builder.tempdir_in(dir)
}

pub fn tempdir(&self) -> io::Result<TempDir> {
self.tempdir_in(env::temp_dir())
}
}
1 change: 0 additions & 1 deletion compiler/rustc_metadata/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,6 @@ rustc_serialize = { path = "../rustc_serialize" }
rustc_session = { path = "../rustc_session" }
rustc_span = { path = "../rustc_span" }
rustc_target = { path = "../rustc_target" }
tempfile = "3.2"
tracing = "0.1"
# tidy-alphabetical-end

Expand Down
4 changes: 2 additions & 2 deletions compiler/rustc_metadata/src/fs.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,11 @@ use std::path::{Path, PathBuf};
use std::{fs, io};

use rustc_data_structures::temp_dir::MaybeTempDir;
use rustc_fs_util::TempDirBuilder;
use rustc_middle::ty::TyCtxt;
use rustc_session::config::{CrateType, OutFileName, OutputType};
use rustc_session::output::filename_for_metadata;
use rustc_session::{MetadataKind, Session};
use tempfile::Builder as TempFileBuilder;

use crate::errors::{
BinaryOutputToTty, FailedCopyToStdout, FailedCreateEncodedMetadata, FailedCreateFile,
Expand Down Expand Up @@ -45,7 +45,7 @@ pub fn encode_and_write_metadata(tcx: TyCtxt<'_>) -> (EncodedMetadata, bool) {
// final destination, with an `fs::rename` call. In order for the rename to
// always succeed, the temporary file needs to be on the same filesystem,
// which is why we create it inside the output directory specifically.
let metadata_tmpdir = TempFileBuilder::new()
let metadata_tmpdir = TempDirBuilder::new()
.prefix("rmeta")
.tempdir_in(out_filename.parent().unwrap_or_else(|| Path::new("")))
.unwrap_or_else(|err| tcx.dcx().emit_fatal(FailedCreateTempdir { err }));
Expand Down
Loading