about summary refs log tree commit diff
path: root/src/bootstrap
diff options
context:
space:
mode:
author许杰友 Jieyou Xu (Joe) <jieyouxu@outlook.com>2024-08-11 15:37:49 +0000
committer许杰友 Jieyou Xu (Joe) <jieyouxu@outlook.com>2024-08-16 06:55:23 +0000
commit26fae1ed1c7a5e614eae684fa806a1cc4ea0b527 (patch)
treefcbceefca63eac65e71958b86b6683d5b6759aa3 /src/bootstrap
parent69e36d65f93f81f4cbd8a3191c33be3fc201f095 (diff)
downloadrust-26fae1ed1c7a5e614eae684fa806a1cc4ea0b527.tar.gz
rust-26fae1ed1c7a5e614eae684fa806a1cc4ea0b527.zip
bootstrap: fix trying to modify file times on read-only file on Windows
Diffstat (limited to 'src/bootstrap')
-rw-r--r--src/bootstrap/src/core/download.rs4
-rw-r--r--src/bootstrap/src/lib.rs15
-rw-r--r--src/bootstrap/src/utils/helpers.rs12
-rw-r--r--src/bootstrap/src/utils/helpers/tests.rs25
4 files changed, 45 insertions, 11 deletions
diff --git a/src/bootstrap/src/core/download.rs b/src/bootstrap/src/core/download.rs
index fd85650bc56..0e44bd287c0 100644
--- a/src/bootstrap/src/core/download.rs
+++ b/src/bootstrap/src/core/download.rs
@@ -703,9 +703,7 @@ download-rustc = false
             let file_times = fs::FileTimes::new().set_accessed(now).set_modified(now);
 
             let llvm_config = llvm_root.join("bin").join(exe("llvm-config", self.build));
-            let llvm_config_file = t!(File::options().write(true).open(llvm_config));
-
-            t!(llvm_config_file.set_times(file_times));
+            t!(crate::utils::helpers::set_file_times(llvm_config, file_times));
 
             if self.should_fix_bins_and_dylibs() {
                 let llvm_lib = llvm_root.join("lib");
diff --git a/src/bootstrap/src/lib.rs b/src/bootstrap/src/lib.rs
index 1e2e90105a9..784519a20a2 100644
--- a/src/bootstrap/src/lib.rs
+++ b/src/bootstrap/src/lib.rs
@@ -37,7 +37,9 @@ use crate::core::builder;
 use crate::core::builder::{Builder, Kind};
 use crate::core::config::{flags, DryRun, LldMode, LlvmLibunwind, Target, TargetSelection};
 use crate::utils::exec::{command, BehaviorOnFailure, BootstrapCommand, CommandOutput, OutputMode};
-use crate::utils::helpers::{self, dir_is_empty, exe, libdir, mtime, output, symlink_dir};
+use crate::utils::helpers::{
+    self, dir_is_empty, exe, libdir, mtime, output, set_file_times, symlink_dir,
+};
 
 mod core;
 mod utils;
@@ -1792,21 +1794,20 @@ Executed at: {executed_at}"#,
             }
         }
         if let Ok(()) = fs::hard_link(&src, dst) {
-            // Attempt to "easy copy" by creating a hard link
-            // (symlinks don't work on windows), but if that fails
-            // just fall back to a slow `copy` operation.
+            // Attempt to "easy copy" by creating a hard link (symlinks are priviledged on windows),
+            // but if that fails just fall back to a slow `copy` operation.
         } else {
             if let Err(e) = fs::copy(&src, dst) {
                 panic!("failed to copy `{}` to `{}`: {}", src.display(), dst.display(), e)
             }
             t!(fs::set_permissions(dst, metadata.permissions()));
 
+            // Restore file times because changing permissions on e.g. Linux using `chmod` can cause
+            // file access time to change.
             let file_times = fs::FileTimes::new()
                 .set_accessed(t!(metadata.accessed()))
                 .set_modified(t!(metadata.modified()));
-
-            let dst_file = t!(fs::File::open(dst));
-            t!(dst_file.set_times(file_times));
+            t!(set_file_times(dst, file_times));
         }
     }
 
diff --git a/src/bootstrap/src/utils/helpers.rs b/src/bootstrap/src/utils/helpers.rs
index 65e75f114bb..a856c99ff55 100644
--- a/src/bootstrap/src/utils/helpers.rs
+++ b/src/bootstrap/src/utils/helpers.rs
@@ -544,3 +544,15 @@ pub fn get_closest_merge_base_commit(
 
     Ok(output_result(git.as_command_mut())?.trim().to_owned())
 }
+
+/// Sets the file times for a given file at `path`.
+pub fn set_file_times<P: AsRef<Path>>(path: P, times: fs::FileTimes) -> io::Result<()> {
+    // Windows requires file to be writable to modify file times. But on Linux CI the file does not
+    // need to be writable to modify file times and might be read-only.
+    let f = if cfg!(windows) {
+        fs::File::options().write(true).open(path)?
+    } else {
+        fs::File::open(path)?
+    };
+    f.set_times(times)
+}
diff --git a/src/bootstrap/src/utils/helpers/tests.rs b/src/bootstrap/src/utils/helpers/tests.rs
index 103c4d26a18..86016a91e49 100644
--- a/src/bootstrap/src/utils/helpers/tests.rs
+++ b/src/bootstrap/src/utils/helpers/tests.rs
@@ -3,7 +3,8 @@ use std::io::Write;
 use std::path::PathBuf;
 
 use crate::utils::helpers::{
-    check_cfg_arg, extract_beta_rev, hex_encode, make, program_out_of_date, symlink_dir,
+    check_cfg_arg, extract_beta_rev, hex_encode, make, program_out_of_date, set_file_times,
+    symlink_dir,
 };
 use crate::{Config, Flags};
 
@@ -92,3 +93,25 @@ fn test_symlink_dir() {
     #[cfg(not(windows))]
     fs::remove_file(link_path).unwrap();
 }
+
+#[test]
+fn test_set_file_times_sanity_check() {
+    let config =
+        Config::parse(Flags::parse(&["check".to_owned(), "--config=/does/not/exist".to_owned()]));
+    let tempfile = config.tempdir().join(".tmp-file");
+
+    {
+        File::create(&tempfile).unwrap().write_all(b"dummy value").unwrap();
+        assert!(tempfile.exists());
+    }
+
+    // This might only fail on Windows (if file is default read-only then we try to modify file
+    // times).
+    let unix_epoch = std::time::SystemTime::UNIX_EPOCH;
+    let target_time = fs::FileTimes::new().set_accessed(unix_epoch).set_modified(unix_epoch);
+    set_file_times(&tempfile, target_time).unwrap();
+
+    let found_metadata = fs::metadata(tempfile).unwrap();
+    assert_eq!(found_metadata.accessed().unwrap(), unix_epoch);
+    assert_eq!(found_metadata.modified().unwrap(), unix_epoch)
+}