use fs_ext4::block_io::FileDevice;
use fs_ext4::Filesystem;
use std::fs;
use std::sync::atomic::{AtomicUsize, Ordering};
use std::sync::Arc;
fn image_path(name: &str) -> String {
format!("{}/test-disks/{}", env!("CARGO_MANIFEST_DIR"), name)
}
fn copy_to_tmp(name: &str, tag: &str) -> Option<String> {
static COUNTER: AtomicUsize = AtomicUsize::new(0);
let n = COUNTER.fetch_add(1, Ordering::Relaxed);
let src = image_path(name);
if !std::path::Path::new(&src).exists() {
return None;
}
let dst = format!("/tmp/fs_ext4_orph_{}_{tag}_{n}.img", std::process::id());
fs::copy(&src, &dst).ok()?;
Some(dst)
}
#[test]
fn clean_image_reports_empty_orphan_list() {
let Some(path) = copy_to_tmp("ext4-basic.img", "clean") else {
return;
};
let dev = FileDevice::open(&path).expect("ro");
let fs = Filesystem::mount(Arc::new(dev)).expect("mount");
let orphans = fs.orphan_list().expect("orphan_list");
assert!(
orphans.is_empty(),
"fresh fixture should have no orphans, got {orphans:?}"
);
assert_eq!(
fs.sb.last_orphan, 0,
"fresh fixture's s_last_orphan must be 0"
);
fs::remove_file(path).ok();
}
#[test]
fn orphan_list_does_not_panic_on_any_image() {
for img in &[
"ext4-basic.img",
"ext4-htree.img",
"ext4-largedir.img",
"ext4-deep-extents.img",
"ext4-inline.img",
"ext4-no-csum.img",
] {
let Some(path) = copy_to_tmp(img, "noprobe") else {
continue;
};
let result = std::panic::catch_unwind(|| {
let dev = FileDevice::open(&path).expect("ro");
let fs = Filesystem::mount(Arc::new(dev)).expect("mount");
let _ = fs.orphan_list();
});
assert!(result.is_ok(), "orphan_list panicked on {img}");
fs::remove_file(path).ok();
}
}