1#[cfg(feature = "client")]
4use binrw::io::TakeSeekExt;
5use smb_msg_derive::*;
6use std::io::SeekFrom;
7
8use binrw::prelude::*;
9use modular_bitfield::prelude::*;
10
11use smb_dtyp::binrw_util::prelude::*;
12use smb_fscc::*;
13
14use super::FileId;
15
16#[smb_request(size = 33)]
24pub struct QueryDirectoryRequest {
25 pub file_information_class: QueryDirectoryInfoClass,
28 pub flags: QueryDirectoryFlags,
31 #[bw(assert(flags.index_specified() || *file_index == 0))]
36 pub file_index: u32,
37 pub file_id: FileId,
40 #[bw(calc = PosMarker::default())]
43 #[br(temp)]
44 pub file_name_offset: PosMarker<u16>,
45 #[bw(try_calc = file_name.size().try_into())]
48 file_name_length: u16, pub output_buffer_length: u32,
51 #[br(seek_before = SeekFrom::Start(file_name_offset.value as u64))]
54 #[br(args {size: SizedStringSize::bytes16(file_name_length)})]
56 #[bw(write_with = PosMarker::write_aoff, args(&file_name_offset))]
57 pub file_name: SizedWideString,
58}
59
60#[smb_dtyp::mbitfield]
67pub struct QueryDirectoryFlags {
68 pub restart_scans: bool,
70 pub return_single_entry: bool,
72 pub index_specified: bool,
74 pub reopen: bool,
76 #[skip]
77 __: B4,
78}
79
80#[smb_response(size = 9)]
88pub struct QueryDirectoryResponse {
89 #[bw(calc = PosMarker::default())]
91 #[br(temp)]
92 output_buffer_offset: PosMarker<u16>,
93 #[bw(try_calc = output_buffer.len().try_into())]
95 #[br(temp)]
96 output_buffer_length: u32,
97 #[br(seek_before = SeekFrom::Start(output_buffer_offset.value as u64))]
100 #[br(map_stream = |s| s.take_seek(output_buffer_length as u64), parse_with = binrw::helpers::until_eof)]
101 #[bw(write_with = PosMarker::write_aoff, args(&output_buffer_offset))]
102 pub output_buffer: Vec<u8>,
103}
104
105impl QueryDirectoryResponse {
106 pub fn read_output<T>(&self) -> BinResult<Vec<T>>
114 where
115 T: QueryDirectoryInfoValue + BinRead + BinWrite,
116 for<'a> <T as BinRead>::Args<'a>: Default,
117 for<'b> <T as BinWrite>::Args<'b>: Default,
118 {
119 let mut cursor = std::io::Cursor::new(&self.output_buffer);
120 Ok(
121 ChainedItemList::<T, { QueryDirectoryInfo::CHAINED_ALIGNMENT }>::read_le(&mut cursor)?
122 .into(),
123 )
124 }
125}
126
127#[cfg(test)]
128mod tests {
129 use time::macros::datetime;
130
131 use super::*;
132 #[test]
133 pub fn test_both_directory_information_attribute_parse() {
134 let data = [
135 0x70, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x39, 0x75, 0x91, 0xbf, 0xc8, 0x4b, 0xdb, 0x1,
136 0xe7, 0xb8, 0x48, 0xcd, 0xc8, 0x5d, 0xdb, 0x1, 0xe7, 0x1b, 0xed, 0xd4, 0x6a, 0x58,
137 0xdb, 0x1, 0xe7, 0x1b, 0xed, 0xd4, 0x6a, 0x58, 0xdb, 0x1, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
138 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x10, 0x0, 0x0, 0x0, 0x2, 0x0, 0x0,
139 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
140 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x7b,
141 0x80, 0x0, 0x0, 0x0, 0x0, 0x2, 0x0, 0x2e, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x70, 0x0,
142 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x3c, 0x8, 0x38, 0x96, 0xae, 0x4b, 0xdb, 0x1, 0x10, 0x6a,
143 0x87, 0x4b, 0x49, 0x5d, 0xdb, 0x1, 0x62, 0xc, 0xcd, 0xc1, 0xc8, 0x4b, 0xdb, 0x1, 0x62,
144 0xc, 0xcd, 0xc1, 0xc8, 0x4b, 0xdb, 0x1, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
145 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x10, 0x0, 0x0, 0x0, 0x4, 0x0, 0x0, 0x0, 0x0, 0x0,
146 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
147 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x2a, 0xe7, 0x1, 0x0,
148 0x0, 0x0, 0x4, 0x0, 0x2e, 0x0, 0x2e, 0x0, 0x0, 0x0, 0x0, 0x0, 0x78, 0x0, 0x0, 0x0, 0x0,
149 0x0, 0x0, 0x0, 0x5b, 0x6c, 0x44, 0xce, 0x6a, 0x58, 0xdb, 0x1, 0x5b, 0x6c, 0x44, 0xce,
150 0x6a, 0x58, 0xdb, 0x1, 0x5b, 0x6c, 0x44, 0xce, 0x6a, 0x58, 0xdb, 0x1, 0x5f, 0xd9, 0xd5,
151 0xce, 0x6a, 0x58, 0xdb, 0x1, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
152 0x0, 0x0, 0x0, 0x0, 0x0, 0x20, 0x0, 0x0, 0x0, 0xa, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
153 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
154 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xf0, 0xa4, 0x0, 0x0, 0x0, 0x0,
155 0xa, 0x0, 0x61, 0x0, 0x2e, 0x0, 0x74, 0x0, 0x78, 0x0, 0x74, 0x0, 0x0, 0x0, 0x0, 0x0,
156 0x0, 0x0, 0x78, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xd8, 0xce, 0xec, 0xcf, 0x6a, 0x58,
157 0xdb, 0x1, 0x7e, 0xc, 0x17, 0xd9, 0x6a, 0x58, 0xdb, 0x1, 0x7e, 0xc, 0x17, 0xd9, 0x6a,
158 0x58, 0xdb, 0x1, 0x7e, 0xc, 0x17, 0xd9, 0x6a, 0x58, 0xdb, 0x1, 0x6, 0x0, 0x0, 0x0, 0x0,
159 0x0, 0x0, 0x0, 0x8, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x20, 0x0, 0x0, 0x0, 0xa, 0x0,
160 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
161 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
162 0xb9, 0xf8, 0x0, 0x0, 0x0, 0x0, 0x4, 0x0, 0x62, 0x0, 0x2e, 0x0, 0x74, 0x0, 0x78, 0x0,
163 0x74, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x78, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x57,
164 0x8e, 0x2f, 0xd0, 0x6a, 0x58, 0xdb, 0x1, 0xe2, 0xa8, 0xc1, 0xdd, 0x6a, 0x58, 0xdb, 0x1,
165 0xe2, 0xa8, 0xc1, 0xdd, 0x6a, 0x58, 0xdb, 0x1, 0xe2, 0xa8, 0xc1, 0xdd, 0x6a, 0x58,
166 0xdb, 0x1, 0xe6, 0x1, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xe8, 0x1, 0x0, 0x0, 0x0, 0x0, 0x0,
167 0x0, 0x20, 0x0, 0x0, 0x0, 0xa, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
168 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
169 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xbb, 0xf8, 0x0, 0x0, 0x0, 0x0, 0x4, 0x0, 0x63, 0x0,
170 0x2e, 0x0, 0x74, 0x0, 0x78, 0x0, 0x74, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
171 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x32, 0x66, 0x47, 0xd0, 0x6a, 0x58, 0xdb, 0x1, 0x3, 0xc,
172 0x39, 0x53, 0x49, 0x5d, 0xdb, 0x1, 0x3, 0xc, 0x39, 0x53, 0x49, 0x5d, 0xdb, 0x1, 0x3,
173 0xc, 0x39, 0x53, 0x49, 0x5d, 0xdb, 0x1, 0x26, 0x3e, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
174 0x40, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x20, 0x0, 0x0, 0x0, 0xa, 0x0, 0x0, 0x0, 0x0, 0x0,
175 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
176 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xbc, 0xf8, 0x0, 0x0,
177 0x0, 0x0, 0x4, 0x0, 0x64, 0x0, 0x2e, 0x0, 0x74, 0x0, 0x78, 0x0, 0x74, 0x0,
178 ];
179
180 let res = QueryDirectoryResponse {
181 output_buffer: data.to_vec(),
182 }
183 .read_output::<FileIdBothDirectoryInformation>()
184 .unwrap();
185
186 assert_eq!(
187 vec![
188 FileIdBothDirectoryInformation {
189 file_index: 0,
190 creation_time: FileTime::from(datetime!(2024-12-11 12:32:31.7084985)),
191 last_access_time: FileTime::from(datetime!(2025-01-03 10:18:15.6499175)),
192 last_write_time: FileTime::from(datetime!(2024-12-27 14:22:59.9648231)),
193 change_time: FileTime::from(datetime!(2024-12-27 14:22:59.9648231)),
194 end_of_file: 0,
195 allocation_size: 0,
196 file_attributes: FileAttributes::new().with_directory(true),
197 ea_size: Some(0),
198 reparse_tag: None,
199 short_name_length: 0,
200 short_name: Default::default(),
201 file_id: 562949953454203,
202 file_name: ".".into(),
203 },
204 FileIdBothDirectoryInformation {
205 file_index: 0,
206 creation_time: FileTime::from(datetime!(2024-12-11 9:25:15.4208828)),
207 last_access_time: FileTime::from(datetime!(2025-01-02 19:05:31.8723088)),
208 last_write_time: FileTime::from(datetime!(2024-12-11 12:32:35.4544738)),
209 change_time: FileTime::from(datetime!(2024-12-11 12:32:35.4544738)),
210 end_of_file: 0,
211 allocation_size: 0,
212 file_attributes: FileAttributes::new().with_directory(true),
213 ea_size: Some(0),
214 reparse_tag: None,
215 short_name_length: 0,
216 short_name: Default::default(),
217 file_id: 1125899906967338,
218 file_name: "..".into(),
219 },
220 FileIdBothDirectoryInformation {
221 file_index: 0,
222 creation_time: FileTime::from(datetime!(2024-12-27 14:22:48.7929947)),
223 last_access_time: FileTime::from(datetime!(2024-12-27 14:22:48.7929947)),
224 last_write_time: FileTime::from(datetime!(2024-12-27 14:22:48.7929947)),
225 change_time: FileTime::from(datetime!(2024-12-27 14:22:49.7460575)),
226 end_of_file: 0,
227 allocation_size: 0,
228 file_attributes: FileAttributes::new().with_archive(true),
229 ea_size: Some(0),
230 reparse_tag: None,
231 short_name_length: 0,
232 short_name: Default::default(),
233 file_id: 2814749767148784,
234 file_name: "a.txt".into(),
235 },
236 FileIdBothDirectoryInformation {
237 file_index: 0,
238 creation_time: FileTime::from(datetime!(2024-12-27 14:22:51.5742424)),
239 last_access_time: FileTime::from(datetime!(2024-12-27 14:23:06.9505662)),
240 last_write_time: FileTime::from(datetime!(2024-12-27 14:23:06.9505662)),
241 change_time: FileTime::from(datetime!(2024-12-27 14:23:06.9505662)),
242 end_of_file: 6,
243 allocation_size: 8,
244 file_attributes: FileAttributes::new().with_archive(true),
245 ea_size: Some(0),
246 reparse_tag: None,
247 short_name_length: 0,
248 short_name: Default::default(),
249 file_id: 1125899906906297,
250 file_name: "b.txt".into(),
251 },
252 FileIdBothDirectoryInformation {
253 file_index: 0,
254 creation_time: FileTime::from(datetime!(2024-12-27 14:22:52.0116823)),
255 last_access_time: FileTime::from(datetime!(2024-12-27 14:23:14.7795682)),
256 last_write_time: FileTime::from(datetime!(2024-12-27 14:23:14.7795682)),
257 change_time: FileTime::from(datetime!(2024-12-27 14:23:14.7795682)),
258 end_of_file: 486,
259 allocation_size: 488,
260 file_attributes: FileAttributes::new().with_archive(true),
261 ea_size: Some(0),
262 reparse_tag: None,
263 short_name_length: 0,
264 short_name: Default::default(),
265 file_id: 1125899906906299,
266 file_name: "c.txt".into(),
267 },
268 FileIdBothDirectoryInformation {
269 file_index: 0,
270 creation_time: FileTime::from(datetime!(2024-12-27 14:22:52.167941),),
271 last_access_time: FileTime::from(datetime!(2025-01-02 19:05:44.7804931),),
272 last_write_time: FileTime::from(datetime!(2025-01-02 19:05:44.7804931),),
273 change_time: FileTime::from(datetime!(2025-01-02 19:05:44.7804931),),
274 end_of_file: 15910,
275 allocation_size: 16384,
276 file_attributes: FileAttributes::new().with_archive(true),
277 ea_size: Some(0),
278 reparse_tag: None,
279 short_name_length: 0,
280 short_name: Default::default(),
281 file_id: 1125899906906300,
282 file_name: "d.txt".into(),
283 },
284 ],
285 res
286 );
287 }
288}