smb_msg/info/
common.rs

1//! Common data structures for query/set info messages.
2
3use binrw::prelude::*;
4use modular_bitfield::prelude::*;
5
6#[binrw::binrw]
7#[derive(Debug, PartialEq, Eq, Copy, Clone)]
8#[brw(repr(u8))]
9pub enum InfoType {
10    File = 0x1,
11    FileSystem = 0x2,
12    Security = 0x3,
13    Quota = 0x4,
14}
15
16#[bitfield]
17#[derive(BinWrite, BinRead, Debug, Default, Clone, Copy, PartialEq, Eq)]
18#[bw(map = |&x| Self::into_bytes(x))]
19#[br(map = Self::from_bytes)]
20pub struct AdditionalInfo {
21    pub owner_security_information: bool,
22    pub group_security_information: bool,
23    pub dacl_security_information: bool,
24    pub sacl_security_information: bool,
25
26    pub label_security_information: bool,
27    pub attribute_security_information: bool,
28    pub scope_security_information: bool,
29
30    #[skip]
31    __: B9,
32    pub backup_security_information: bool,
33    #[skip]
34    __: B15,
35}
36
37/// Internal helper macro to easily generate fields & methods for [QueryInfoData](super::query::QueryInfoData).
38///
39/// Builds:
40/// 1. The enum with the specified name, with variants for each info type specified.
41/// 2. A generic struct names `Raw<name>` to hold the raw data, with a method to convert it to the actual data.
42#[macro_export]
43macro_rules! query_info_data {
44    ($name:ident $($info_type:ident: $content:ty, )+) => {
45        paste::paste! {
46            #[allow(unused_imports)]
47            use binrw::prelude::*;
48            #[allow(unused_imports)]
49            use binrw::meta::WriteEndian;
50            /// Represents information passed in get/set info requests.
51            /// This is the information matching [InfoType], and should be used
52            /// in the get info response and in the set info request.
53            #[binrw::binrw]
54            #[derive(Debug)]
55            #[brw(little)]
56            #[br(import(info_type: InfoType))]
57            pub enum $name {
58                $(
59                    #[br(pre_assert(info_type == InfoType::$info_type))]
60                    $info_type($content),
61                )+
62            }
63
64            impl $name {
65                // unwrap_ methods to easily get the inner content.
66                $(
67                    pub fn [<unwrap_ $info_type:lower>](self) -> $content {
68                        match self {
69                            $name::$info_type(data) => data,
70                            _ => panic!("Expected $info_type, got {:?}", self),
71                        }
72                    }
73                    pub fn [<as_ $info_type:lower>](self) -> Result<$content, $crate::SmbMsgError> {
74                        match self {
75                            $name::$info_type(data) => Ok(data),
76                            _ => Err($crate::SmbMsgError::UnexpectedContent {
77                                expected: stringify!($info_type),
78                                actual: self.name(),
79                            }),
80                        }
81                    }
82                )+
83
84                /// Get the [InfoType] of this data.
85                pub fn info_type(&self) -> InfoType {
86                    match self {
87                        $(
88                            $name::$info_type(_) => InfoType::$info_type,
89                        )+
90                    }
91                }
92
93                /// Get the name of this data.
94                pub fn name(&self) -> &'static str {
95                    match self {
96                        $(
97                            $name::$info_type(_) => stringify!($info_type),
98                        )+
99                    }
100                }
101            }
102
103            /// Content to enum conversions:
104            $(
105                impl From<$content> for $name {
106                    fn from(value: $content) -> Self {
107                        $name::$info_type(value)
108                    }
109                }
110            )+
111
112            // All same for filesystem:
113            #[binrw::binrw]
114            #[derive(Debug)]
115            pub struct [<Raw $name>]<T>
116            where
117                T: Sized,
118            {
119                #[br(parse_with = binrw::helpers::until_eof)]
120                data: Vec<u8>,
121
122                phantom: std::marker::PhantomData<T>,
123            }
124
125
126            impl<T> [<Raw $name>]<T>
127            where
128                T: Sized,
129            {
130                pub fn data(&self) -> &[u8] {
131                    &self.data
132                }
133            }
134
135            impl<T> [<Raw $name>]<T>
136            where
137                T: Sized,
138                T: BinRead<Args<'static> = (T::Class,)> + FileInfoType,
139            {
140                // A parse method that accepts the class of T as an argument, reads the data and returns the T.
141                pub fn parse(&self, class: T::Class) -> Result<T, $crate::SmbMsgError> {
142                    let mut cursor = std::io::Cursor::new(&self.data);
143                    let value = T::read_le_args(&mut cursor, (class,))?;
144                    Ok(value)
145                }
146            }
147
148            impl<T> From<T> for [<Raw $name>]<T>
149            where
150                for<'a> T: BinWrite<Args<'a> = ()>,
151            {
152                fn from(value: T) -> Self {
153                    let mut cursor = std::io::Cursor::new(Vec::new());
154                    value.write_le(&mut cursor).unwrap();
155                    Self {
156                        data: cursor.into_inner(),
157                        phantom: std::marker::PhantomData,
158                    }
159                }
160            }
161        }
162    };
163}