1use binrw::io::TakeSeekExt;
4use std::io::SeekFrom;
5
6use binrw::prelude::*;
7use modular_bitfield::prelude::*;
8
9use smb_dtyp::binrw_util::prelude::*;
10use smb_fscc::*;
11
12use super::FileId;
13
14#[binrw::binrw]
15#[derive(Debug)]
16pub struct QueryDirectoryRequest {
17 #[bw(calc = 33)]
18 #[br(assert(_structure_size == 33))]
19 _structure_size: u16,
20 pub file_information_class: QueryDirectoryInfoClass,
21 pub flags: QueryDirectoryFlags,
22 #[bw(assert(flags.index_specified() || *file_index == 0))]
25 pub file_index: u32,
26 pub file_id: FileId,
27 #[bw(calc = PosMarker::default())]
28 pub file_name_offset: PosMarker<u16>,
29 #[bw(try_calc = file_name.size().try_into())]
30 file_name_length: u16, pub output_buffer_length: u32,
32 #[br(seek_before = SeekFrom::Start(file_name_offset.value as u64))]
33 #[br(args(file_name_length as u64))]
35 #[bw(write_with = PosMarker::write_aoff, args(&file_name_offset))]
36 pub file_name: SizedWideString,
37}
38
39#[bitfield]
40#[derive(BinWrite, BinRead, Debug, Default, Clone, Copy, PartialEq, Eq)]
41#[bw(map = |&x| Self::into_bytes(x))]
42#[br(map = Self::from_bytes)]
43pub struct QueryDirectoryFlags {
44 pub restart_scans: bool,
45 pub return_single_entry: bool,
46 pub index_specified: bool,
47 pub reopen: bool,
48 #[skip]
49 __: B4,
50}
51
52#[binrw::binrw]
53#[derive(Debug)]
54pub struct QueryDirectoryResponse {
55 #[bw(calc = 9)]
56 #[br(assert(_structure_size == 9))]
57 _structure_size: u16,
58 #[bw(calc = PosMarker::default())]
59 output_buffer_offset: PosMarker<u16>,
60 #[bw(try_calc = output_buffer.len().try_into())]
61 output_buffer_length: u32,
62 #[br(seek_before = SeekFrom::Start(output_buffer_offset.value as u64))]
63 #[br(map_stream = |s| s.take_seek(output_buffer_length as u64), parse_with = binrw::helpers::until_eof)]
64 #[bw(write_with = PosMarker::write_aoff, args(&output_buffer_offset))]
65 pub output_buffer: Vec<u8>,
66}
67
68impl QueryDirectoryResponse {
69 pub fn read_output<T>(&self) -> BinResult<Vec<T>>
70 where
71 T: QueryDirectoryInfoValue + BinRead + BinWrite,
72 for<'a> <T as BinRead>::Args<'a>: Default,
73 for<'b> <T as BinWrite>::Args<'b>: Default,
74 {
75 let mut cursor = std::io::Cursor::new(&self.output_buffer);
76 Ok(ChainedItemList::<T>::read_le(&mut cursor)?.into())
77 }
78}
79
80#[cfg(test)]
81mod tests {
82 use time::macros::datetime;
83
84 use super::*;
85 #[test]
86 pub fn test_both_directory_information_attribute_parse() {
87 let data = [
88 0x70, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x39, 0x75, 0x91, 0xbf, 0xc8, 0x4b, 0xdb, 0x1,
89 0xe7, 0xb8, 0x48, 0xcd, 0xc8, 0x5d, 0xdb, 0x1, 0xe7, 0x1b, 0xed, 0xd4, 0x6a, 0x58,
90 0xdb, 0x1, 0xe7, 0x1b, 0xed, 0xd4, 0x6a, 0x58, 0xdb, 0x1, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
91 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x10, 0x0, 0x0, 0x0, 0x2, 0x0, 0x0,
92 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
93 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x7b,
94 0x80, 0x0, 0x0, 0x0, 0x0, 0x2, 0x0, 0x2e, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x70, 0x0,
95 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x3c, 0x8, 0x38, 0x96, 0xae, 0x4b, 0xdb, 0x1, 0x10, 0x6a,
96 0x87, 0x4b, 0x49, 0x5d, 0xdb, 0x1, 0x62, 0xc, 0xcd, 0xc1, 0xc8, 0x4b, 0xdb, 0x1, 0x62,
97 0xc, 0xcd, 0xc1, 0xc8, 0x4b, 0xdb, 0x1, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
98 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x10, 0x0, 0x0, 0x0, 0x4, 0x0, 0x0, 0x0, 0x0, 0x0,
99 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
100 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x2a, 0xe7, 0x1, 0x0,
101 0x0, 0x0, 0x4, 0x0, 0x2e, 0x0, 0x2e, 0x0, 0x0, 0x0, 0x0, 0x0, 0x78, 0x0, 0x0, 0x0, 0x0,
102 0x0, 0x0, 0x0, 0x5b, 0x6c, 0x44, 0xce, 0x6a, 0x58, 0xdb, 0x1, 0x5b, 0x6c, 0x44, 0xce,
103 0x6a, 0x58, 0xdb, 0x1, 0x5b, 0x6c, 0x44, 0xce, 0x6a, 0x58, 0xdb, 0x1, 0x5f, 0xd9, 0xd5,
104 0xce, 0x6a, 0x58, 0xdb, 0x1, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
105 0x0, 0x0, 0x0, 0x0, 0x0, 0x20, 0x0, 0x0, 0x0, 0xa, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
106 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
107 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xf0, 0xa4, 0x0, 0x0, 0x0, 0x0,
108 0xa, 0x0, 0x61, 0x0, 0x2e, 0x0, 0x74, 0x0, 0x78, 0x0, 0x74, 0x0, 0x0, 0x0, 0x0, 0x0,
109 0x0, 0x0, 0x78, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xd8, 0xce, 0xec, 0xcf, 0x6a, 0x58,
110 0xdb, 0x1, 0x7e, 0xc, 0x17, 0xd9, 0x6a, 0x58, 0xdb, 0x1, 0x7e, 0xc, 0x17, 0xd9, 0x6a,
111 0x58, 0xdb, 0x1, 0x7e, 0xc, 0x17, 0xd9, 0x6a, 0x58, 0xdb, 0x1, 0x6, 0x0, 0x0, 0x0, 0x0,
112 0x0, 0x0, 0x0, 0x8, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x20, 0x0, 0x0, 0x0, 0xa, 0x0,
113 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
114 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
115 0xb9, 0xf8, 0x0, 0x0, 0x0, 0x0, 0x4, 0x0, 0x62, 0x0, 0x2e, 0x0, 0x74, 0x0, 0x78, 0x0,
116 0x74, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x78, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x57,
117 0x8e, 0x2f, 0xd0, 0x6a, 0x58, 0xdb, 0x1, 0xe2, 0xa8, 0xc1, 0xdd, 0x6a, 0x58, 0xdb, 0x1,
118 0xe2, 0xa8, 0xc1, 0xdd, 0x6a, 0x58, 0xdb, 0x1, 0xe2, 0xa8, 0xc1, 0xdd, 0x6a, 0x58,
119 0xdb, 0x1, 0xe6, 0x1, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xe8, 0x1, 0x0, 0x0, 0x0, 0x0, 0x0,
120 0x0, 0x20, 0x0, 0x0, 0x0, 0xa, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
121 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
122 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xbb, 0xf8, 0x0, 0x0, 0x0, 0x0, 0x4, 0x0, 0x63, 0x0,
123 0x2e, 0x0, 0x74, 0x0, 0x78, 0x0, 0x74, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
124 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x32, 0x66, 0x47, 0xd0, 0x6a, 0x58, 0xdb, 0x1, 0x3, 0xc,
125 0x39, 0x53, 0x49, 0x5d, 0xdb, 0x1, 0x3, 0xc, 0x39, 0x53, 0x49, 0x5d, 0xdb, 0x1, 0x3,
126 0xc, 0x39, 0x53, 0x49, 0x5d, 0xdb, 0x1, 0x26, 0x3e, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
127 0x40, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x20, 0x0, 0x0, 0x0, 0xa, 0x0, 0x0, 0x0, 0x0, 0x0,
128 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
129 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xbc, 0xf8, 0x0, 0x0,
130 0x0, 0x0, 0x4, 0x0, 0x64, 0x0, 0x2e, 0x0, 0x74, 0x0, 0x78, 0x0, 0x74, 0x0,
131 ];
132
133 let res = QueryDirectoryResponse {
134 output_buffer: data.to_vec(),
135 }
136 .read_output::<FileIdBothDirectoryInformation>()
137 .unwrap();
138
139 assert_eq!(
140 vec![
141 FileIdBothDirectoryInformation {
142 file_index: 0,
143 creation_time: FileTime::from(datetime!(2024-12-11 12:32:31.7084985)),
144 last_access_time: FileTime::from(datetime!(2025-01-03 10:18:15.6499175)),
145 last_write_time: FileTime::from(datetime!(2024-12-27 14:22:59.9648231)),
146 change_time: FileTime::from(datetime!(2024-12-27 14:22:59.9648231)),
147 end_of_file: 0,
148 allocation_size: 0,
149 file_attributes: FileAttributes::new().with_directory(true),
150 ea_size: Some(0),
151 reparse_tag: None,
152 short_name_length: 0,
153 short_name: [0; 12],
154 fild_id: 562949953454203,
155 file_name: ".".into(),
156 },
157 FileIdBothDirectoryInformation {
158 file_index: 0,
159 creation_time: FileTime::from(datetime!(2024-12-11 9:25:15.4208828)),
160 last_access_time: FileTime::from(datetime!(2025-01-02 19:05:31.8723088)),
161 last_write_time: FileTime::from(datetime!(2024-12-11 12:32:35.4544738)),
162 change_time: FileTime::from(datetime!(2024-12-11 12:32:35.4544738)),
163 end_of_file: 0,
164 allocation_size: 0,
165 file_attributes: FileAttributes::new().with_directory(true),
166 ea_size: Some(0),
167 reparse_tag: None,
168 short_name_length: 0,
169 short_name: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,],
170 fild_id: 1125899906967338,
171 file_name: "..".into(),
172 },
173 FileIdBothDirectoryInformation {
174 file_index: 0,
175 creation_time: FileTime::from(datetime!(2024-12-27 14:22:48.7929947)),
176 last_access_time: FileTime::from(datetime!(2024-12-27 14:22:48.7929947)),
177 last_write_time: FileTime::from(datetime!(2024-12-27 14:22:48.7929947)),
178 change_time: FileTime::from(datetime!(2024-12-27 14:22:49.7460575)),
179 end_of_file: 0,
180 allocation_size: 0,
181 file_attributes: FileAttributes::new().with_archive(true),
182 ea_size: Some(0),
183 reparse_tag: None,
184 short_name_length: 0,
185 short_name: [0; 12],
186 fild_id: 2814749767148784,
187 file_name: "a.txt".into(),
188 },
189 FileIdBothDirectoryInformation {
190 file_index: 0,
191 creation_time: FileTime::from(datetime!(2024-12-27 14:22:51.5742424)),
192 last_access_time: FileTime::from(datetime!(2024-12-27 14:23:06.9505662)),
193 last_write_time: FileTime::from(datetime!(2024-12-27 14:23:06.9505662)),
194 change_time: FileTime::from(datetime!(2024-12-27 14:23:06.9505662)),
195 end_of_file: 6,
196 allocation_size: 8,
197 file_attributes: FileAttributes::new().with_archive(true),
198 ea_size: Some(0),
199 reparse_tag: None,
200 short_name_length: 0,
201 short_name: [0; 12],
202 fild_id: 1125899906906297,
203 file_name: "b.txt".into(),
204 },
205 FileIdBothDirectoryInformation {
206 file_index: 0,
207 creation_time: FileTime::from(datetime!(2024-12-27 14:22:52.0116823)),
208 last_access_time: FileTime::from(datetime!(2024-12-27 14:23:14.7795682)),
209 last_write_time: FileTime::from(datetime!(2024-12-27 14:23:14.7795682)),
210 change_time: FileTime::from(datetime!(2024-12-27 14:23:14.7795682)),
211 end_of_file: 486,
212 allocation_size: 488,
213 file_attributes: FileAttributes::new().with_archive(true),
214 ea_size: Some(0),
215 reparse_tag: None,
216 short_name_length: 0,
217 short_name: [0; 12],
218 fild_id: 1125899906906299,
219 file_name: "c.txt".into(),
220 },
221 FileIdBothDirectoryInformation {
222 file_index: 0,
223 creation_time: FileTime::from(datetime!(2024-12-27 14:22:52.167941),),
224 last_access_time: FileTime::from(datetime!(2025-01-02 19:05:44.7804931),),
225 last_write_time: FileTime::from(datetime!(2025-01-02 19:05:44.7804931),),
226 change_time: FileTime::from(datetime!(2025-01-02 19:05:44.7804931),),
227 end_of_file: 15910,
228 allocation_size: 16384,
229 file_attributes: FileAttributes::new().with_archive(true),
230 ea_size: Some(0),
231 reparse_tag: None,
232 short_name_length: 0,
233 short_name: [0; 12],
234 fild_id: 1125899906906300,
235 file_name: "d.txt".into(),
236 },
237 ],
238 res
239 );
240 }
241}