1use std::io::SeekFrom;
4
5use binrw::prelude::*;
6use modular_bitfield::prelude::*;
7
8use super::FileId;
9use super::header::Header;
10use smb_dtyp::binrw_util::prelude::*;
11
12#[binrw::binrw]
13#[derive(Debug)]
14pub struct FlushRequest {
15 #[bw(calc = 24)]
16 #[br(assert(_structure_size == 24))]
17 _structure_size: u16,
18 #[bw(calc = 0)]
19 #[br(assert(_reserved1 == 0))]
20 _reserved1: u16,
21 #[bw(calc = 0)]
22 #[br(assert(_reserved2 == 0))]
23 _reserved2: u32,
24 pub file_id: FileId,
25}
26
27#[binrw::binrw]
28#[derive(Debug, PartialEq, Eq)]
29pub struct FlushResponse {
30 #[bw(calc = 4)]
31 #[br(assert(_structure_size == 4))]
32 _structure_size: u16,
33 #[bw(calc = 0)]
34 #[br(assert(_reserved == 0))]
35 _reserved: u16,
36}
37
38#[binrw::binrw]
39#[derive(Debug)]
40pub struct ReadRequest {
41 #[bw(calc = 49)]
42 #[br(assert(_structure_size == 49))]
43 _structure_size: u16,
44 #[bw(calc = 0)]
45 _padding: u8,
46 pub flags: ReadFlags,
47 pub length: u32,
48 pub offset: u64,
49 pub file_id: FileId,
50 pub minimum_count: u32,
51 #[bw(calc = CommunicationChannel::None)]
54 #[br(assert(channel == CommunicationChannel::None))]
55 channel: CommunicationChannel,
56 #[bw(calc = 0)]
57 #[br(assert(_remaining_bytes == 0))]
58 _remaining_bytes: u32,
59 #[bw(calc = 0)]
60 #[br(assert(_read_channel_info_offset == 0))]
61 _read_channel_info_offset: u16,
62 #[bw(calc = 0)]
63 #[br(assert(_read_channel_info_length == 0))]
64 _read_channel_info_length: u16,
65
66 #[bw(calc = 0)]
69 _pad_blob_placeholder: u8,
70}
71
72#[binrw::binrw]
73#[derive(Debug, PartialEq, Eq)]
74pub struct ReadResponse {
75 #[bw(calc = Self::STRUCT_SIZE as u16)]
76 #[br(assert(_structure_size == Self::STRUCT_SIZE as u16))]
77 _structure_size: u16,
78 #[br(assert(_data_offset.value as usize >= Header::STRUCT_SIZE + Self::STRUCT_SIZE - 1))]
82 #[bw(calc = PosMarker::default())]
83 _data_offset: PosMarker<u8>,
84 #[bw(calc = 0)]
85 #[br(assert(_reserved == 0))]
86 _reserved: u8,
87 #[bw(try_calc = buffer.len().try_into())]
88 #[br(assert(_data_length > 0))] _data_length: u32,
90 #[bw(calc = 0)]
91 #[br(assert(_data_remaining == 0))]
92 _data_remaining: u32,
93
94 #[bw(calc = 0)]
96 #[br(assert(_reserved2 == 0))]
97 _reserved2: u32,
98
99 #[br(seek_before = SeekFrom::Start(_data_offset.value as u64))]
100 #[br(count = _data_length)]
101 #[bw(assert(!buffer.is_empty()))] #[bw(write_with = PosMarker::write_aoff, args(&_data_offset))]
103 pub buffer: Vec<u8>,
104}
105
106impl ReadResponse {
107 const STRUCT_SIZE: usize = 17;
108}
109
110#[bitfield]
111#[derive(BinWrite, BinRead, Debug, Default, Clone, Copy)]
112#[bw(map = |&x| Self::into_bytes(x))]
113#[br(map = Self::from_bytes)]
114pub struct ReadFlags {
115 pub read_unbuffered: bool,
116 pub read_compressed: bool,
117 #[skip]
118 __: B6,
119}
120
121#[binrw::binrw]
122#[derive(Debug, PartialEq, Eq)]
123#[brw(repr(u32))]
124pub enum CommunicationChannel {
125 None = 0,
126 RdmaV1 = 1,
127 RdmaV1Invalidate = 2,
128}
129
130#[binrw::binrw]
137#[derive(Debug)]
138#[allow(clippy::manual_non_exhaustive)]
139pub struct WriteRequest {
140 #[bw(calc = 49)]
141 #[br(assert(_structure_size == 49))]
142 _structure_size: u16,
143 #[bw(calc = PosMarker::new(0))]
145 _data_offset: PosMarker<u16>,
146
147 pub length: u32,
149 pub offset: u64,
151 pub file_id: FileId,
152 #[bw(calc = CommunicationChannel::None)]
154 #[br(assert(channel == CommunicationChannel::None))]
155 pub channel: CommunicationChannel,
156 #[bw(calc = 0)]
157 #[br(assert(_remaining_bytes == 0))]
158 _remaining_bytes: u32,
159 #[bw(calc = 0)]
160 #[br(assert(_write_channel_info_offset == 0))]
161 _write_channel_info_offset: u16,
162 #[bw(calc = 0)]
163 #[br(assert(_write_channel_info_length == 0))]
164 _write_channel_info_length: u16,
165 pub flags: WriteFlags,
166
167 #[bw(write_with = PosMarker::write_aoff, args(&_data_offset))]
168 _write_offset: (),
169}
170
171impl WriteRequest {
172 pub fn new(offset: u64, file_id: FileId, flags: WriteFlags, length: u32) -> Self {
173 Self {
174 length,
175 offset,
176 file_id,
177 flags,
178 _write_offset: (),
179 }
180 }
181}
182
183#[binrw::binrw]
184#[derive(Debug, PartialEq, Eq)]
185pub struct WriteResponse {
186 #[bw(calc = 17)]
187 #[br(assert(_structure_size == 17))]
188 _structure_size: u16,
189 #[bw(calc = 0)]
190 #[br(assert(_reserved == 0))]
191 _reserved: u16,
192 pub count: u32,
193 #[bw(calc = 0)] #[br(assert(_remaining_bytes == 0))]
195 _remaining_bytes: u32,
196 #[bw(calc = 0)] #[br(assert(_write_channel_info_offset == 0))]
198 _write_channel_info_offset: u16,
199 #[bw(calc = 0)] #[br(assert(_write_channel_info_length == 0))]
201 _write_channel_info_length: u16,
202}
203
204#[bitfield]
205#[derive(BinWrite, BinRead, Debug, Default, Clone, Copy)]
206#[bw(map = |&x| Self::into_bytes(x))]
207#[br(map = Self::from_bytes)]
208pub struct WriteFlags {
209 pub write_unbuffered: bool,
210 pub write_through: bool,
211 #[skip]
212 __: B30,
213}
214
215#[cfg(test)]
216mod tests {
217 use std::io::Cursor;
218
219 use crate::*;
220
221 use super::*;
222
223 #[test]
224 pub fn test_flush_req_write() {
225 let mut cursor = Cursor::new(Vec::new());
226 FlushRequest {
227 file_id: [
228 0x14, 0x04, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x51, 0x00, 0x10, 0x00, 0x0c, 0x00,
229 0x00, 0x00,
230 ]
231 .into(),
232 }
233 .write_le(&mut cursor)
234 .unwrap();
235 assert_eq!(
236 cursor.into_inner(),
237 [
238 0x18, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x14, 0x4, 0x0, 0x0, 0xc, 0x0, 0x0, 0x0,
239 0x51, 0x0, 0x10, 0x0, 0xc, 0x0, 0x0, 0x0
240 ]
241 )
242 }
243
244 #[test]
245 pub fn test_flush_res_parse() {
246 let data = [0x4u8, 0, 0, 0, 0, 0, 0, 0];
247 let mut cursor = Cursor::new(data);
248 let resp = FlushResponse::read_le(&mut cursor).unwrap();
249 assert_eq!(resp, FlushResponse {});
250 }
251
252 #[test]
253 pub fn test_read_req_write() {
254 let req = ReadRequest {
255 flags: ReadFlags::new(),
256 length: 0x10203040,
257 offset: 0x5060708090a0b0c,
258 file_id: [
259 0x03, 0x03, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, 0xc5, 0x00, 0x00, 0x00, 0x0c, 0x00,
260 0x00, 0x00,
261 ]
262 .into(),
263 minimum_count: 1,
264 };
265 let data = encode_content(req.into());
266 assert_eq![
267 data,
268 [
269 0x31, 0x0, 0x0, 0x0, 0x40, 0x30, 0x20, 0x10, 0x0c, 0x0b, 0x0a, 0x09, 0x08, 0x07,
270 0x06, 0x05, 0x3, 0x3, 0x0, 0x0, 0xc, 0x0, 0x0, 0x0, 0xc5, 0x0, 0x0, 0x0, 0xc, 0x0,
271 0x0, 0x0, 0x1, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
272 0x0, 0x0, 0x0
274 ]
275 ]
276 }
277
278 #[test]
279 pub fn test_read_resp_parse() {
280 let data = [
281 0xfeu8, 0x53, 0x4d, 0x42, 0x40, 0x0, 0x1, 0x0, 0x0, 0x0, 0x0, 0x0, 0x8, 0x0, 0x1, 0x0,
282 0x1, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xd4, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xff,
283 0xfe, 0x0, 0x0, 0x5, 0x0, 0x0, 0x0, 0x31, 0x0, 0x0, 0x20, 0x0, 0x30, 0x0, 0x0, 0x0,
284 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x11, 0x0,
285 0x50, 0x0, 0x6, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x62, 0x62,
286 0x62, 0x62, 0x62, 0x62,
287 ];
288
289 let resp = decode_content(&data).content.to_read().unwrap();
290 assert_eq!(
291 resp,
292 ReadResponse {
293 buffer: b"bbbbbb".to_vec(),
294 }
295 );
296 }
297
298 #[test]
299 pub fn test_write_req_write() {
300 let data = encode_content(
301 WriteRequest::new(
302 0x1234abcd,
303 [
304 0x14, 0x04, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x51, 0x00, 0x10, 0x00, 0x0c,
305 0x00, 0x00, 0x00,
306 ]
307 .into(),
308 WriteFlags::new(),
309 "MeFriend!THIS IS FINE!".as_bytes().to_vec().len() as u32,
310 )
311 .into(),
312 );
313 assert_eq!(
314 data,
315 [
316 0x31, 0x0, 0x70, 0x0, 0x16, 0x0, 0x0, 0x0, 0xcd, 0xab, 0x34, 0x12, 0x0, 0x0, 0x0,
317 0x0, 0x14, 0x4, 0x0, 0x0, 0xc, 0x0, 0x0, 0x0, 0x51, 0x0, 0x10, 0x0, 0xc, 0x0, 0x0,
318 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
319 0x0
320 ]
321 );
322 }
323
324 #[test]
325 pub fn test_write_resp_parse() {
326 let data = [
327 0x11u8, 0x0, 0x0, 0x0, 0xaf, 0xba, 0xef, 0xbe, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
328 ];
329 let mut cursor = Cursor::new(data);
330 let resp = WriteResponse::read_le(&mut cursor).unwrap();
331 assert_eq!(resp, WriteResponse { count: 0xbeefbaaf });
332 }
333}