Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Write GNU tar files, supporting long names. #8453

Merged
merged 2 commits into from
Jul 6, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
32 changes: 6 additions & 26 deletions src/cargo/ops/cargo_package.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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(|| {
Expand All @@ -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 {
Expand All @@ -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))?;
}
}
Expand Down
44 changes: 44 additions & 0 deletions tests/testsuite/package.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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();
}