1use crate::cluster::ClustersReader;
2use crate::entries::{ClusterAllocation, EntriesReader, EntryType, FileEntry, StreamEntry};
3use crate::file::File;
4use crate::image::Image;
5use std::io::{Read, Seek};
6use std::ops::DerefMut;
7use std::sync::Arc;
8use thiserror::Error;
9
10pub struct Directory<I: Read + Seek> {
12 image: Arc<Image<I>>,
13 name: String,
14 stream: StreamEntry,
15}
16
17impl<I: Read + Seek> Directory<I> {
18 pub(crate) fn new(image: Arc<Image<I>>, name: String, stream: StreamEntry) -> Self {
19 Self {
20 image,
21 name,
22 stream,
23 }
24 }
25
26 pub fn name(&self) -> &str {
27 self.name.as_ref()
28 }
29
30 pub fn open(&self) -> Result<Vec<Item<I>>, OpenError> {
31 let params = self.image.params();
33 let fat = self.image.fat();
34 let mut image = self.image.reader();
35 let alloc = self.stream.allocation();
36 let mut reader = match ClustersReader::new(
37 params,
38 fat,
39 image.deref_mut(),
40 alloc.first_cluster(),
41 Some(alloc.data_length()),
42 Some(self.stream.no_fat_chain()),
43 ) {
44 Ok(v) => EntriesReader::new(v),
45 Err(e) => return Err(OpenError::CreateClustersReaderFailed(alloc.clone(), e)),
46 };
47
48 let mut items: Vec<Item<I>> = Vec::new();
50
51 loop {
52 let entry = match reader.read() {
54 Ok(v) => v,
55 Err(e) => return Err(OpenError::ReadEntryFailed(e)),
56 };
57
58 let ty = entry.ty();
60
61 if !ty.is_regular() {
62 break;
63 } else if ty.type_category() != EntryType::PRIMARY {
64 return Err(OpenError::NotPrimaryEntry(entry.index(), entry.cluster()));
65 } else if ty.type_importance() != EntryType::CRITICAL || ty.type_code() != 5 {
66 return Err(OpenError::NotFileEntry(entry.index(), entry.cluster()));
67 }
68
69 let file = match FileEntry::load(entry, &mut reader) {
71 Ok(v) => v,
72 Err(e) => return Err(OpenError::LoadFileEntryFailed(e)),
73 };
74
75 let name = file.name;
77 let attrs = file.attributes;
78 let stream = file.stream;
79
80 let item = if attrs.is_directory() {
81 Item::Directory(Directory::new(self.image.clone(), name, stream))
82 } else {
83 Item::File(File::new(self.image.clone(), name, stream))
84 };
85
86 items.push(item);
87 }
88
89 Ok(items)
90 }
91}
92
93pub enum Item<I: Read + Seek> {
95 Directory(Directory<I>),
96 File(File<I>),
97}
98
99#[derive(Debug, Error)]
101pub enum OpenError {
102 #[error("cannot create a clusters reader for allocation {0}")]
103 CreateClustersReaderFailed(ClusterAllocation, #[source] crate::cluster::NewError),
104
105 #[error("cannot read an entry")]
106 ReadEntryFailed(#[source] crate::entries::ReaderError),
107
108 #[error("entry #{0} on cluster #{1} is not a primary entry")]
109 NotPrimaryEntry(usize, usize),
110
111 #[error("entry #{0} on cluster #{1} is not a file entry")]
112 NotFileEntry(usize, usize),
113
114 #[error("cannot load file entry")]
115 LoadFileEntryFailed(#[source] crate::entries::FileEntryError),
116}