Auto merge of #8453 - sourcefrog:name-length-limit-8452, r=alexcrichton

Write GNU tar files, supporting long names.

Fixes #8452

If I understand the previous bugs correctly, long trees packaged using Cargo with this patch will be misinterpreted by Cargo from before Jan 2016. (Without this patch, they can't be written at all.)

To me that seems like long enough ago that it's safe to land this now.

- [x] Add a test.
This commit is contained in:
bors 2020-07-06 15:27:16 +00:00
commit 548eea773f
2 changed files with 50 additions and 26 deletions

View File

@ -501,28 +501,7 @@ fn tar(
config
.shell()
.verbose(|shell| shell.status("Archiving", &rel_str))?;
// The `tar::Builder` type by default will build GNU archives, but
// unfortunately we force it here to use UStar archives instead. The
// UStar format has more limitations on the length of path name that it
// can encode, so it's not quite as nice to use.
//
// Older cargos, however, had a bug where GNU archives were interpreted
// as UStar archives. This bug means that if we publish a GNU archive
// which has fully filled out metadata it'll be corrupt when unpacked by
// older cargos.
//
// Hopefully in the future after enough cargos have been running around
// with the bugfixed tar-rs library we'll be able to switch this over to
// GNU archives, but for now we'll just say that you can't encode paths
// in archives that are *too* long.
//
// For an instance of this in the wild, use the tar-rs 0.3.3 library to
// unpack the selectors 0.4.0 crate on crates.io. Either that or take a
// look at rust-lang/cargo#2326.
let mut header = Header::new_ustar();
header
.set_path(&ar_path)
.chain_err(|| format!("failed to add to archive: `{}`", rel_str))?;
let mut header = Header::new_gnu();
match contents {
FileContents::OnDisk(disk_path) => {
let mut file = File::open(&disk_path).chain_err(|| {
@ -533,9 +512,10 @@ fn tar(
})?;
header.set_metadata(&metadata);
header.set_cksum();
ar.append(&header, &mut file).chain_err(|| {
format!("could not archive source file `{}`", disk_path.display())
})?;
ar.append_data(&mut header, &ar_path, &mut file)
.chain_err(|| {
format!("could not archive source file `{}`", disk_path.display())
})?;
}
FileContents::Generated(generated_kind) => {
let contents = match generated_kind {
@ -553,7 +533,7 @@ fn tar(
);
header.set_size(contents.len() as u64);
header.set_cksum();
ar.append(&header, contents.as_bytes())
ar.append_data(&mut header, &ar_path, contents.as_bytes())
.chain_err(|| format!("could not archive source file `{}`", rel_str))?;
}
}

View File

@ -1845,3 +1845,47 @@ dependency `bar` does not specify a version.
)
.run();
}
#[cargo_test]
fn long_file_names() {
// Filenames over 100 characters require a GNU extension tarfile.
// See #8453.
registry::init();
let long_name = concat!(
"012345678901234567890123456789012345678901234567890123456789",
"012345678901234567890123456789012345678901234567890123456789",
"012345678901234567890123456789012345678901234567890123456789"
);
let p = project()
.file(
"Cargo.toml",
r#"
[package]
name = "foo"
version = "0.1.0"
license = "MIT"
description = "foo"
homepage = "foo"
[dependencies]
"#,
)
.file(long_name, "something")
.file("src/main.rs", "fn main() {}")
.build();
p.cargo("package").run();
p.cargo("package --list")
.with_stdout(&format!(
"\
{}
Cargo.lock
Cargo.toml
Cargo.toml.orig
src/main.rs
",
long_name
))
.run();
}