use crate::archive::ArchiveContents;
use crate::encryption::EncryptionLayer;
use crate::error::VfsResult;
use crate::fs::{DynFs, FsKind};
use crate::source::DynSource;
use crate::volume::{VolumeScheme, VolumeSystem};
#[non_exhaustive]
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub enum ContainerFormat {
Ewf,
Vmdk,
Vhdx,
Vhd,
Qcow2,
Dmg,
Aff4,
Ad1,
Dar,
Raw,
Auto,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum Confidence {
No,
Maybe,
Yes { how: &'static str },
}
impl Confidence {
#[must_use]
pub fn is_candidate(self) -> bool {
!matches!(self, Confidence::No)
}
#[must_use]
pub fn is_yes(self) -> bool {
matches!(self, Confidence::Yes { .. })
}
}
pub struct SniffWindow<'a> {
base: u64,
bytes: &'a [u8],
total_len: u64,
tail: &'a [u8],
}
impl<'a> SniffWindow<'a> {
#[must_use]
pub fn new(base: u64, bytes: &'a [u8]) -> Self {
Self {
base,
bytes,
total_len: base.saturating_add(bytes.len() as u64),
tail: &[],
}
}
#[must_use]
pub fn with_tail(base: u64, bytes: &'a [u8], total_len: u64, tail: &'a [u8]) -> Self {
Self {
base,
bytes,
total_len,
tail,
}
}
#[must_use]
pub fn base(&self) -> u64 {
self.base
}
#[must_use]
pub fn bytes(&self) -> &[u8] {
self.bytes
}
#[must_use]
pub fn total_len(&self) -> u64 {
self.total_len
}
#[must_use]
pub fn at(&self, off: usize, n: usize) -> Option<&[u8]> {
let end = off.checked_add(n)?;
self.bytes.get(off..end)
}
#[must_use]
pub fn has_magic(&self, off: usize, magic: &[u8]) -> bool {
self.at(off, magic.len()) == Some(magic)
}
#[must_use]
pub fn tail_at(&self, from_end: usize, n: usize) -> Option<&[u8]> {
let start = self.tail.len().checked_sub(from_end)?;
let end = start.checked_add(n)?;
self.tail.get(start..end)
}
#[must_use]
pub fn has_magic_from_end(&self, from_end: usize, magic: &[u8]) -> bool {
self.tail_at(from_end, magic.len()) == Some(magic)
}
}
pub trait ContainerOpen: Send + Sync {
fn format(&self) -> ContainerFormat;
fn probe(&self, w: &SniffWindow) -> Confidence;
fn open(&self, src: DynSource) -> VfsResult<DynSource>;
}
pub trait VolumeSystemOpen: Send + Sync {
fn scheme(&self) -> VolumeScheme;
fn probe(&self, w: &SniffWindow) -> Confidence;
fn open(&self, src: DynSource) -> VfsResult<Box<dyn VolumeSystem>>;
}
pub trait EncryptionOpen: Send + Sync {
fn scheme(&self) -> crate::encryption::EncryptionScheme;
fn probe(&self, w: &SniffWindow) -> Confidence;
fn open(&self, src: DynSource) -> VfsResult<Box<dyn EncryptionLayer>>;
}
pub trait FileSystemOpen: Send + Sync {
fn kind(&self) -> FsKind;
fn probe(&self, w: &SniffWindow) -> Confidence;
fn open(&self, src: DynSource) -> VfsResult<DynFs>;
}
pub trait ArchiveOpen: Send + Sync {
fn probe(&self, w: &SniffWindow) -> Confidence;
fn open(&self, src: DynSource) -> VfsResult<ArchiveContents>;
}
#[derive(Default)]
pub struct Openers {
containers: Vec<Box<dyn ContainerOpen>>,
volume_systems: Vec<Box<dyn VolumeSystemOpen>>,
encryption: Vec<Box<dyn EncryptionOpen>>,
filesystems: Vec<Box<dyn FileSystemOpen>>,
archives: Vec<Box<dyn ArchiveOpen>>,
}
impl Openers {
#[must_use]
pub fn new() -> Self {
Self::default()
}
#[must_use]
pub fn container(mut self, d: impl ContainerOpen + 'static) -> Self {
self.containers.push(Box::new(d));
self
}
#[must_use]
pub fn volume_system(mut self, p: impl VolumeSystemOpen + 'static) -> Self {
self.volume_systems.push(Box::new(p));
self
}
#[must_use]
pub fn encryption(mut self, p: impl EncryptionOpen + 'static) -> Self {
self.encryption.push(Box::new(p));
self
}
#[must_use]
pub fn filesystem(mut self, p: impl FileSystemOpen + 'static) -> Self {
self.filesystems.push(Box::new(p));
self
}
#[must_use]
pub fn archive(mut self, a: impl ArchiveOpen + 'static) -> Self {
self.archives.push(Box::new(a));
self
}
#[must_use]
pub fn containers(&self) -> &[Box<dyn ContainerOpen>] {
&self.containers
}
#[must_use]
pub fn volume_systems(&self) -> &[Box<dyn VolumeSystemOpen>] {
&self.volume_systems
}
#[must_use]
pub fn encryption_layers(&self) -> &[Box<dyn EncryptionOpen>] {
&self.encryption
}
#[must_use]
pub fn filesystems(&self) -> &[Box<dyn FileSystemOpen>] {
&self.filesystems
}
#[must_use]
pub fn archives(&self) -> &[Box<dyn ArchiveOpen>] {
&self.archives
}
}