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, PartialEq, Eq)]
14pub struct FlushRequest {
15 #[bw(calc = 24)]
16 #[br(assert(_structure_size == 24))]
17 _structure_size: u16,
18 #[bw(calc = 0)]
19 _reserved1: u16,
20 #[bw(calc = 0)]
21 _reserved2: u32,
22 pub file_id: FileId,
23}
24
25#[binrw::binrw]
26#[derive(Debug, PartialEq, Eq)]
27pub struct FlushResponse {
28 #[bw(calc = 4)]
29 #[br(assert(_structure_size == 4))]
30 _structure_size: u16,
31 #[bw(calc = 0)]
32 _reserved: u16,
33}
34
35#[binrw::binrw]
36#[derive(Debug, PartialEq, Eq)]
37pub struct ReadRequest {
38 #[bw(calc = 49)]
39 #[br(assert(_structure_size == 49))]
40 _structure_size: u16,
41 #[bw(calc = 0)]
42 _padding: u8,
43 pub flags: ReadFlags,
44 pub length: u32,
45 pub offset: u64,
46 pub file_id: FileId,
47 pub minimum_count: u32,
48 #[bw(calc = CommunicationChannel::None)]
51 #[br(assert(channel == CommunicationChannel::None))]
52 channel: CommunicationChannel,
53 #[bw(calc = 0)]
54 #[br(assert(_remaining_bytes == 0))]
55 _remaining_bytes: u32,
56 #[bw(calc = 0)]
57 #[br(assert(_read_channel_info_offset == 0))]
58 _read_channel_info_offset: u16,
59 #[bw(calc = 0)]
60 #[br(assert(_read_channel_info_length == 0))]
61 _read_channel_info_length: u16,
62
63 #[bw(calc = 0)]
66 _pad_blob_placeholder: u8,
67}
68
69#[binrw::binrw]
70#[derive(Debug, PartialEq, Eq)]
71pub struct ReadResponse {
72 #[bw(calc = Self::STRUCT_SIZE as u16)]
73 #[br(assert(_structure_size == Self::STRUCT_SIZE as u16))]
74 _structure_size: u16,
75 #[br(assert(_data_offset.value as usize >= Header::STRUCT_SIZE + Self::STRUCT_SIZE - 1))]
79 #[bw(calc = PosMarker::default())]
80 _data_offset: PosMarker<u8>,
81 #[bw(calc = 0)]
82 _reserved: u8,
83 #[bw(try_calc = buffer.len().try_into())]
84 #[br(assert(_data_length > 0))] _data_length: u32,
86 #[bw(calc = 0)]
87 #[br(assert(_data_remaining == 0))]
88 _data_remaining: u32,
89
90 #[bw(calc = 0)]
92 _reserved2: u32,
93
94 #[br(seek_before = SeekFrom::Start(_data_offset.value as u64))]
95 #[br(count = _data_length)]
96 #[bw(assert(!buffer.is_empty()))] #[bw(write_with = PosMarker::write_aoff, args(&_data_offset))]
98 pub buffer: Vec<u8>,
99}
100
101impl ReadResponse {
102 const STRUCT_SIZE: usize = 17;
103}
104
105#[bitfield]
106#[derive(BinWrite, BinRead, Debug, Default, Clone, Copy, PartialEq, Eq)]
107#[bw(map = |&x| Self::into_bytes(x))]
108#[br(map = Self::from_bytes)]
109pub struct ReadFlags {
110 pub read_unbuffered: bool,
111 pub read_compressed: bool,
112 #[skip]
113 __: B6,
114}
115
116#[binrw::binrw]
117#[derive(Debug, PartialEq, Eq)]
118#[brw(repr(u32))]
119pub enum CommunicationChannel {
120 None = 0,
121 RdmaV1 = 1,
122 RdmaV1Invalidate = 2,
123}
124
125#[binrw::binrw]
132#[derive(Debug, PartialEq, Eq)]
133#[allow(clippy::manual_non_exhaustive)]
134pub struct WriteRequest {
135 #[bw(calc = 49)]
136 #[br(assert(_structure_size == 49))]
137 _structure_size: u16,
138 #[bw(calc = PosMarker::new(0))]
140 _data_offset: PosMarker<u16>,
141
142 pub length: u32,
144 pub offset: u64,
146 pub file_id: FileId,
147 #[bw(calc = CommunicationChannel::None)]
149 #[br(assert(channel == CommunicationChannel::None))]
150 pub channel: CommunicationChannel,
151 #[bw(calc = 0)]
152 #[br(assert(_remaining_bytes == 0))]
153 _remaining_bytes: u32,
154 #[bw(calc = 0)]
155 #[br(assert(_write_channel_info_offset == 0))]
156 _write_channel_info_offset: u16,
157 #[bw(calc = 0)]
158 #[br(assert(_write_channel_info_length == 0))]
159 _write_channel_info_length: u16,
160 pub flags: WriteFlags,
161
162 #[bw(write_with = PosMarker::write_aoff, args(&_data_offset))]
163 _write_offset: (),
164}
165
166impl WriteRequest {
167 pub fn new(offset: u64, file_id: FileId, flags: WriteFlags, length: u32) -> Self {
168 Self {
169 length,
170 offset,
171 file_id,
172 flags,
173 _write_offset: (),
174 }
175 }
176}
177
178#[binrw::binrw]
179#[derive(Debug, PartialEq, Eq)]
180pub struct WriteResponse {
181 #[bw(calc = 17)]
182 #[br(assert(_structure_size == 17))]
183 _structure_size: u16,
184 #[bw(calc = 0)]
185 _reserved: u16,
186 pub count: u32,
187 #[bw(calc = 0)] #[br(assert(_remaining_bytes == 0))]
189 _remaining_bytes: u32,
190 #[bw(calc = 0)] #[br(assert(_write_channel_info_offset == 0))]
192 _write_channel_info_offset: u16,
193 #[bw(calc = 0)] #[br(assert(_write_channel_info_length == 0))]
195 _write_channel_info_length: u16,
196}
197
198#[bitfield]
199#[derive(BinWrite, BinRead, Debug, Default, Clone, Copy, PartialEq, Eq)]
200#[bw(map = |&x| Self::into_bytes(x))]
201#[br(map = Self::from_bytes)]
202pub struct WriteFlags {
203 pub write_unbuffered: bool,
204 pub write_through: bool,
205 #[skip]
206 __: B30,
207}
208
209#[cfg(test)]
210mod tests {
211 use crate::*;
212
213 use super::*;
214 use smb_tests::*;
215
216 test_binrw! {
217 struct FlushRequest {
218 file_id: [
219 0x14, 0x04, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x51, 0x00, 0x10, 0x00, 0x0c, 0x00,
220 0x00, 0x00,
221 ]
222 .into(),
223 } => "1800000000000000140400000c000000510010000c000000"
224 }
225
226 test_binrw! {
227 struct FlushResponse { } => "04 00 00 00"
228 }
229
230 test_request! {
231 Read {
232 flags: ReadFlags::new(),
233 length: 0x10203040,
234 offset: 0x5060708090a0b0c,
235 file_id: [
236 0x03, 0x03, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, 0xc5, 0x00, 0x00, 0x00, 0x0c, 0x00,
237 0x00, 0x00,
238 ]
239 .into(),
240 minimum_count: 1,
241 } => "31000000403020100c0b0a0908070605030300000c000000c50000000c0000000100000000000000000000000000000000"
242 }
243
244 test_response! {
245 Read {
246 buffer: b"bbbbbb".to_vec(),
247 } => "11005000060000000000000000000000626262626262"
248 }
249
250 test_request! {
251 Write {
252 offset: 0x1234abcd,
253 file_id: [
254 0x14, 0x04, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x51, 0x00, 0x10, 0x00, 0x0c, 0x00,
255 0x00, 0x00,
256 ]
257 .into(),
258 flags: WriteFlags::new(),
259 length: "MeFriend!THIS IS FINE!".as_bytes().to_vec().len() as u32,
260 _write_offset: (),
261 } => "3100700016000000cdab341200000000140400000c000000510010000c00000000000000000000000000000000000000"
262 }
263
264 test_binrw! {
265 struct WriteResponse { count: 0xbeefbaaf, } => "11000000afbaefbe0000000000000000"
266 }
267}