Skip to content

Commit ec49c75

Browse files
committed
Add missing truncate when writing .crate files (#16688)
<!-- _Thanks for the pull request 🎉!_ _Please read the contribution guide: <https://doc.crates.io/contrib/>._ --> ### What does this PR try to resolve? Fixes #16683 by adding manuall truncate. <!-- _Explain the motivation behind this change._ _A clear overview along with an in-depth explanation are helpful._ --> ### How to test and review this PR? See the original issue for mCVE. <!-- _Demonstrate how you test this change and guide reviewers through your PR._ _With a smooth review process, a pull request usually gets reviewed quicker._ -->
1 parent 6ab9b00 commit ec49c75

2 files changed

Lines changed: 138 additions & 0 deletions

File tree

src/cargo/ops/cargo_package/mod.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -221,6 +221,7 @@ pub fn package(ws: &Workspace<'_>, opts: &PackageOpts<'_>) -> CargoResult<Vec<Fi
221221
for (pkg, _, src) in packaged {
222222
let filename = pkg.package_id().tarball_name();
223223
let dst = artifact_dir.open_rw_exclusive_create(filename, ws.gctx(), "uplifted package")?;
224+
dst.file().set_len(0)?;
224225
src.file().seek(SeekFrom::Start(0))?;
225226
std::io::copy(&mut src.file(), &mut dst.file())?;
226227
result.push(dst);
@@ -1157,6 +1158,7 @@ impl<'a> TmpRegistry<'a> {
11571158
self.gctx,
11581159
"temporary package registry",
11591160
)?;
1161+
tar_copy.file().set_len(0)?;
11601162
tar.file().seek(SeekFrom::Start(0))?;
11611163
std::io::copy(&mut tar.file(), &mut tar_copy)?;
11621164
tar_copy.flush()?;
@@ -1229,6 +1231,7 @@ impl<'a> TmpRegistry<'a> {
12291231
self.gctx,
12301232
"temporary package registry",
12311233
)?;
1234+
dst.file().set_len(0)?;
12321235
dst.write_all(index_line.as_bytes())?;
12331236
Ok(())
12341237
}

tests/testsuite/package.rs

Lines changed: 135 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7895,3 +7895,138 @@ fn package_dir_not_excluded_from_backups() {
78957895
"CACHEDIR.TAG should exist in target directory to exclude it from backups"
78967896
);
78977897
}
7898+
7899+
#[cargo_test]
7900+
fn repackage_smaller_crate_has_trailing_garbage() {
7901+
// When a package is re-packaged and the new .crate file is smaller than
7902+
// the previous one, the artifact on disk should be smaller without trailing garbage bytes.
7903+
let big_file_contents = "x".repeat(100_000);
7904+
let p = project()
7905+
.file(
7906+
"Cargo.toml",
7907+
r#"
7908+
[package]
7909+
name = "foo"
7910+
version = "0.0.1"
7911+
edition = "2021"
7912+
include = ["src/**", "Cargo.toml", "big.txt"]
7913+
"#,
7914+
)
7915+
.file("src/lib.rs", "")
7916+
.file("big.txt", &big_file_contents)
7917+
.build();
7918+
7919+
// First package run: includes big.txt, so the .crate file is large.
7920+
p.cargo("package --no-verify").run();
7921+
7922+
let crate_path = p.root().join("target/package/foo-0.0.1.crate");
7923+
let first_size = fs::metadata(&crate_path).unwrap().len();
7924+
7925+
// Remove big.txt from the project so the next package will be smaller.
7926+
fs::remove_file(p.root().join("big.txt")).unwrap();
7927+
7928+
// Update the manifest to no longer include big.txt.
7929+
p.change_file(
7930+
"Cargo.toml",
7931+
r#"
7932+
[package]
7933+
name = "foo"
7934+
version = "0.0.1"
7935+
edition = "2021"
7936+
include = ["src/**", "Cargo.toml"]
7937+
"#,
7938+
);
7939+
7940+
// Second package run: no big.txt, so the .crate file should be much smaller.
7941+
p.cargo("package --no-verify").run();
7942+
7943+
let second_size = fs::metadata(&crate_path).unwrap().len();
7944+
7945+
// The target .crate file *is* smaller.
7946+
assert!(
7947+
first_size > second_size,
7948+
"the .crate file should be smaller after removing big.txt"
7949+
);
7950+
}
7951+
7952+
#[cargo_test]
7953+
fn repackage_smaller_local_dep_tmp_registry_checksum_match() {
7954+
let reg = registry::init();
7955+
let big_file_contents = "x".repeat(100_000);
7956+
let p = project()
7957+
.file(
7958+
"Cargo.toml",
7959+
r#"
7960+
[workspace]
7961+
members = ["foo", "bar"]
7962+
resolver = "2"
7963+
"#,
7964+
)
7965+
.file(
7966+
"foo/Cargo.toml",
7967+
r#"
7968+
[package]
7969+
name = "foo"
7970+
version = "0.0.1"
7971+
edition = "2021"
7972+
7973+
[dependencies]
7974+
bar = { path = "../bar", version = "0.0.1" }
7975+
"#,
7976+
)
7977+
.file("foo/src/lib.rs", "pub fn foo() { bar::bar(); }")
7978+
.file(
7979+
"bar/Cargo.toml",
7980+
r#"
7981+
[package]
7982+
name = "bar"
7983+
version = "0.0.1"
7984+
edition = "2021"
7985+
include = ["src/**", "Cargo.toml", "big.txt"]
7986+
"#,
7987+
)
7988+
.file("bar/src/lib.rs", "pub fn bar() {}")
7989+
.file("bar/big.txt", &big_file_contents)
7990+
.build();
7991+
7992+
p.cargo("package --workspace --no-verify")
7993+
.replace_crates_io(reg.index_url())
7994+
.run();
7995+
7996+
fs::remove_file(p.root().join("bar/big.txt")).unwrap();
7997+
p.change_file(
7998+
"bar/Cargo.toml",
7999+
r#"
8000+
[package]
8001+
name = "bar"
8002+
version = "0.0.1"
8003+
edition = "2021"
8004+
include = ["src/**", "Cargo.toml"]
8005+
"#,
8006+
);
8007+
p.cargo("package --workspace --no-verify")
8008+
.replace_crates_io(reg.index_url())
8009+
.run();
8010+
8011+
let index_line = read_to_string(p.root().join("target/package/tmp-registry/index/3/b/bar"))
8012+
.unwrap()
8013+
.lines()
8014+
.last()
8015+
.unwrap()
8016+
.to_owned();
8017+
let expected_cksum = serde_json::from_str::<serde_json::Value>(&index_line)
8018+
.unwrap()
8019+
.get("cksum")
8020+
.and_then(|value| value.as_str())
8021+
.unwrap()
8022+
.to_owned();
8023+
8024+
let crate_contents =
8025+
fs::read(p.root().join("target/package/tmp-registry/bar-0.0.1.crate")).unwrap();
8026+
let actual_cksum = registry::cksum(&crate_contents);
8027+
8028+
assert_eq!(
8029+
expected_cksum, actual_cksum,
8030+
"tmp-registry crate checksum should match index entry"
8031+
);
8032+
}

0 commit comments

Comments
 (0)