]> git.lizzy.rs Git - rust.git/blobdiff - compiler/rustc_codegen_ssa/src/back/archive.rs
Auto merge of #103591 - lqd:win-lto, r=Mark-Simulacrum
[rust.git] / compiler / rustc_codegen_ssa / src / back / archive.rs
index 280fa49e29b60ef941717e26e18058d5dd1705be..58558fb8c4ba2912b53f7fcef66c10c676c4a7aa 100644 (file)
@@ -10,6 +10,7 @@
 use ar_archive_writer::{write_archive_to_stream, ArchiveKind, NewArchiveMember};
 use object::read::archive::ArchiveFile;
 use object::read::macho::FatArch;
+use tempfile::Builder as TempFileBuilder;
 
 use std::error::Error;
 use std::fs::File;
@@ -271,12 +272,35 @@ fn build_inner(self, output: &Path) -> io::Result<bool> {
             })
         }
 
-        let mut w = File::create(output)
-            .map_err(|err| io_error_context("failed to create archive file", err))?;
-
-        write_archive_to_stream(&mut w, &entries, true, archive_kind, true, false)?;
-
-        Ok(!entries.is_empty())
+        // Write to a temporary file first before atomically renaming to the final name.
+        // This prevents programs (including rustc) from attempting to read a partial archive.
+        // It also enables writing an archive with the same filename as a dependency on Windows as
+        // required by a test.
+        let mut archive_tmpfile = TempFileBuilder::new()
+            .suffix(".temp-archive")
+            .tempfile_in(output.parent().unwrap_or_else(|| Path::new("")))
+            .map_err(|err| io_error_context("couldn't create a temp file", err))?;
+
+        write_archive_to_stream(
+            archive_tmpfile.as_file_mut(),
+            &entries,
+            true,
+            archive_kind,
+            true,
+            false,
+        )?;
+
+        let any_entries = !entries.is_empty();
+        drop(entries);
+        // Drop src_archives to unmap all input archives, which is necessary if we want to write the
+        // output archive to the same location as an input archive on Windows.
+        drop(self.src_archives);
+
+        archive_tmpfile
+            .persist(output)
+            .map_err(|err| io_error_context("failed to rename archive file", err.error))?;
+
+        Ok(any_entries)
     }
 }