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 return dump_at_offset(&opts.file, abs_offset, opts.length.unwrap_or(256), opts.raw, writer);
22 }
23
24 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}