mod builder;
use builder::{
make_section_descriptor, EVF_SIGNATURE, FILE_HEADER_SIZE, SECTION_DESCRIPTOR_SIZE,
VOLUME_DATA_SIZE,
};
use ewf_forensic::{EwfIntegrity, EwfIntegrityAnomaly};
const TABLE_DATA_SIZE: usize = 24 + 4;
fn e01_with_table2(table2_body: &[u8]) -> Vec<u8> {
let mut buf: Vec<u8> = Vec::new();
let header_sz = (SECTION_DESCRIPTOR_SIZE + 1) as u64;
let volume_sz = (SECTION_DESCRIPTOR_SIZE + VOLUME_DATA_SIZE) as u64;
let table_sz = (SECTION_DESCRIPTOR_SIZE + TABLE_DATA_SIZE) as u64;
let sectors_data: Vec<u8> = vec![0u8; 512 * 64];
let sectors_sz = SECTION_DESCRIPTOR_SIZE as u64 + sectors_data.len() as u64;
let table2_sz = SECTION_DESCRIPTOR_SIZE as u64 + table2_body.len() as u64;
let hash_body = [0u8; 16];
let hash_sz = (SECTION_DESCRIPTOR_SIZE + hash_body.len()) as u64;
let done_sz = SECTION_DESCRIPTOR_SIZE as u64;
let base = FILE_HEADER_SIZE as u64;
let volume_off = base + header_sz;
let table_off = volume_off + volume_sz;
let sectors_off = table_off + table_sz;
let table2_off = sectors_off + sectors_sz;
let hash_off = table2_off + table2_sz;
let done_off = hash_off + hash_sz;
buf.extend_from_slice(&EVF_SIGNATURE);
buf.push(0x01);
buf.extend_from_slice(&1u16.to_le_bytes());
buf.extend_from_slice(&0u16.to_le_bytes());
buf.extend_from_slice(&make_section_descriptor("header", volume_off, header_sz));
buf.push(0u8);
buf.extend_from_slice(&make_section_descriptor("volume", table_off, volume_sz));
buf.extend(std::iter::repeat_n(0u8, VOLUME_DATA_SIZE));
let table_body: Vec<u8> = {
let mut v = vec![0u8; 24]; v.extend_from_slice(&(sectors_off as u32).to_le_bytes()); v
};
buf.extend_from_slice(&make_section_descriptor("table", sectors_off, table_sz));
buf.extend_from_slice(&table_body);
buf.extend_from_slice(&make_section_descriptor("sectors", table2_off, sectors_sz));
buf.extend_from_slice(§ors_data);
buf.extend_from_slice(&make_section_descriptor("table2", hash_off, table2_sz));
buf.extend_from_slice(table2_body);
buf.extend_from_slice(&make_section_descriptor("hash", done_off, hash_sz));
buf.extend_from_slice(&hash_body);
buf.extend_from_slice(&make_section_descriptor("done", done_off, done_sz));
buf
}
fn matching_table_body() -> Vec<u8> {
let mut v = vec![0u8; 24];
let sectors_off = (FILE_HEADER_SIZE as u64
+ (SECTION_DESCRIPTOR_SIZE + 1) as u64 + (SECTION_DESCRIPTOR_SIZE + VOLUME_DATA_SIZE) as u64 + (SECTION_DESCRIPTOR_SIZE + TABLE_DATA_SIZE) as u64) as u32;
v.extend_from_slice(§ors_off.to_le_bytes());
v
}
#[test]
fn table2_matching_no_anomaly() {
let body = matching_table_body();
let image = e01_with_table2(&body);
let findings = EwfIntegrity::new(&image).analyse();
assert!(
!findings
.iter()
.any(|a| matches!(a, EwfIntegrityAnomaly::Table2Mismatch { .. })),
"matching table2 must not produce Table2Mismatch; got: {findings:#?}"
);
}
#[test]
fn table2_mismatch_detected() {
let mut corrupted = matching_table_body();
if !corrupted.is_empty() {
corrupted[0] ^= 0xFF; }
let image = e01_with_table2(&corrupted);
let findings = EwfIntegrity::new(&image).analyse();
assert!(
findings
.iter()
.any(|a| matches!(a, EwfIntegrityAnomaly::Table2Mismatch { .. })),
"mismatching table2 must produce Table2Mismatch; got: {findings:#?}"
);
}
#[test]
fn clean_e01_no_table2_anomaly() {
let image = builder::E01Builder::new(512 * 64).build();
let findings = EwfIntegrity::new(&image).analyse();
assert!(
!findings
.iter()
.any(|a| matches!(a, EwfIntegrityAnomaly::Table2Mismatch { .. })),
"image without table2 must not produce Table2Mismatch; got: {findings:#?}"
);
}