Preserve sparse ext positions across indirect levels (from #705)

This commit is contained in:
Afloat
2026-11-04 01:12:03 +07:00
committed by bflatastic
parent 009313c429
commit cacaa2aade
2 changed files with 43 additions and 0 deletions
+2
View File
@@ -107,6 +107,8 @@ fn file_block_map(data: &[u8], sb: &Sb, inode_off: u64, flags: u32, nblocks: u64
if let Some(ind) = r.u32_le(ib + 48).filter(|&p| p != 0) {
read_indirect(data, sb, u64::from(ind), 1, per, &mut logical, &mut map);
}
// The single-indirect span still occupies its logical blocks when its root is absent.
logical = 12 + per;
// Double indirect.
if let Some(dind) = r.u32_le(ib + 52).filter(|&p| p != 0) {
read_indirect(data, sb, u64::from(dind), 2, per, &mut logical, &mut map);
@@ -0,0 +1,41 @@
use craft_anything_formats::fsread::{self, Limits};
const BS: usize = 1024;
const FILE_INODE: usize = 5120 + 10 * 128;
fn put(data: &mut [u8], at: usize, value: u32) {
data[at..at + 4].copy_from_slice(&value.to_le_bytes());
}
#[test]
fn a_missing_single_indirect_root_keeps_the_whole_sparse_span() {
let mut data = craft_anything_testkit::firmware::ext_image(false);
data.resize(14 * BS, 0);
put(&mut data, 1024 + 4, 14);
data[FILE_INODE + 40..FILE_INODE + 100].fill(0);
put(&mut data, FILE_INODE + 4, (269 * BS) as u32);
put(&mut data, FILE_INODE + 92, 11);
put(&mut data, 11 * BS, 12);
put(&mut data, 12 * BS, 13);
data[13 * BS..13 * BS + 4].copy_from_slice(b"tail");
let image = fsread::extfs::read(&data, &Limits::default());
let recovered = image.entries.iter().find(|e| e.path == "hello.txt").unwrap().data.as_ref().unwrap();
assert!(recovered[..268 * BS].iter().all(|b| *b == 0));
assert_eq!(&recovered[268 * BS..268 * BS + 4], b"tail");
assert!(image.complete, "{:?}", image.warnings);
}
#[test]
fn an_existing_single_indirect_block_keeps_its_original_position() {
let mut data = craft_anything_testkit::firmware::ext_image(false);
data.resize(12 * BS, 0);
put(&mut data, 1024 + 4, 12);
data[FILE_INODE + 40..FILE_INODE + 100].fill(0);
put(&mut data, FILE_INODE + 4, (13 * BS) as u32);
put(&mut data, FILE_INODE + 88, 11);
put(&mut data, 11 * BS, 8);
let image = fsread::extfs::read(&data, &Limits::default());
let recovered = image.entries.iter().find(|e| e.path == "hello.txt").unwrap().data.as_ref().unwrap();
assert!(recovered[..12 * BS].iter().all(|b| *b == 0));
assert_eq!(&recovered[12 * BS..12 * BS + 22], b"Hello ext filesystem!\n");
}