Skip to main content

hexz_cli/cmd/data/
overlay.rs

1//! Inspect FUSE overlay files and identify modified blocks.
2//!
3//! This command analyzes overlay files created by the FUSE mount (in read-write
4//! mode) to display which blocks have been modified. The overlay tracks writes at
5//! 4 KiB granularity via a separate `.meta` sidecar file, allowing fast inspection
6//! without scanning the (potentially large) overlay data file.
7//!
8//! # Common Usage
9//!
10//! ```bash
11//! hexz overlay vm-state.overlay             # summary
12//! hexz overlay vm-state.overlay --blocks    # block count + size
13//! hexz overlay vm-state.overlay --files     # list individual block indices
14//! ```
15
16use anyhow::Result;
17use hexz_common::constants::{META_ENTRY_SIZE, OVERLAY_BLOCK_SIZE};
18use indicatif::HumanBytes;
19use std::fs::File;
20use std::io::{Read, Seek, SeekFrom};
21use std::path::PathBuf;
22
23/// Show statistics or block indices for a FUSE overlay file.
24pub fn run(overlay: PathBuf, blocks: bool, files: bool) -> Result<()> {
25    let meta_path = overlay.with_extension("meta");
26    if !meta_path.exists() {
27        println!("No metadata file found for overlay: {}", overlay.display());
28        return Ok(());
29    }
30
31    let mut f = File::open(&meta_path)?;
32    let count = f.metadata()?.len() / META_ENTRY_SIZE as u64;
33
34    if blocks {
35        println!("Modified Blocks: {}", count);
36        println!(
37            "Total Changed:   {}",
38            HumanBytes(count * OVERLAY_BLOCK_SIZE)
39        );
40    } else if files {
41        println!("Modified Block Indices:");
42        let mut buf = [0u8; META_ENTRY_SIZE];
43        f.seek(SeekFrom::Start(0))?;
44        for _ in 0..count {
45            if f.read_exact(&mut buf).is_ok() {
46                println!("  {}", u64::from_le_bytes(buf));
47            }
48        }
49    } else {
50        println!("Overlay:  {}", overlay.display());
51        println!(
52            "Modified: {}  ({})",
53            count,
54            HumanBytes(count * OVERLAY_BLOCK_SIZE)
55        );
56    }
57
58    Ok(())
59}