smb_msg/info/
common.rs

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