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. This includes:
41///   - A method to get the info type of the enum variant - `info_type()`.
42///   - A method to get the name of the enum variant - `name()`.
43///   - implementations of `From<ContentType>` for each content type.
44///   - Methods to unwrap the content type, named `as_<variant_name_in_snake_case>()`.
45/// 2. A generic struct names `Raw<name>` to hold the raw data, with a method to convert it to the actual data.
46#[macro_export]
47macro_rules! query_info_data {
48    ($name:ident $($info_type:ident: $content:ty, )+) => {
49        paste::paste! {
50            #[allow(unused_imports)]
51            use binrw::prelude::*;
52            #[allow(unused_imports)]
53            use binrw::meta::WriteEndian;
54
55            #[doc = concat!("Enum to hold the different info types for ", stringify!($name),
56            ", that are used within SMB requests for querying or setting information.")]
57            #[binrw::binrw]
58            #[derive(Debug)]
59            #[brw(little)]
60            #[br(import(info_type: InfoType))]
61            pub enum $name {
62                $(
63                    #[br(pre_assert(info_type == InfoType::$info_type))]
64                    $info_type($content),
65                )+
66            }
67
68            impl $name {
69                // as_ methods to easily get the inner content.
70                $(
71                    #[doc = concat!("Get the inner content as [`", stringify!($content), "`].")]
72                    pub fn [<as_ $info_type:lower>](self) -> Result<$content, $crate::SmbMsgError> {
73                        match self {
74                            $name::$info_type(data) => Ok(data),
75                            _ => Err($crate::SmbMsgError::UnexpectedContent {
76                                expected: stringify!($info_type),
77                                actual: self.name(),
78                            }),
79                        }
80                    }
81                )+
82
83                /// Get the [InfoType] of this data.
84                pub fn info_type(&self) -> InfoType {
85                    match self {
86                        $(
87                            $name::$info_type(_) => InfoType::$info_type,
88                        )+
89                    }
90                }
91
92                /// Get the name of this data.
93                pub fn name(&self) -> &'static str {
94                    match self {
95                        $(
96                            $name::$info_type(_) => stringify!($info_type),
97                        )+
98                    }
99                }
100            }
101
102            /// Content to enum conversions:
103            $(
104                impl From<$content> for $name {
105                    fn from(value: $content) -> Self {
106                        $name::$info_type(value)
107                    }
108                }
109            )+
110
111            // All same for filesystem:
112            #[binrw::binrw]
113            #[derive(Debug)]
114            pub struct [<Raw $name>]<T>
115            where
116                T: Sized,
117            {
118                #[br(parse_with = binrw::helpers::until_eof)]
119                data: Vec<u8>,
120
121                phantom: std::marker::PhantomData<T>,
122            }
123
124
125            impl<T> [<Raw $name>]<T>
126            where
127                T: Sized,
128            {
129                pub fn data(&self) -> &[u8] {
130                    &self.data
131                }
132            }
133
134            impl<T> [<Raw $name>]<T>
135            where
136                T: Sized,
137                T: BinRead<Args<'static> = (T::Class,)> + FileInfoType,
138            {
139                // A parse method that accepts the class of T as an argument, reads the data and returns the T.
140                pub fn parse(&self, class: T::Class) -> Result<T, $crate::SmbMsgError> {
141                    let mut cursor = std::io::Cursor::new(&self.data);
142                    let value = T::read_le_args(&mut cursor, (class,))?;
143                    Ok(value)
144                }
145            }
146
147            impl<T> From<T> for [<Raw $name>]<T>
148            where
149                for<'a> T: BinWrite<Args<'a> = ()>,
150            {
151                fn from(value: T) -> Self {
152                    let mut cursor = std::io::Cursor::new(Vec::new());
153                    value.write_le(&mut cursor).unwrap();
154                    Self {
155                        data: cursor.into_inner(),
156                        phantom: std::marker::PhantomData,
157                    }
158                }
159            }
160        }
161    };
162}