1use crate::archive::ArchiveContents;
10use crate::encryption::EncryptionLayer;
11use crate::error::VfsResult;
12use crate::fs::{DynFs, FsKind};
13use crate::source::DynSource;
14use crate::volume::{VolumeScheme, VolumeSystem};
15
16#[non_exhaustive]
18#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
19pub enum ContainerFormat {
20 Ewf,
21 Vmdk,
22 Vhdx,
23 Vhd,
24 Qcow2,
25 Dmg,
26 Aff4,
27 Ad1,
28 Dar,
29 Raw,
31 Auto,
33}
34
35#[derive(Debug, Clone, Copy, PartialEq, Eq)]
37pub enum Confidence {
38 No,
39 Maybe,
40 Yes { how: &'static str },
41}
42
43impl Confidence {
44 #[must_use]
46 pub fn is_candidate(self) -> bool {
47 !matches!(self, Confidence::No)
48 }
49
50 #[must_use]
52 pub fn is_yes(self) -> bool {
53 matches!(self, Confidence::Yes { .. })
54 }
55}
56
57pub struct SniffWindow<'a> {
64 base: u64,
65 bytes: &'a [u8],
66 total_len: u64,
67 tail: &'a [u8],
68}
69
70impl<'a> SniffWindow<'a> {
71 #[must_use]
75 pub fn new(base: u64, bytes: &'a [u8]) -> Self {
76 Self {
77 base,
78 bytes,
79 total_len: base.saturating_add(bytes.len() as u64),
80 tail: &[],
81 }
82 }
83
84 #[must_use]
88 pub fn with_tail(base: u64, bytes: &'a [u8], total_len: u64, tail: &'a [u8]) -> Self {
89 Self {
90 base,
91 bytes,
92 total_len,
93 tail,
94 }
95 }
96
97 #[must_use]
99 pub fn base(&self) -> u64 {
100 self.base
101 }
102
103 #[must_use]
105 pub fn bytes(&self) -> &[u8] {
106 self.bytes
107 }
108
109 #[must_use]
111 pub fn total_len(&self) -> u64 {
112 self.total_len
113 }
114
115 #[must_use]
118 pub fn at(&self, off: usize, n: usize) -> Option<&[u8]> {
119 let end = off.checked_add(n)?;
120 self.bytes.get(off..end)
121 }
122
123 #[must_use]
125 pub fn has_magic(&self, off: usize, magic: &[u8]) -> bool {
126 self.at(off, magic.len()) == Some(magic)
127 }
128
129 #[must_use]
132 pub fn tail_at(&self, from_end: usize, n: usize) -> Option<&[u8]> {
133 let start = self.tail.len().checked_sub(from_end)?;
134 let end = start.checked_add(n)?;
135 self.tail.get(start..end)
136 }
137
138 #[must_use]
142 pub fn has_magic_from_end(&self, from_end: usize, magic: &[u8]) -> bool {
143 self.tail_at(from_end, magic.len()) == Some(magic)
144 }
145}
146
147pub trait ContainerOpen: Send + Sync {
149 fn format(&self) -> ContainerFormat;
150 fn probe(&self, w: &SniffWindow) -> Confidence;
151 fn open(&self, src: DynSource) -> VfsResult<DynSource>;
152}
153
154pub trait VolumeSystemOpen: Send + Sync {
156 fn scheme(&self) -> VolumeScheme;
157 fn probe(&self, w: &SniffWindow) -> Confidence;
158 fn open(&self, src: DynSource) -> VfsResult<Box<dyn VolumeSystem>>;
159}
160
161pub trait EncryptionOpen: Send + Sync {
163 fn scheme(&self) -> crate::encryption::EncryptionScheme;
164 fn probe(&self, w: &SniffWindow) -> Confidence;
165 fn open(&self, src: DynSource) -> VfsResult<Box<dyn EncryptionLayer>>;
166}
167
168pub trait FileSystemOpen: Send + Sync {
170 fn kind(&self) -> FsKind;
171 fn probe(&self, w: &SniffWindow) -> Confidence;
172 fn open(&self, src: DynSource) -> VfsResult<DynFs>;
173}
174
175pub trait ArchiveOpen: Send + Sync {
182 fn probe(&self, w: &SniffWindow) -> Confidence;
183 fn open(&self, src: DynSource) -> VfsResult<ArchiveContents>;
184}
185
186#[derive(Default)]
190pub struct Openers {
191 containers: Vec<Box<dyn ContainerOpen>>,
192 volume_systems: Vec<Box<dyn VolumeSystemOpen>>,
193 encryption: Vec<Box<dyn EncryptionOpen>>,
194 filesystems: Vec<Box<dyn FileSystemOpen>>,
195 archives: Vec<Box<dyn ArchiveOpen>>,
196}
197
198impl Openers {
199 #[must_use]
201 pub fn new() -> Self {
202 Self::default()
203 }
204
205 #[must_use]
207 pub fn container(mut self, d: impl ContainerOpen + 'static) -> Self {
208 self.containers.push(Box::new(d));
209 self
210 }
211
212 #[must_use]
214 pub fn volume_system(mut self, p: impl VolumeSystemOpen + 'static) -> Self {
215 self.volume_systems.push(Box::new(p));
216 self
217 }
218
219 #[must_use]
221 pub fn encryption(mut self, p: impl EncryptionOpen + 'static) -> Self {
222 self.encryption.push(Box::new(p));
223 self
224 }
225
226 #[must_use]
228 pub fn filesystem(mut self, p: impl FileSystemOpen + 'static) -> Self {
229 self.filesystems.push(Box::new(p));
230 self
231 }
232
233 #[must_use]
235 pub fn archive(mut self, a: impl ArchiveOpen + 'static) -> Self {
236 self.archives.push(Box::new(a));
237 self
238 }
239
240 #[must_use]
242 pub fn containers(&self) -> &[Box<dyn ContainerOpen>] {
243 &self.containers
244 }
245 #[must_use]
247 pub fn volume_systems(&self) -> &[Box<dyn VolumeSystemOpen>] {
248 &self.volume_systems
249 }
250 #[must_use]
252 pub fn encryption_layers(&self) -> &[Box<dyn EncryptionOpen>] {
253 &self.encryption
254 }
255 #[must_use]
257 pub fn filesystems(&self) -> &[Box<dyn FileSystemOpen>] {
258 &self.filesystems
259 }
260 #[must_use]
262 pub fn archives(&self) -> &[Box<dyn ArchiveOpen>] {
263 &self.archives
264 }
265}