use crate::error::Result;
const MFT_ENTRY_SIZE: usize = 1024;
const MIRROR_ENTRY_COUNT: usize = 4;
#[derive(Debug, Clone)]
pub struct MirrorComparison {
pub matches: [bool; MIRROR_ENTRY_COUNT],
pub diff_offsets: Vec<Vec<usize>>,
pub is_consistent: bool,
}
pub fn compare_mft_mirror(mft_data: &[u8], mftmirr_data: &[u8]) -> Result<MirrorComparison> {
let mut matches = [true; MIRROR_ENTRY_COUNT];
let mut diff_offsets = vec![Vec::new(); MIRROR_ENTRY_COUNT];
let mut is_consistent = true;
for i in 0..MIRROR_ENTRY_COUNT {
let mft_start = i * MFT_ENTRY_SIZE;
let mft_end = mft_start + MFT_ENTRY_SIZE;
let mirr_start = i * MFT_ENTRY_SIZE;
let mirr_end = mirr_start + MFT_ENTRY_SIZE;
if mft_end > mft_data.len() || mirr_end > mftmirr_data.len() {
matches[i] = false;
is_consistent = false;
continue;
}
let mft_entry = &mft_data[mft_start..mft_end];
let mirr_entry = &mftmirr_data[mirr_start..mirr_end];
for (offset, (a, b)) in mft_entry.iter().zip(mirr_entry.iter()).enumerate() {
if a != b {
matches[i] = false;
is_consistent = false;
diff_offsets[i].push(offset);
}
}
}
Ok(MirrorComparison {
matches,
diff_offsets,
is_consistent,
})
}
#[cfg(test)]
#[allow(clippy::redundant_closure_for_method_calls)]
mod tests {
use super::*;
#[test]
fn test_identical_mirror() {
let data = vec![0xAAu8; MFT_ENTRY_SIZE * MIRROR_ENTRY_COUNT];
let result = compare_mft_mirror(&data, &data).unwrap();
assert!(result.is_consistent);
assert!(result.matches.iter().all(|&m| m));
}
#[test]
fn test_different_mirror() {
let mft = vec![0xAAu8; MFT_ENTRY_SIZE * MIRROR_ENTRY_COUNT];
let mut mirr = mft.clone();
mirr[0] = 0xBB;
let result = compare_mft_mirror(&mft, &mirr).unwrap();
assert!(!result.is_consistent);
assert!(!result.matches[0]);
assert!(result.matches[1]);
assert!(result.matches[2]);
assert!(result.matches[3]);
assert_eq!(result.diff_offsets[0], vec![0]);
}
#[test]
fn test_short_mirror_data() {
let mft = vec![0xAAu8; MFT_ENTRY_SIZE * MIRROR_ENTRY_COUNT];
let mirr = vec![0xAAu8; MFT_ENTRY_SIZE];
let result = compare_mft_mirror(&mft, &mirr).unwrap();
assert!(!result.is_consistent);
assert!(result.matches[0]); assert!(!result.matches[1]); }
#[test]
fn test_short_mft_data() {
let mft = vec![0xAAu8; MFT_ENTRY_SIZE]; let mirr = vec![0xAAu8; MFT_ENTRY_SIZE * MIRROR_ENTRY_COUNT];
let result = compare_mft_mirror(&mft, &mirr).unwrap();
assert!(!result.is_consistent);
assert!(result.matches[0]); assert!(!result.matches[1]); }
#[test]
fn test_multiple_differences() {
let mft = vec![0xAAu8; MFT_ENTRY_SIZE * MIRROR_ENTRY_COUNT];
let mut mirr = mft.clone();
mirr[0] = 0xBB;
mirr[10] = 0xCC;
mirr[2 * MFT_ENTRY_SIZE + 5] = 0xDD;
let result = compare_mft_mirror(&mft, &mirr).unwrap();
assert!(!result.is_consistent);
assert!(!result.matches[0]);
assert!(result.matches[1]);
assert!(!result.matches[2]);
assert!(result.matches[3]);
assert_eq!(result.diff_offsets[0].len(), 2);
assert_eq!(result.diff_offsets[2].len(), 1);
}
#[test]
fn test_empty_data() {
let result = compare_mft_mirror(&[], &[]).unwrap();
assert!(!result.is_consistent);
assert!(result.matches.iter().all(|&m| !m));
}
#[test]
fn test_exact_four_entries_identical() {
let data = vec![0xBBu8; MFT_ENTRY_SIZE * MIRROR_ENTRY_COUNT];
let result = compare_mft_mirror(&data, &data).unwrap();
assert!(result.is_consistent);
assert!(result.matches.iter().all(|&m| m));
assert!(result.diff_offsets.iter().all(|d| d.is_empty()));
}
#[test]
fn test_fewer_than_four_entries_in_mirror() {
let mft = vec![0xAAu8; MFT_ENTRY_SIZE * MIRROR_ENTRY_COUNT];
let mirr = vec![0xAAu8; MFT_ENTRY_SIZE * 2];
let result = compare_mft_mirror(&mft, &mirr).unwrap();
assert!(!result.is_consistent);
assert!(result.matches[0]);
assert!(result.matches[1]);
assert!(!result.matches[2]);
assert!(!result.matches[3]);
}
#[test]
fn test_fewer_than_four_entries_in_mft() {
let mft = vec![0xAAu8; MFT_ENTRY_SIZE * 3];
let mirr = vec![0xAAu8; MFT_ENTRY_SIZE * MIRROR_ENTRY_COUNT];
let result = compare_mft_mirror(&mft, &mirr).unwrap();
assert!(!result.is_consistent);
assert!(result.matches[0]);
assert!(result.matches[1]);
assert!(result.matches[2]);
assert!(!result.matches[3]); }
#[test]
fn test_exactly_one_byte_short_of_four_entries() {
let mft = vec![0xAAu8; MFT_ENTRY_SIZE * MIRROR_ENTRY_COUNT];
let mirr = vec![0xAAu8; MFT_ENTRY_SIZE * MIRROR_ENTRY_COUNT - 1];
let result = compare_mft_mirror(&mft, &mirr).unwrap();
assert!(!result.is_consistent);
assert!(result.matches[0]);
assert!(result.matches[1]);
assert!(result.matches[2]);
assert!(!result.matches[3]); }
#[test]
fn test_mirror_with_more_than_four_entries() {
let data = vec![0xCCu8; MFT_ENTRY_SIZE * 8]; let result = compare_mft_mirror(&data, &data).unwrap();
assert!(result.is_consistent);
assert!(result.matches.iter().all(|&m| m));
}
#[test]
fn test_each_entry_can_differ_independently() {
let mft = vec![0xAAu8; MFT_ENTRY_SIZE * MIRROR_ENTRY_COUNT];
for entry_idx in 0..MIRROR_ENTRY_COUNT {
let mut mirr = mft.clone();
mirr[entry_idx * MFT_ENTRY_SIZE + 100] = 0xBB;
let result = compare_mft_mirror(&mft, &mirr).unwrap();
assert!(!result.is_consistent);
for j in 0..MIRROR_ENTRY_COUNT {
if j == entry_idx {
assert!(!result.matches[j]);
assert_eq!(result.diff_offsets[j].len(), 1);
assert_eq!(result.diff_offsets[j][0], 100);
} else {
assert!(result.matches[j]);
}
}
}
}
#[test]
fn test_exact_boundary_data_length_multiple_of_1024() {
let data = vec![0xDDu8; MFT_ENTRY_SIZE * MIRROR_ENTRY_COUNT];
assert_eq!(data.len() % MFT_ENTRY_SIZE, 0);
let result = compare_mft_mirror(&data, &data).unwrap();
assert!(result.is_consistent);
}
#[test]
fn test_insufficient_data_marks_missing_entries_as_mismatched() {
let mft = vec![0xAAu8; MFT_ENTRY_SIZE * MIRROR_ENTRY_COUNT];
let mirr = vec![0xAAu8; MFT_ENTRY_SIZE * 2];
let result = compare_mft_mirror(&mft, &mirr).unwrap();
assert!(!result.is_consistent);
assert!(!result.matches[2]);
assert!(!result.matches[3]);
}
#[test]
fn test_diff_is_recorded_per_entry() {
let mft = vec![0xAAu8; MFT_ENTRY_SIZE * MIRROR_ENTRY_COUNT];
let mut mirr = mft.clone();
mirr[0] = 0xBB;
let result = compare_mft_mirror(&mft, &mirr).unwrap();
assert!(!result.is_consistent);
assert!(!result.matches[0]);
assert_eq!(result.diff_offsets[0].len(), 1);
}
#[test]
fn test_mixed_diff_and_insufficient_data() {
let mft = vec![0xAAu8; MFT_ENTRY_SIZE * MIRROR_ENTRY_COUNT];
let mut mirr = vec![0xAAu8; MFT_ENTRY_SIZE * 2]; mirr[0] = 0xBB;
let result = compare_mft_mirror(&mft, &mirr).unwrap();
assert!(!result.is_consistent);
assert!(!result.matches[0]);
assert!(!result.diff_offsets[0].is_empty());
assert!(result.matches[1]);
assert!(!result.matches[2]);
assert!(!result.matches[3]);
}
}