Skip to main content

idb/cli/
dump.rs

1use std::fs::File;
2use std::io::{Read, Seek, SeekFrom, Write};
3
4use crate::cli::wprintln;
5use crate::innodb::tablespace::Tablespace;
6use crate::util::hex::hex_dump;
7use crate::IdbError;
8
9pub struct DumpOptions {
10    pub file: String,
11    pub page: Option<u64>,
12    pub offset: Option<u64>,
13    pub length: Option<usize>,
14    pub raw: bool,
15    pub page_size: Option<u32>,
16}
17
18pub fn execute(opts: &DumpOptions, writer: &mut dyn Write) -> Result<(), IdbError> {
19    if let Some(abs_offset) = opts.offset {
20        // Absolute offset mode: dump raw bytes from file position
21        return dump_at_offset(&opts.file, abs_offset, opts.length.unwrap_or(256), opts.raw, writer);
22    }
23
24    // Page mode: dump a specific page (or page 0 by default)
25    let mut ts = match opts.page_size {
26        Some(ps) => Tablespace::open_with_page_size(&opts.file, ps)?,
27        None => Tablespace::open(&opts.file)?,
28    };
29
30    let page_size = ts.page_size();
31    let page_num = opts.page.unwrap_or(0);
32    let page_data = ts.read_page(page_num)?;
33
34    let length = opts.length.unwrap_or(page_size as usize);
35    let dump_len = length.min(page_data.len());
36    let base_offset = page_num * page_size as u64;
37
38    if opts.raw {
39        writer
40            .write_all(&page_data[..dump_len])
41            .map_err(|e| IdbError::Io(format!("Cannot write to stdout: {}", e)))?;
42    } else {
43        wprintln!(
44            writer,
45            "Hex dump of {} page {} ({} bytes):",
46            opts.file, page_num, dump_len
47        )?;
48        wprintln!(writer)?;
49        wprintln!(writer, "{}", hex_dump(&page_data[..dump_len], base_offset))?;
50    }
51
52    Ok(())
53}
54
55fn dump_at_offset(file: &str, offset: u64, length: usize, raw: bool, writer: &mut dyn Write) -> Result<(), IdbError> {
56    let mut f = File::open(file)
57        .map_err(|e| IdbError::Io(format!("Cannot open {}: {}", file, e)))?;
58
59    let file_size = f
60        .metadata()
61        .map_err(|e| IdbError::Io(format!("Cannot stat {}: {}", file, e)))?
62        .len();
63
64    if offset >= file_size {
65        return Err(IdbError::Argument(format!(
66            "Offset {} is beyond file size {}",
67            offset, file_size
68        )));
69    }
70
71    let available = (file_size - offset) as usize;
72    let read_len = length.min(available);
73
74    f.seek(SeekFrom::Start(offset))
75        .map_err(|e| IdbError::Io(format!("Cannot seek to offset {}: {}", offset, e)))?;
76
77    let mut buf = vec![0u8; read_len];
78    f.read_exact(&mut buf)
79        .map_err(|e| IdbError::Io(format!("Cannot read {} bytes at offset {}: {}", read_len, offset, e)))?;
80
81    if raw {
82        writer
83            .write_all(&buf)
84            .map_err(|e| IdbError::Io(format!("Cannot write to stdout: {}", e)))?;
85    } else {
86        wprintln!(
87            writer,
88            "Hex dump of {} at offset {} ({} bytes):",
89            file, offset, read_len
90        )?;
91        wprintln!(writer)?;
92        wprintln!(writer, "{}", hex_dump(&buf, offset))?;
93    }
94
95    Ok(())
96}