Skip to content

Commit 2f6852f

Browse files
committed
fix: update mtime for generated files after unpacking
This is the unpacking half of #16237 Updating mtime for all files might not be worthy as crate published after 1.54 should all have the deterministic mtime for non-generated files, except those did manual upload. This patch is aimed at fixing the "regression" of vendor direct extraction, rather than a complete fix of the non-deterministic mtime. Also there are workarounds, so the workflow is not completely blocked. Since Cargo had a couple CVEs around tar and unpack, I separate the mtime update logic from the main unpack logic, so that each function's intent is clearer. Hope it won't introduce new vulnerability
1 parent c3fbb4d commit 2f6852f

File tree

3 files changed

+24
-2
lines changed

3 files changed

+24
-2
lines changed

src/cargo/sources/registry/mod.rs

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -635,6 +635,7 @@ impl<'gctx> RegistrySource<'gctx> {
635635
dst.create_dir()?;
636636

637637
let bytes_written = unpack(self.gctx, tarball, unpack_dir, &|_| true)?;
638+
update_mtime_for_generated_files(unpack_dir);
638639

639640
// Now that we've finished unpacking, create and write to the lock file to indicate that
640641
// unpacking was successful.
@@ -679,6 +680,7 @@ impl<'gctx> RegistrySource<'gctx> {
679680
let tarball =
680681
File::open(path).with_context(|| format!("failed to open {}", path.display()))?;
681682
unpack(self.gctx, &tarball, &dst, include)?;
683+
update_mtime_for_generated_files(&dst);
682684
Ok(dst)
683685
}
684686

@@ -1104,3 +1106,25 @@ fn unpack(
11041106

11051107
Ok(bytes_written)
11061108
}
1109+
1110+
/// Workaround for rust-lang/cargo#16237
1111+
///
1112+
/// Generated files should have the same deterministic mtime as other files.
1113+
/// However, since we forgot to set mtime for those files when uploading, they
1114+
/// always have older mtime (1973-11-29) that prevents zip from packing (requiring >1980)
1115+
///
1116+
/// This workaround updates mtime after we unpack the tarball at the destination.
1117+
fn update_mtime_for_generated_files(pkg_root: &Path) {
1118+
const GENERATED_FILES: &[&str] = &["Cargo.lock", "Cargo.toml", ".cargo_vcs_info.json"];
1119+
// Hardcoded value be removed once alexcrichton/tar-rs#420 is merged and released.
1120+
// See also rust-lang/cargo#16237
1121+
const DETERMINISTIC_TIMESTAMP: i64 = 1153704088;
1122+
1123+
for file in GENERATED_FILES {
1124+
let path = pkg_root.join(file);
1125+
let mtime = filetime::FileTime::from_unix_time(DETERMINISTIC_TIMESTAMP, 0);
1126+
if let Err(e) = filetime::set_file_mtime(&path, mtime) {
1127+
tracing::trace!("failed to set deterministic mtime for {path:?}: {e}");
1128+
}
1129+
}
1130+
}

tests/testsuite/registry.rs

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4656,7 +4656,6 @@ required by package `foo v0.0.1 ([ROOT]/foo)`
46564656
}
46574657

46584658
#[cargo_test]
4659-
#[should_panic]
46604659
fn deterministic_mtime() {
46614660
let registry = registry::init();
46624661
Package::new("foo", "0.1.0")

tests/testsuite/vendor.rs

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2122,7 +2122,6 @@ fn vendor_rename_fallback() {
21222122
}
21232123

21242124
#[cargo_test]
2125-
#[should_panic]
21262125
fn deterministic_mtime() {
21272126
Package::new("foo", "0.1.0")
21282127
// content doesn't matter, we just want to check mtime

0 commit comments

Comments
 (0)