Keep GNU tar timestamps out of recovered member names (R3.12) (from #613)

This commit is contained in:
Afloat
2026-11-03 20:04:56 +07:00
committed by bflatastic
parent 1790c544f7
commit 982b091bf8
2 changed files with 33 additions and 1 deletions
+2 -1
View File
@@ -177,7 +177,8 @@ pub fn tar(data: &[u8], max_members: usize) -> Option<Listing> {
}
b'g' => {}
_ => {
let ustar = h.get(257..262) == Some(b"ustar");
// Old GNU headers use these bytes for timestamps and sparse-file metadata.
let ustar = h.get(257..263) == Some(b"ustar\0");
let base = text(h.get(0..100).unwrap_or(&[]));
let prefix = if ustar { text(h.get(345..500).unwrap_or(&[])) } else { String::new() };
let joined = if prefix.is_empty() { base } else { format!("{prefix}/{base}") };
+31
View File
@@ -0,0 +1,31 @@
use craft_anything_formats::tarcpio::{member_data, tar};
use craft_anything_testkit::firmware as fx;
fn checksum(header: &mut [u8]) {
header[148..156].fill(b' ');
let sum: u32 = header.iter().map(|&b| u32::from(b)).sum();
header[148..156].copy_from_slice(format!("{sum:06o}\0 ").as_bytes());
}
#[test]
fn old_gnu_timestamps_are_not_posix_path_prefixes() {
let mut archive = fx::tar(&[("program", b"payload")]);
let header = &mut archive[..512];
header[257..265].copy_from_slice(b"ustar \0");
header[345..357].copy_from_slice(b"00000000123\0");
header[357..369].copy_from_slice(b"00000000456\0");
checksum(header);
let listing = tar(&archive, 10).unwrap();
assert!(listing.complete);
assert_eq!(listing.members[0].name, "program");
assert_eq!(member_data(&archive, &listing.members[0]), Some(b"payload".as_slice()));
}
#[test]
fn posix_ustar_prefixes_are_still_joined() {
let mut archive = fx::tar(&[("program", b"payload")]);
let header = &mut archive[..512];
header[345..352].copy_from_slice(b"usr/bin");
checksum(header);
assert_eq!(tar(&archive, 10).unwrap().members[0].name, "usr/bin/program");
}