smb_msg/info/
set.rs

1//! Set Info Request/Response messages and related types.
2
3use crate::FileId;
4
5use super::{NullByte, common::*};
6#[cfg(feature = "server")]
7use binrw::io::TakeSeekExt;
8use binrw::prelude::*;
9use smb_dtyp::{SecurityDescriptor, binrw_util::prelude::*};
10use smb_fscc::*;
11use smb_msg_derive::*;
12
13/// SMB2 SET_INFO request packet for setting information on a file or object store.
14///
15/// Used by clients to set file information, filesystem information, security information,
16/// or quota information on files or underlying object stores.
17/// The structure size is fixed at 33 bytes regardless of buffer length.
18///
19/// MS-SMB2 2.2.39
20#[smb_request(size = 33)]
21pub struct SetInfoRequest {
22    /// Type of information being set (File=0x01, FileSystem=0x02, Security=0x03, Quota=0x04)
23    #[bw(calc = data.info_type())]
24    #[br(temp)]
25    pub info_type: InfoType,
26    /// Information class indicating the specific type of information to set
27    pub info_class: SetInfoClass,
28    /// Length in bytes of the information to be set
29    #[bw(calc = PosMarker::default())]
30    #[br(temp)]
31    buffer_length: PosMarker<u32>,
32    /// Offset from SMB2 header to the information buffer
33    #[bw(calc = PosMarker::default())]
34    #[br(temp)]
35    _buffer_offset: PosMarker<u16>,
36    reserved: u16,
37    /// Additional information for security operations or 0 for other operations
38    pub additional_information: AdditionalInfo,
39    /// File identifier of the file or named pipe on which to perform the set operation
40    pub file_id: FileId,
41    /// Variable-length buffer containing the information being set
42    #[br(map_stream = |s| s.take_seek(buffer_length.value as u64))]
43    #[br(args(info_type))]
44    #[bw(write_with = PosMarker::write_aoff_size, args(&_buffer_offset, &buffer_length))]
45    pub data: SetInfoData,
46}
47
48query_info_data! {
49    SetInfoData
50    File: RawSetInfoData<SetFileInfo>,
51    FileSystem: RawSetInfoData<SetFileSystemInfo>,
52    Security: SecurityDescriptor,
53    Quota: ChainedItemList<FileQuotaInformation>,
54}
55
56/// Information class specifying the type of information to set.
57///
58/// Defines the specific information class for each info type category.
59/// For Security and Quota operations, the class is set to null byte (0).
60///
61/// MS-SMB2 2.2.39
62#[smb_message_binrw]
63pub enum SetInfoClass {
64    /// File information class (e.g., FileBasicInformation, FileRenameInformation)
65    File(SetFileInfoClass),
66    /// Filesystem information class (e.g., FileFsControlInformation)
67    FileSystem(SetFileSystemInfoClass),
68    /// Security information class (always 0)
69    Security(NullByte),
70    /// Quota information class (always 0)
71    Quota(NullByte),
72}
73
74impl From<SetFileInfoClass> for SetInfoClass {
75    fn from(val: SetFileInfoClass) -> Self {
76        SetInfoClass::File(val)
77    }
78}
79
80impl From<SetFileSystemInfoClass> for SetInfoClass {
81    fn from(val: SetFileSystemInfoClass) -> Self {
82        SetInfoClass::FileSystem(val)
83    }
84}
85
86impl SetInfoData {
87    /// Creates a SetInfoRequest from this data with the specified parameters.
88    ///
89    /// Validates that the info class and data combination are compatible before
90    /// creating the request structure.
91    ///
92    /// # Panics
93    ///
94    /// Panics if the info class and data type combination is invalid
95    /// (e.g., File class with FileSystem data).
96    pub fn to_req(
97        self,
98        info_class: SetInfoClass,
99        file_id: FileId,
100        additional_info: AdditionalInfo,
101    ) -> SetInfoRequest {
102        // Validate the info class and data combination
103        // to ensure they are compatible.
104        match (&info_class, &self) {
105            (SetInfoClass::File(_), SetInfoData::File(_)) => {}
106            (SetInfoClass::FileSystem(_), SetInfoData::FileSystem(_)) => {}
107            (SetInfoClass::Security(_), SetInfoData::Security(_)) => {}
108            (SetInfoClass::Quota(_), SetInfoData::Quota(_)) => {}
109            _ => panic!("Invalid info class and data combination"),
110        }
111
112        SetInfoRequest {
113            info_class,
114            additional_information: additional_info,
115            file_id,
116            data: self,
117        }
118    }
119}
120
121/// SMB2 SET_INFO response packet indicating successful completion.
122///
123/// Sent by the server to notify the client that the SET_INFO request
124/// has been successfully processed. Contains only the structure size field.
125///
126/// MS-SMB2 2.2.40
127#[smb_response(size = 2)]
128#[derive(Default)]
129pub struct SetInfoResponse {}
130
131#[cfg(test)]
132mod tests {
133    use super::*;
134    use crate::*;
135    use smb_dtyp::*;
136
137    test_request! {
138        SetInfo {
139            info_class: SetInfoClass::File(SetFileInfoClass::RenameInformation),
140            data: SetInfoData::from(RawSetInfoData::from(SetFileInfo::RenameInformation(FileRenameInformation {
141                replace_if_exists: false.into(),
142                root_directory: 0,
143                file_name: "hello\\myNewFile.txt".into(),
144            }))),
145            file_id: make_guid!("00000042-000e-0000-0500-10000e000000").into(),
146            additional_information: AdditionalInfo::new(),
147        } => "2100010a3a0000006000000000000000420000000e000000050010000e0000000000000000000000000000000000000026000000680065006c006c006f005c006d0079004e0065007700460069006c0065002e00740078007400"
148    }
149
150    test_binrw_response! {
151        struct SetInfoResponse {} => "0200"
152    }
153}