use crate::{ mem_writer::{Buffer, MemoryArrayWriter, MemoryWriterError}, minidump_format::MDRawDirectory, }; use std::io::{Error, Seek, Write}; pub type DumpBuf = Buffer; #[derive(Debug, thiserror::Error)] pub enum FileWriterError { #[error("IO error")] IOError(#[from] Error), #[error("Failed to write to memory")] MemoryWriterError(#[from] MemoryWriterError), } /// Utility that wraps writing minidump directory entries to an I/O stream, generally /// a [`std::fs::File`]. #[derive(Debug)] pub struct DirSection<'a, W> where W: Write + Seek, { curr_idx: usize, section: MemoryArrayWriter, /// If we have to append to some file, we have to know where we currently are destination_start_offset: u64, destination: &'a mut W, last_position_written_to_file: u64, } impl<'a, W> DirSection<'a, W> where W: Write + Seek, { pub fn new( buffer: &mut DumpBuf, index_length: u32, destination: &'a mut W, ) -> std::result::Result { let dir_section = MemoryArrayWriter::::alloc_array(buffer, index_length as usize)?; Ok(Self { curr_idx: 0, section: dir_section, destination_start_offset: destination.stream_position()?, destination, last_position_written_to_file: 0, }) } #[inline] pub fn position(&self) -> u32 { self.section.position } pub fn dump_dir_entry( &mut self, buffer: &mut DumpBuf, dirent: MDRawDirectory, ) -> std::result::Result<(), FileWriterError> { self.section.set_value_at(buffer, dirent, self.curr_idx)?; // Now write it to file // First get all the positions let curr_file_pos = self.destination.stream_position()?; let idx_pos = self.section.location_of_index(self.curr_idx); self.curr_idx += 1; self.destination.seek(std::io::SeekFrom::Start( self.destination_start_offset + idx_pos.rva as u64, ))?; let start = idx_pos.rva as usize; let end = (idx_pos.rva + idx_pos.data_size) as usize; self.destination.write_all(&buffer[start..end])?; // Reset file-position self.destination .seek(std::io::SeekFrom::Start(curr_file_pos))?; Ok(()) } /// Writes 2 things to file: /// 1. The given dirent into the dir section in the header (if any is given) /// 2. Everything in the in-memory buffer that was added since the last call to this function pub fn write_to_file( &mut self, buffer: &mut DumpBuf, dirent: Option, ) -> std::result::Result<(), FileWriterError> { if let Some(dirent) = dirent { self.dump_dir_entry(buffer, dirent)?; } let start_pos = self.last_position_written_to_file as usize; self.destination.write_all(&buffer[start_pos..])?; self.last_position_written_to_file = buffer.position(); Ok(()) } }