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 {
11 pub file: String,
13 pub page: Option<u64>,
15 pub offset: Option<u64>,
17 pub length: Option<usize>,
19 pub raw: bool,
21 pub page_size: Option<u32>,
23}
24
25pub fn execute(opts: &DumpOptions, writer: &mut dyn Write) -> Result<(), IdbError> {
43 if let Some(abs_offset) = opts.offset {
44 return dump_at_offset(&opts.file, abs_offset, opts.length.unwrap_or(256), opts.raw, writer);
46 }
47
48 let mut ts = match opts.page_size {
50 Some(ps) => Tablespace::open_with_page_size(&opts.file, ps)?,
51 None => Tablespace::open(&opts.file)?,
52 };
53
54 let page_size = ts.page_size();
55 let page_num = opts.page.unwrap_or(0);
56 let page_data = ts.read_page(page_num)?;
57
58 let length = opts.length.unwrap_or(page_size as usize);
59 let dump_len = length.min(page_data.len());
60 let base_offset = page_num * page_size as u64;
61
62 if opts.raw {
63 writer
64 .write_all(&page_data[..dump_len])
65 .map_err(|e| IdbError::Io(format!("Cannot write to stdout: {}", e)))?;
66 } else {
67 wprintln!(
68 writer,
69 "Hex dump of {} page {} ({} bytes):",
70 opts.file, page_num, dump_len
71 )?;
72 wprintln!(writer)?;
73 wprintln!(writer, "{}", hex_dump(&page_data[..dump_len], base_offset))?;
74 }
75
76 Ok(())
77}
78
79fn dump_at_offset(file: &str, offset: u64, length: usize, raw: bool, writer: &mut dyn Write) -> Result<(), IdbError> {
80 let mut f = File::open(file)
81 .map_err(|e| IdbError::Io(format!("Cannot open {}: {}", file, e)))?;
82
83 let file_size = f
84 .metadata()
85 .map_err(|e| IdbError::Io(format!("Cannot stat {}: {}", file, e)))?
86 .len();
87
88 if offset >= file_size {
89 return Err(IdbError::Argument(format!(
90 "Offset {} is beyond file size {}",
91 offset, file_size
92 )));
93 }
94
95 let available = (file_size - offset) as usize;
96 let read_len = length.min(available);
97
98 f.seek(SeekFrom::Start(offset))
99 .map_err(|e| IdbError::Io(format!("Cannot seek to offset {}: {}", offset, e)))?;
100
101 let mut buf = vec![0u8; read_len];
102 f.read_exact(&mut buf)
103 .map_err(|e| IdbError::Io(format!("Cannot read {} bytes at offset {}: {}", read_len, offset, e)))?;
104
105 if raw {
106 writer
107 .write_all(&buf)
108 .map_err(|e| IdbError::Io(format!("Cannot write to stdout: {}", e)))?;
109 } else {
110 wprintln!(
111 writer,
112 "Hex dump of {} at offset {} ({} bytes):",
113 file, offset, read_len
114 )?;
115 wprintln!(writer)?;
116 wprintln!(writer, "{}", hex_dump(&buf, offset))?;
117 }
118
119 Ok(())
120}