smb_msg/
error.rs

1//! Error response message
2
3use binrw::prelude::*;
4
5use smb_dtyp::binrw_util::prelude::*;
6
7#[binrw::binrw]
8#[derive(Debug, PartialEq, Eq)]
9pub struct ErrorResponse {
10    #[bw(calc = 9)]
11    #[br(assert(_structure_size == 9))]
12    _structure_size: u16,
13
14    #[bw(try_calc = error_data.len().try_into())]
15    _error_context_count: u8,
16
17    #[bw(calc = 0)]
18    _reserved: u8,
19
20    #[bw(calc = PosMarker::default())]
21    _byte_count: PosMarker<u32>,
22
23    #[br(count = _error_context_count)]
24    pub error_data: Vec<ErrorResponseContext>,
25}
26
27#[binrw::binrw]
28#[derive(Debug, PartialEq, Eq)]
29pub struct ErrorResponseContext {
30    // each context item should be aligned to 8 bytes,
31    // relative to the start of the error context.
32    // luckily, it appears after the header, which is, itself, aligned to 8 bytes.
33    #[brw(align_before = 8)]
34    #[bw(try_calc = error_data.len().try_into())]
35    _error_data_length: u32,
36    pub error_id: ErrorId,
37    #[br(count = _error_data_length)]
38    pub error_data: Vec<u8>,
39}
40
41impl ErrorResponse {
42    /// Locates a context by its ID,
43    /// returning a reference to it if found.
44    pub fn find_context(&self, id: ErrorId) -> Option<&ErrorResponseContext> {
45        self.error_data.iter().find(|c| c.error_id == id)
46    }
47}
48
49impl ErrorResponseContext {
50    /// Interprets the error data as a u32, if possible.
51    /// Returns an error if the data length is not 4 bytes.
52    pub fn as_u32(&self) -> crate::Result<u32> {
53        if self.error_data.len() == std::mem::size_of::<u32>() {
54            Ok(u32::from_le_bytes(
55                self.error_data.as_slice().try_into().unwrap(),
56            ))
57        } else {
58            Err(crate::SmbMsgError::InvalidData(
59                "Invalid error data length for u32".into(),
60            ))
61        }
62    }
63
64    /// Interprets the error data as a u64, if possible.
65    /// Returns an error if the data length is not 8 bytes.
66    pub fn as_u64(&self) -> crate::Result<u64> {
67        if self.error_data.len() == std::mem::size_of::<u64>() {
68            Ok(u64::from_le_bytes(
69                self.error_data.as_slice().try_into().unwrap(),
70            ))
71        } else {
72            Err(crate::SmbMsgError::InvalidData(
73                "Invalid error data length for u64".into(),
74            ))
75        }
76    }
77}
78
79#[binrw::binrw]
80#[derive(Debug, PartialEq, Eq)]
81#[brw(repr(u32))]
82pub enum ErrorId {
83    Default = 0,
84    ShareRedirect = 0x72645253,
85}
86
87#[cfg(test)]
88mod tests {
89    use crate::*;
90
91    test_response! {
92        error_simple, Command::Cancel => Error { error_data: vec![], } => "0900000000000000"
93    }
94}