1use crate::{FileId, query_info_data};
4
5use super::{NullByte, QueryQuotaInfo, common::*};
6use binrw::io::TakeSeekExt;
7use binrw::prelude::*;
8use smb_dtyp::{SecurityDescriptor, binrw_util::prelude::*};
9use smb_fscc::*;
10
11#[binrw::binrw]
12#[derive(Debug)]
13pub struct SetInfoRequest {
14 #[bw(calc = 33)]
15 #[br(assert(_structure_size == 33))]
16 _structure_size: u16,
17 #[bw(calc = data.info_type())]
18 pub info_type: InfoType,
19 pub info_class: SetInfoClass,
20 #[bw(calc = PosMarker::default())]
21 buffer_length: PosMarker<u32>,
22 #[bw(calc = PosMarker::default())]
23 _buffer_offset: PosMarker<u16>,
24 #[bw(calc = 0)]
25 _reserved: u16,
26 pub additional_information: AdditionalInfo,
27 pub file_id: FileId,
28 #[br(map_stream = |s| s.take_seek(buffer_length.value as u64))]
29 #[br(args(info_type))]
30 #[bw(write_with = PosMarker::write_aoff_size, args(&_buffer_offset, &buffer_length))]
31 pub data: SetInfoData,
32}
33
34query_info_data! {
35 SetInfoData
36 File: RawSetInfoData<SetFileInfo>,
37 FileSystem: RawSetInfoData<SetFileSystemInfo>,
38 Security: SecurityDescriptor,
39 Quota: QueryQuotaInfo,
40}
41
42#[binrw::binrw]
45#[derive(Debug, PartialEq, Eq)]
46pub enum SetInfoClass {
47 File(SetFileInfoClass),
48 FileSystem(SetFileSystemInfoClass),
49 Security(NullByte),
50 Quota(NullByte),
51}
52
53impl From<SetFileInfoClass> for SetInfoClass {
54 fn from(val: SetFileInfoClass) -> Self {
55 SetInfoClass::File(val)
56 }
57}
58
59impl From<SetFileSystemInfoClass> for SetInfoClass {
60 fn from(val: SetFileSystemInfoClass) -> Self {
61 SetInfoClass::FileSystem(val)
62 }
63}
64
65impl SetInfoData {
66 pub fn to_req(
69 self,
70 info_class: SetInfoClass,
71 file_id: FileId,
72 additional_info: AdditionalInfo,
73 ) -> SetInfoRequest {
74 match (&info_class, &self) {
77 (SetInfoClass::File(_), SetInfoData::File(_)) => {}
78 (SetInfoClass::FileSystem(_), SetInfoData::FileSystem(_)) => {}
79 (SetInfoClass::Security(_), SetInfoData::Security(_)) => {}
80 (SetInfoClass::Quota(_), SetInfoData::Quota(_)) => {}
81 _ => panic!("Invalid info class and data combination"),
82 }
83
84 SetInfoRequest {
85 info_class,
86 additional_information: additional_info,
87 file_id,
88 data: self,
89 }
90 }
91}
92
93#[binrw::binrw]
94#[derive(Debug, PartialEq, Eq)]
95pub struct SetInfoResponse {
96 #[bw(calc = 2)]
97 #[br(assert(_structure_size == 2))]
98 _structure_size: u16,
99}
100
101#[cfg(test)]
102mod tests {
103 use super::*;
104 use crate::*;
105 use smb_dtyp::*;
106
107 #[test]
108 fn test_set_info_request_write() {
109 let set_info = SetFileInfo::RenameInformation(FileRenameInformation2 {
110 replace_if_exists: false.into(),
111 root_directory: 0,
112 file_name: "hello\\myNewFile.txt".into(),
113 });
114
115 let cls = set_info.class();
116 let req = SetInfoData::from(RawSetInfoData::<SetFileInfo>::from(set_info)).to_req(
117 cls.into(),
118 guid!("00000042-000e-0000-0500-10000e000000").into(),
119 AdditionalInfo::new(),
120 );
121 let req_data = encode_content(req.into());
122 assert_eq!(
123 req_data,
124 [
125 0x21, 0x0, 0x1, 0xa, 0x3a, 0x0, 0x0, 0x0, 0x60, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
126 0x42, 0x0, 0x0, 0x0, 0xe, 0x0, 0x0, 0x0, 0x5, 0x0, 0x10, 0x0, 0xe, 0x0, 0x0, 0x0,
127 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
128 0x26, 0x0, 0x0, 0x0, 0x68, 0x0, 0x65, 0x0, 0x6c, 0x0, 0x6c, 0x0, 0x6f, 0x0, 0x5c,
129 0x0, 0x6d, 0x0, 0x79, 0x0, 0x4e, 0x0, 0x65, 0x0, 0x77, 0x0, 0x46, 0x0, 0x69, 0x0,
130 0x6c, 0x0, 0x65, 0x0, 0x2e, 0x0, 0x74, 0x0, 0x78, 0x0, 0x74, 0x0
131 ]
132 );
133 }
134
135 #[test]
136 fn test_set_info_response_parse() {
137 let data = [0x2, 0x0, 0x0, 0x0];
138 let response = SetInfoResponse::read_le(&mut std::io::Cursor::new(&data)).unwrap();
139 assert_eq!(response, SetInfoResponse {});
140 }
141}