pull: ignore the pax global header when detecting a tarball wrapper
Git-archive tarballs open with a pax global header record
('pax_global_header'): GNU tar consumes it and never lists or
extracts it, but the tar crate yields it as an entry. Counting it
for the wrapper detection made every git-archive orig look
multi-rooted - linux-riscv's orig stayed nested under 'linux-6.8/'
and its .diff.gz failed to apply with 'can't find file to patch'.
Skip the record outright: unpack would no-op on it anyway, so this
only keeps it out of the wrapper detection (and the tree).
This commit is contained in:
+47
@@ -263,6 +263,19 @@ where
|
||||
|
||||
for entry in archive.entries()? {
|
||||
let mut entry = entry?;
|
||||
|
||||
// A pax global header record ('pax_global_header', the opening
|
||||
// entry of git-archive tarballs) is metadata about the archive,
|
||||
// not content: GNU tar consumes it and never lists or extracts
|
||||
// it, but the tar crate yields it as an entry. It must not be
|
||||
// extracted (unpack would no-op) and must not count for the
|
||||
// wrapper detection below — it used to make every git-archive
|
||||
// orig look multi-rooted, skipping the unwrap and leaving the
|
||||
// sources nested one level too deep.
|
||||
if entry.header().entry_type().is_pax_global_extensions() {
|
||||
continue;
|
||||
}
|
||||
|
||||
let path = entry.path()?.to_path_buf();
|
||||
|
||||
// Archives built with './'-prefixed entries (common in third-party
|
||||
@@ -1235,6 +1248,40 @@ mod tests {
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_extract_tar_skips_pax_global_header() {
|
||||
// Regression: git-archive tarballs open with a pax global header
|
||||
// record ('pax_global_header'): GNU tar consumes it and never
|
||||
// lists or extracts it, but the tar crate yields it as an entry.
|
||||
// Counting it for the wrapper detection made every git-archive
|
||||
// orig look multi-rooted: the unwrap was skipped, the sources
|
||||
// stayed nested one level too deep and the package's .diff.gz
|
||||
// did not apply (linux-riscv).
|
||||
let temp_dir = tempfile::tempdir().unwrap();
|
||||
let tar_path = temp_dir.path().join("git.orig.tar");
|
||||
let mut tar_bytes = Vec::new();
|
||||
push_tar_entry(
|
||||
&mut tar_bytes,
|
||||
"pax_global_header",
|
||||
b'g',
|
||||
b"52 comment=d0e1c2d",
|
||||
None,
|
||||
);
|
||||
push_tar_entry(&mut tar_bytes, "pkg-1.0/Makefile", b'0', b"all:", None);
|
||||
tar_bytes.extend_from_slice(&[0u8; 1024]);
|
||||
std::fs::write(&tar_path, tar_bytes).unwrap();
|
||||
|
||||
let tree = temp_dir.path().join("tree");
|
||||
let extracted = extract_tar_archive(&tar_path, &tree, None, |f| f).unwrap();
|
||||
unwrap_wrapper(&tree, &extracted.wrapper.unwrap()).unwrap();
|
||||
|
||||
assert!(!tree.join("pax_global_header").exists());
|
||||
assert_eq!(
|
||||
std::fs::read_to_string(tree.join("Makefile")).unwrap(),
|
||||
"all:"
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_extract_tar_rejects_hardlink_escape() {
|
||||
let temp_dir = tempfile::tempdir().unwrap();
|
||||
|
||||
Reference in New Issue
Block a user