1use crate::internal::{consts, DirEntry, MiniAllocator, ObjType, Timestamp};
2use std::fmt;
3use std::path::{Path, PathBuf};
4use std::sync::{Arc, RwLock};
5use std::time::SystemTime;
6use uuid::Uuid;
7
8#[derive(Clone)]
12pub struct Entry {
13 name: String,
14 path: PathBuf,
15 obj_type: ObjType,
16 clsid: Uuid,
17 state_bits: u32,
18 creation_time: Timestamp,
19 modified_time: Timestamp,
20 stream_len: u64,
21}
22
23impl Entry {
24 pub(crate) fn new(dir_entry: &DirEntry, path: PathBuf) -> Entry {
25 Entry {
26 name: dir_entry.name.clone(),
27 path,
28 obj_type: dir_entry.obj_type,
29 clsid: dir_entry.clsid,
30 state_bits: dir_entry.state_bits,
31 creation_time: dir_entry.creation_time,
32 modified_time: dir_entry.modified_time,
33 stream_len: dir_entry.stream_len,
34 }
35 }
36
37 pub fn name(&self) -> &str {
39 &self.name
40 }
41
42 pub fn path(&self) -> &Path {
44 &self.path
45 }
46
47 pub fn is_stream(&self) -> bool {
50 self.obj_type == ObjType::Stream
51 }
52
53 pub fn is_storage(&self) -> bool {
56 self.obj_type == ObjType::Storage || self.obj_type == ObjType::Root
57 }
58
59 pub fn is_root(&self) -> bool {
62 self.obj_type == ObjType::Root
63 }
64
65 pub fn len(&self) -> u64 {
67 self.stream_len
68 }
69
70 pub fn is_empty(&self) -> bool {
72 self.stream_len == 0
73 }
74
75 pub fn clsid(&self) -> &Uuid {
78 &self.clsid
79 }
80
81 pub fn state_bits(&self) -> u32 {
83 self.state_bits
84 }
85
86 pub fn created(&self) -> SystemTime {
89 self.creation_time.to_system_time()
90 }
91
92 pub fn modified(&self) -> SystemTime {
95 self.modified_time.to_system_time()
96 }
97}
98
99impl fmt::Debug for Entry {
100 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> {
101 write!(
102 f,
103 "{path} ({len} bytes)",
104 path = self.path().display(),
105 len = self.len()
106 )
107 }
108}
109
110#[derive(Clone, Copy, Eq, PartialEq)]
113pub enum EntriesOrder {
114 Nonrecursive,
115 Preorder,
116}
117
118pub struct Entries<'a, F: 'a> {
122 order: EntriesOrder,
123 minialloc: &'a Arc<RwLock<MiniAllocator<F>>>,
128 stack: Vec<(PathBuf, u32, bool)>,
129}
130
131impl<'a, F> Entries<'a, F> {
132 pub(crate) fn new(
133 order: EntriesOrder,
134 minialloc: &'a Arc<RwLock<MiniAllocator<F>>>,
135 parent_path: PathBuf,
136 start: u32,
137 ) -> Entries<'a, F> {
138 let mut entries = Entries { order, minialloc, stack: Vec::new() };
139 match order {
140 EntriesOrder::Nonrecursive => {
141 entries.stack_left_spine(&parent_path, start);
142 }
143 EntriesOrder::Preorder => {
144 entries.stack.push((parent_path, start, false));
145 }
146 }
147 entries
148 }
149
150 fn stack_left_spine(&mut self, parent_path: &Path, mut current_id: u32) {
151 let minialloc = self.minialloc.read().unwrap();
152 while current_id != consts::NO_STREAM {
153 self.stack.push((parent_path.to_path_buf(), current_id, true));
154 current_id = minialloc.dir_entry(current_id).left_sibling;
155 }
156 }
157}
158
159impl<'a, F> Iterator for Entries<'a, F> {
160 type Item = Entry;
161
162 fn next(&mut self) -> Option<Entry> {
163 if let Some((parent, stream_id, visit_siblings)) = self.stack.pop() {
164 let minialloc = self.minialloc.read().unwrap();
165 let dir_entry = minialloc.dir_entry(stream_id);
166 let path = join_path(&parent, dir_entry);
167 if visit_siblings {
168 self.stack_left_spine(&parent, dir_entry.right_sibling);
169 }
170 if self.order == EntriesOrder::Preorder
171 && dir_entry.obj_type != ObjType::Stream
172 && dir_entry.child != consts::NO_STREAM
173 {
174 self.stack_left_spine(&path, dir_entry.child);
175 }
176 Some(Entry::new(dir_entry, path))
177 } else {
178 None
179 }
180 }
181}
182
183fn join_path(parent_path: &Path, dir_entry: &DirEntry) -> PathBuf {
186 if dir_entry.obj_type == ObjType::Root {
187 parent_path.to_path_buf()
188 } else {
189 parent_path.join(&dir_entry.name)
190 }
191}
192
193#[cfg(test)]
196mod tests {
197 use super::{Entries, EntriesOrder, Entry};
198 use crate::internal::consts::{self, NO_STREAM, ROOT_DIR_NAME};
199 use crate::internal::{
200 Allocator, DirEntry, Directory, MiniAllocator, ObjType, Sectors,
201 Timestamp, Validation, Version,
202 };
203 use std::path::{Path, PathBuf};
204 use std::sync::{Arc, RwLock};
205
206 fn make_entry(
207 name: &str,
208 obj_type: ObjType,
209 left: u32,
210 child: u32,
211 right: u32,
212 ) -> DirEntry {
213 let mut dir_entry = DirEntry::new(name, obj_type, Timestamp::zero());
214 dir_entry.left_sibling = left;
215 dir_entry.child = child;
216 dir_entry.right_sibling = right;
217 dir_entry
218 }
219
220 fn make_minialloc() -> Arc<RwLock<MiniAllocator<()>>> {
221 let dir_entries = vec![
230 make_entry(ROOT_DIR_NAME, ObjType::Root, NO_STREAM, 5, NO_STREAM),
231 make_entry("1", ObjType::Stream, NO_STREAM, NO_STREAM, 2),
232 make_entry("2", ObjType::Stream, NO_STREAM, NO_STREAM, NO_STREAM),
233 make_entry("3", ObjType::Storage, 1, 8, 4),
234 make_entry("4", ObjType::Stream, NO_STREAM, NO_STREAM, NO_STREAM),
235 make_entry("5", ObjType::Stream, 3, NO_STREAM, 6),
236 make_entry("6", ObjType::Storage, NO_STREAM, NO_STREAM, NO_STREAM),
237 make_entry("7", ObjType::Stream, NO_STREAM, NO_STREAM, NO_STREAM),
238 make_entry("8", ObjType::Stream, 7, NO_STREAM, 9),
239 make_entry("9", ObjType::Stream, NO_STREAM, NO_STREAM, NO_STREAM),
240 ];
241 let version = Version::V3;
242 let sectors =
243 Sectors::new(version, 3 * version.sector_len() as u64, ());
244 let allocator = Allocator::new(
245 sectors,
246 vec![],
247 vec![0],
248 vec![consts::FAT_SECTOR, consts::END_OF_CHAIN],
249 Validation::Strict,
250 )
251 .unwrap();
252 let directory =
253 Directory::new(allocator, dir_entries, 1, Validation::Strict)
254 .unwrap();
255 let minialloc = MiniAllocator::new(
256 directory,
257 vec![],
258 consts::END_OF_CHAIN,
259 Validation::Strict,
260 )
261 .unwrap();
262 Arc::new(RwLock::new(minialloc))
263 }
264
265 fn paths_for_entries(entries: &[Entry]) -> Vec<&Path> {
266 entries.iter().map(|entry| entry.path()).collect()
267 }
268
269 #[test]
270 fn nonrecursive_entries_from_root() {
271 let minialloc = make_minialloc();
272 let entries: Vec<Entry> = Entries::new(
273 EntriesOrder::Nonrecursive,
274 &minialloc,
275 PathBuf::from("/"),
276 5,
277 )
278 .collect();
279 let paths = paths_for_entries(&entries);
280 assert_eq!(
281 paths,
282 vec![
283 Path::new("/1"),
284 Path::new("/2"),
285 Path::new("/3"),
286 Path::new("/4"),
287 Path::new("/5"),
288 Path::new("/6")
289 ]
290 );
291 }
292
293 #[test]
294 fn nonrecursive_entries_from_storage() {
295 let minialloc = make_minialloc();
296 let entries: Vec<Entry> = Entries::new(
297 EntriesOrder::Nonrecursive,
298 &minialloc,
299 PathBuf::from("/3"),
300 8,
301 )
302 .collect();
303 let paths = paths_for_entries(&entries);
304 assert_eq!(
305 paths,
306 vec![Path::new("/3/7"), Path::new("/3/8"), Path::new("/3/9")]
307 );
308 }
309
310 #[test]
311 fn preorder_entries_from_root() {
312 let minialloc = make_minialloc();
313 let entries: Vec<Entry> = Entries::new(
314 EntriesOrder::Preorder,
315 &minialloc,
316 PathBuf::from("/"),
317 0,
318 )
319 .collect();
320 let paths = paths_for_entries(&entries);
321 assert_eq!(
322 paths,
323 vec![
324 Path::new("/"),
325 Path::new("/1"),
326 Path::new("/2"),
327 Path::new("/3"),
328 Path::new("/3/7"),
329 Path::new("/3/8"),
330 Path::new("/3/9"),
331 Path::new("/4"),
332 Path::new("/5"),
333 Path::new("/6"),
334 ]
335 );
336 }
337
338 #[test]
339 fn preorder_entries_from_storage() {
340 let minialloc = make_minialloc();
341 let entries: Vec<Entry> = Entries::new(
342 EntriesOrder::Preorder,
343 &minialloc,
344 PathBuf::from("/"),
345 3,
346 )
347 .collect();
348 let paths = paths_for_entries(&entries);
349 assert_eq!(
350 paths,
351 vec![
352 Path::new("/3"),
353 Path::new("/3/7"),
354 Path::new("/3/8"),
355 Path::new("/3/9")
356 ]
357 );
358 }
359}
360
361