Skip to main content

minidump_writer/
dir_section.rs

1use {
2    crate::{
3        mem_writer::{Buffer, MemoryArrayWriter, MemoryWriterError},
4        minidump_format::MDRawDirectory,
5        serializers::*,
6    },
7    std::io::{Error, Seek, Write},
8};
9
10pub type DumpBuf = Buffer;
11
12#[derive(Debug, thiserror::Error, serde::Serialize)]
13pub enum FileWriterError {
14    #[error("IO error")]
15    IOError(
16        #[from]
17        #[serde(serialize_with = "serialize_io_error")]
18        Error,
19    ),
20    #[error("Failed to write to memory")]
21    MemoryWriterError(#[from] MemoryWriterError),
22}
23
24/// Utility that wraps writing minidump directory entries to an I/O stream, generally
25/// a [`std::fs::File`].
26#[derive(Debug)]
27pub struct DirSection<'a, W>
28where
29    W: Write + Seek,
30{
31    curr_idx: usize,
32    section: MemoryArrayWriter<MDRawDirectory>,
33    /// If we have to append to some file, we have to know where we currently are
34    destination_start_offset: u64,
35    destination: &'a mut W,
36    last_position_written_to_file: u64,
37}
38
39impl<'a, W> DirSection<'a, W>
40where
41    W: Write + Seek,
42{
43    pub fn new(
44        buffer: &mut DumpBuf,
45        index_length: u32,
46        destination: &'a mut W,
47    ) -> std::result::Result<Self, FileWriterError> {
48        let dir_section =
49            MemoryArrayWriter::<MDRawDirectory>::alloc_array(buffer, index_length as usize)?;
50
51        Ok(Self {
52            curr_idx: 0,
53            section: dir_section,
54            destination_start_offset: destination.stream_position()?,
55            destination,
56            last_position_written_to_file: 0,
57        })
58    }
59
60    #[inline]
61    pub fn position(&self) -> u32 {
62        self.section.position
63    }
64
65    pub fn dump_dir_entry(
66        &mut self,
67        buffer: &mut DumpBuf,
68        dirent: MDRawDirectory,
69    ) -> std::result::Result<(), FileWriterError> {
70        self.section.set_value_at(buffer, dirent, self.curr_idx)?;
71
72        // Now write it to file
73
74        // First get all the positions
75        let curr_file_pos = self.destination.stream_position()?;
76        let idx_pos = self.section.location_of_index(self.curr_idx);
77        self.curr_idx += 1;
78
79        self.destination.seek(std::io::SeekFrom::Start(
80            self.destination_start_offset + idx_pos.rva as u64,
81        ))?;
82        let start = idx_pos.rva as usize;
83        let end = (idx_pos.rva + idx_pos.data_size) as usize;
84        self.destination.write_all(&buffer[start..end])?;
85
86        // Reset file-position
87        self.destination
88            .seek(std::io::SeekFrom::Start(curr_file_pos))?;
89
90        Ok(())
91    }
92
93    /// Writes 2 things to file:
94    /// 1. The given dirent into the dir section in the header (if any is given)
95    /// 2. Everything in the in-memory buffer that was added since the last call to this function
96    pub fn write_to_file(
97        &mut self,
98        buffer: &mut DumpBuf,
99        dirent: Option<MDRawDirectory>,
100    ) -> std::result::Result<(), FileWriterError> {
101        if let Some(dirent) = dirent {
102            self.dump_dir_entry(buffer, dirent)?;
103        }
104
105        let start_pos = self.last_position_written_to_file as usize;
106        self.destination.write_all(&buffer[start_pos..])?;
107        self.last_position_written_to_file = buffer.position();
108        Ok(())
109    }
110}