use std::io::Write;
use tempfile::NamedTempFile;
use ewf::{EwfError, EwfReader};
const EVF_MAGIC: [u8; 8] = [0x45, 0x56, 0x46, 0x09, 0x0d, 0x0a, 0xff, 0x00];
fn file_header(segment: u16) -> [u8; 13] {
let mut h = [0u8; 13];
h[0..8].copy_from_slice(&EVF_MAGIC);
h[8] = 0x01;
h[9..11].copy_from_slice(&segment.to_le_bytes());
h[11..13].copy_from_slice(&0u16.to_le_bytes());
h
}
fn section_desc(section_type: &[u8], next: u64, section_size: u64) -> [u8; 76] {
let mut d = [0u8; 76];
let copy_len = section_type.len().min(16);
d[..copy_len].copy_from_slice(§ion_type[..copy_len]);
d[16..24].copy_from_slice(&next.to_le_bytes());
d[24..32].copy_from_slice(§ion_size.to_le_bytes());
d
}
fn volume_data(chunk_count: u32, sectors_per_chunk: u32, bytes_per_sector: u32) -> [u8; 94] {
let mut v = [0u8; 94];
v[4..8].copy_from_slice(&chunk_count.to_le_bytes());
v[8..12].copy_from_slice(§ors_per_chunk.to_le_bytes());
v[12..16].copy_from_slice(&bytes_per_sector.to_le_bytes());
v[16..24].copy_from_slice(&u64::from(chunk_count).to_le_bytes()); v
}
fn write_temp_e01(content: &[u8]) -> (NamedTempFile, std::path::PathBuf) {
let mut f = NamedTempFile::with_suffix(".E01").unwrap();
f.write_all(content).unwrap();
let path = f.path().to_path_buf();
(f, path)
}
const FHDR: usize = 13; const VOL_SECTION_SIZE: u64 = 76 + 94; const VOL_DATA_END: usize = FHDR + 76 + 94; const SECTORS_DESC_OFF: usize = VOL_DATA_END; const DONE_DESC_OFF: usize = SECTORS_DESC_OFF + 76;
#[test]
fn section_next_max_does_not_panic() {
let mut buf: Vec<u8> = Vec::new();
buf.extend_from_slice(&file_header(1));
buf.extend_from_slice(§ion_desc(b"done", u64::MAX, 76));
let (_f, path) = write_temp_e01(&buf);
let _ = EwfReader::open(&path);
}
#[test]
fn section_size_max_does_not_panic() {
let mut buf: Vec<u8> = Vec::new();
buf.extend_from_slice(&file_header(1));
let sectors_off = SECTORS_DESC_OFF as u64;
let done_off = DONE_DESC_OFF as u64;
buf.extend_from_slice(§ion_desc(b"volume", sectors_off, VOL_SECTION_SIZE));
buf.extend_from_slice(&volume_data(1, 64, 512)); buf.extend_from_slice(§ion_desc(b"sectors", done_off, u64::MAX)); buf.extend_from_slice(§ion_desc(b"done", 0, 76));
let (_f, path) = write_temp_e01(&buf);
let _ = EwfReader::open(&path);
}
#[test]
fn chunk_size_too_large_is_rejected() {
let sectors_per_chunk: u32 = 32769;
let bytes_per_sector: u32 = 4096;
let done_off = (FHDR + 76 + 94 + 76) as u64;
let mut buf: Vec<u8> = Vec::new();
buf.extend_from_slice(&file_header(1));
buf.extend_from_slice(§ion_desc(b"volume", done_off, VOL_SECTION_SIZE));
buf.extend_from_slice(&volume_data(1, sectors_per_chunk, bytes_per_sector));
buf.extend_from_slice(§ion_desc(b"done", 0, 76));
let (_f, path) = write_temp_e01(&buf);
let err = EwfReader::open(&path).expect_err("huge chunk_size must be rejected");
assert!(
matches!(err, EwfError::InvalidChunkSize(_)),
"expected InvalidChunkSize, got {err:?}"
);
}
#[test]
fn chunk_count_too_large_is_rejected() {
let huge_chunk_count: u32 = 4_000_001;
let done_off = (FHDR + 76 + 94 + 76) as u64;
let mut buf: Vec<u8> = Vec::new();
buf.extend_from_slice(&file_header(1));
buf.extend_from_slice(§ion_desc(b"volume", done_off, VOL_SECTION_SIZE));
buf.extend_from_slice(&volume_data(huge_chunk_count, 64, 512));
buf.extend_from_slice(§ion_desc(b"done", 0, 76));
let (_f, path) = write_temp_e01(&buf);
let err = EwfReader::open(&path).expect_err("huge chunk_count must be rejected");
assert!(
matches!(err, EwfError::Parse(_)),
"expected Parse error for huge chunk_count, got {err:?}"
);
}