1#[cfg(feature = "client")]
3use std::io::SeekFrom;
4
5use binrw::prelude::*;
6use modular_bitfield::prelude::*;
7use smb_msg_derive::*;
8
9use super::FileId;
10#[cfg(feature = "client")]
11use super::header::Header;
12use smb_dtyp::binrw_util::prelude::*;
13
14#[smb_request(size = 24)]
20pub struct FlushRequest {
21 reserved: u16,
22 reserved: u32,
23 pub file_id: FileId,
25}
26
27#[smb_response(size = 4)]
33#[derive(Default)]
34pub struct FlushResponse {
35 reserved: u16,
36}
37
38#[smb_request(size = 49)]
44pub struct ReadRequest {
45 #[bw(calc = 0)]
46 #[br(temp)]
47 _padding: u8,
48 pub flags: ReadFlags,
50 pub length: u32,
52 pub offset: u64,
54 pub file_id: FileId,
56 pub minimum_count: u32,
58 #[bw(calc = CommunicationChannel::None)]
59 #[br(assert(channel == CommunicationChannel::None))]
60 #[br(temp)]
61 channel: CommunicationChannel,
62 #[bw(calc = 0)]
63 #[br(assert(_remaining_bytes == 0))]
64 #[br(temp)]
65 _remaining_bytes: u32,
66 #[bw(calc = 0)]
67 #[br(assert(_read_channel_info_offset == 0))]
68 #[br(temp)]
69 _read_channel_info_offset: u16,
70 #[bw(calc = 0)]
71 #[br(assert(_read_channel_info_length == 0))]
72 #[br(temp)]
73 _read_channel_info_length: u16,
74
75 #[bw(calc = 0)]
78 #[br(temp)]
79 _pad_blob_placeholder: u8,
80}
81
82#[smb_response(size = 17)]
88pub struct ReadResponse {
89 #[br(assert(_data_offset.value as usize >= Header::STRUCT_SIZE + Self::STRUCT_SIZE - 1))]
90 #[bw(calc = PosMarker::default())]
91 #[br(temp)]
92 _data_offset: PosMarker<u8>,
93 reserved: u8,
94 #[bw(try_calc = buffer.len().try_into())]
95 #[br(assert(_data_length > 0))]
96 #[br(temp)]
97 _data_length: u32,
98 #[bw(calc = 0)]
99 #[br(assert(_data_remaining == 0))]
100 #[br(temp)]
101 _data_remaining: u32,
102
103 reserved: u32,
104
105 #[br(seek_before = SeekFrom::Start(_data_offset.value as u64))]
107 #[br(count = _data_length)]
108 #[bw(assert(!buffer.is_empty()))]
109 #[bw(write_with = PosMarker::write_aoff, args(&_data_offset))]
110 pub buffer: Vec<u8>,
111}
112
113impl ReadResponse {
114 pub const STRUCT_SIZE: usize = 17;
115}
116
117#[smb_dtyp::mbitfield]
121pub struct ReadFlags {
122 pub read_unbuffered: bool,
124 pub read_compressed: bool,
126 #[skip]
127 __: B6,
128}
129
130#[smb_request_binrw]
134#[brw(repr(u32))]
135pub enum CommunicationChannel {
136 None = 0,
138 RdmaV1 = 1,
140 RdmaV1Invalidate = 2,
142}
143
144#[smb_request(size = 49)]
152#[allow(clippy::manual_non_exhaustive)]
153pub struct WriteRequest {
154 #[bw(calc = PosMarker::new(0))]
155 #[br(temp)]
156 _data_offset: PosMarker<u16>,
157
158 pub length: u32,
160 pub offset: u64,
162 pub file_id: FileId,
164 #[bw(calc = CommunicationChannel::None)]
165 #[br(temp)]
166 #[br(assert(channel == CommunicationChannel::None))]
167 pub channel: CommunicationChannel,
168 #[bw(calc = 0)]
169 #[br(temp)]
170 #[br(assert(_remaining_bytes == 0))]
171 _remaining_bytes: u32,
172 #[bw(calc = 0)]
173 #[br(temp)]
174 #[br(assert(_write_channel_info_offset == 0))]
175 _write_channel_info_offset: u16,
176 #[bw(calc = 0)]
177 #[br(temp)]
178 #[br(assert(_write_channel_info_length == 0))]
179 _write_channel_info_length: u16,
180 pub flags: WriteFlags,
182
183 #[bw(write_with = PosMarker::write_aoff, args(&_data_offset))]
184 _write_offset: (),
185}
186
187impl WriteRequest {
188 pub fn new(offset: u64, file_id: FileId, flags: WriteFlags, length: u32) -> Self {
189 Self {
190 length,
191 offset,
192 file_id,
193 flags,
194 _write_offset: (),
195 }
196 }
197}
198
199#[smb_response(size = 17)]
205pub struct WriteResponse {
206 reserved: u16,
207
208 pub count: u32,
210
211 reserved: u32,
213 reserved: u16,
215 reserved: u16,
217}
218
219#[smb_dtyp::mbitfield]
223pub struct WriteFlags {
224 pub write_unbuffered: bool,
226 pub write_through: bool,
228 #[skip]
229 __: B30,
230}
231
232#[cfg(test)]
233mod tests {
234 use crate::*;
235
236 use super::*;
237
238 test_binrw_request! {
239 struct FlushRequest {
240 file_id: [
241 0x14, 0x04, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x51, 0x00, 0x10, 0x00, 0x0c, 0x00,
242 0x00, 0x00,
243 ]
244 .into(),
245 } => "1800000000000000140400000c000000510010000c000000"
246 }
247
248 test_binrw_response! {
249 struct FlushResponse { } => "04 00 00 00"
250 }
251
252 test_request! {
253 Read {
254 flags: ReadFlags::new(),
255 length: 0x10203040,
256 offset: 0x5060708090a0b0c,
257 file_id: [
258 0x03, 0x03, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, 0xc5, 0x00, 0x00, 0x00, 0x0c, 0x00,
259 0x00, 0x00,
260 ]
261 .into(),
262 minimum_count: 1,
263 } => "31000000403020100c0b0a0908070605030300000c000000c50000000c0000000100000000000000000000000000000000"
264 }
265
266 test_response! {
267 Read {
268 buffer: b"bbbbbb".to_vec(),
269 } => "11005000060000000000000000000000626262626262"
270 }
271
272 test_request! {
273 Write {
274 offset: 0x1234abcd,
275 file_id: [
276 0x14, 0x04, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x51, 0x00, 0x10, 0x00, 0x0c, 0x00,
277 0x00, 0x00,
278 ]
279 .into(),
280 flags: WriteFlags::new(),
281 length: "MeFriend!THIS IS FINE!".as_bytes().to_vec().len() as u32,
282 _write_offset: (),
283 } => "3100700016000000cdab341200000000140400000c000000510010000c00000000000000000000000000000000000000"
284 }
285
286 test_binrw_response! {
287 struct WriteResponse { count: 0xbeefbaaf, } => "11000000afbaefbe0000000000000000"
288 }
289}