use std::sync::Arc;
use crate::error::VfsResult;
#[non_exhaustive]
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub enum FileId {
NtfsRef { entry: u64, seq: u16 },
ExtInode { ino: u64, gen: u32 },
ApfsOid { oid: u64, xid: u64 },
FatDirEntry { cluster: u32, index: u16 },
IsoExtent { block: u32 },
Opaque(u64),
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct StreamInfo {
pub id: StreamId,
pub name: Option<Vec<u8>>,
pub size: u64,
pub residency: ResidencyKind,
pub kind: StreamKind,
}
#[non_exhaustive]
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub enum StreamId {
Default,
Named(u16),
ResourceFork,
Xattr(u16),
Slack,
}
#[non_exhaustive]
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum StreamKind {
NtfsData,
NtfsAds,
HfsResourceFork,
ApfsNamed,
Xattr,
SyntheticSlack,
}
#[non_exhaustive]
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum ResidencyKind {
Resident { inline_len: u32 },
NonResident,
}
#[non_exhaustive]
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum Allocation {
Allocated,
Deleted,
Orphan,
}
#[non_exhaustive]
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum NodeKind {
File,
Dir,
Symlink,
Device,
Other,
}
#[non_exhaustive]
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum TimeSource {
Si,
Fn,
InodeTable,
DirEntry,
Unspecified,
}
#[non_exhaustive]
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum TimeResolution {
WinFileTime,
Nanos,
Micros,
Seconds,
TwoSeconds,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct TimeStamp {
pub unix_nanos: i128,
pub source: TimeSource,
pub resolution: TimeResolution,
}
#[derive(Debug, Clone, Copy, Default, PartialEq, Eq)]
pub struct MacbTimes {
pub modified: Option<TimeStamp>,
pub accessed: Option<TimeStamp>,
pub changed: Option<TimeStamp>,
pub born: Option<TimeStamp>,
}
#[non_exhaustive]
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum TimeZonePolicy {
Utc,
LocalUnknown,
Local { minutes_east: i16 },
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct SectorSizes {
pub logical: u32,
pub physical: u32,
pub cluster_or_block: u32,
}
#[allow(clippy::struct_excessive_bools)] #[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
pub struct RunFlags {
pub sparse: bool,
pub encrypted: bool,
pub compressed: bool,
pub filler: bool,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct ByteRun {
pub image_offset: u64,
pub len: u64,
pub flags: RunFlags,
}
#[non_exhaustive]
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum RunAlloc {
Allocated,
Unallocated,
Overwritten,
Unknown,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct RunInfo {
pub run: ByteRun,
pub alloc: RunAlloc,
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct DirEntry {
pub name: Vec<u8>,
pub id: FileId,
pub kind: NodeKind,
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct HardLink {
pub parent: FileId,
pub name: Vec<u8>,
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct FsMeta {
pub ino: u64,
pub kind: NodeKind,
pub allocated: Allocation,
pub size: u64,
pub nlink: u32,
pub uid: Option<u32>,
pub gid: Option<u32>,
pub mode: Option<u32>,
pub times: MacbTimes,
pub streams: Vec<StreamInfo>,
pub residency: ResidencyKind,
pub link_target: Option<Vec<u8>>,
}
pub struct DirStream(Box<dyn Iterator<Item = VfsResult<DirEntry>> + Send>);
pub struct ExtentStream(Box<dyn Iterator<Item = VfsResult<RunInfo>> + Send>);
pub struct NodeStream(Box<dyn Iterator<Item = VfsResult<FsMeta>> + Send>);
impl DirStream {
pub fn new(it: impl Iterator<Item = VfsResult<DirEntry>> + Send + 'static) -> Self {
Self(Box::new(it))
}
#[must_use]
pub fn empty() -> Self {
Self(Box::new(std::iter::empty()))
}
}
impl ExtentStream {
pub fn new(it: impl Iterator<Item = VfsResult<RunInfo>> + Send + 'static) -> Self {
Self(Box::new(it))
}
#[must_use]
pub fn empty() -> Self {
Self(Box::new(std::iter::empty()))
}
}
impl NodeStream {
pub fn new(it: impl Iterator<Item = VfsResult<FsMeta>> + Send + 'static) -> Self {
Self(Box::new(it))
}
#[must_use]
pub fn empty() -> Self {
Self(Box::new(std::iter::empty()))
}
}
impl Iterator for DirStream {
type Item = VfsResult<DirEntry>;
fn next(&mut self) -> Option<Self::Item> {
self.0.next()
}
}
impl Iterator for ExtentStream {
type Item = VfsResult<RunInfo>;
fn next(&mut self) -> Option<Self::Item> {
self.0.next()
}
}
impl Iterator for NodeStream {
type Item = VfsResult<FsMeta>;
fn next(&mut self) -> Option<Self::Item> {
self.0.next()
}
}
pub use forensicnomicon_core::filesystems::FsKind;
pub trait FileSystem: Send + Sync {
fn kind(&self) -> FsKind;
fn root(&self) -> FileId;
fn sector_sizes(&self) -> SectorSizes;
fn timestamp_zone(&self) -> TimeZonePolicy;
fn read_dir(&self, ino: FileId) -> VfsResult<DirStream>;
fn extents(&self, ino: FileId, stream: StreamId) -> VfsResult<ExtentStream>;
fn lookup(&self, parent: FileId, name: &[u8]) -> VfsResult<Option<FileId>>;
fn meta(&self, ino: FileId) -> VfsResult<FsMeta>;
fn read_at(&self, ino: FileId, stream: StreamId, off: u64, buf: &mut [u8]) -> VfsResult<usize>;
fn read_link(&self, ino: FileId, cap: usize) -> VfsResult<Vec<u8>>;
fn data_streams(&self, ino: FileId) -> VfsResult<Vec<StreamInfo>> {
let _ = ino;
Ok(Vec::new())
}
fn hardlinks(&self, ino: FileId) -> VfsResult<Vec<HardLink>> {
let _ = ino;
Ok(Vec::new())
}
fn deleted(&self) -> VfsResult<NodeStream>;
fn unallocated(&self) -> VfsResult<ExtentStream>;
fn slack(&self, ino: FileId, stream: StreamId) -> VfsResult<Option<ByteRun>> {
let _ = (ino, stream);
Ok(None)
}
#[cfg(feature = "findings")]
fn findings(&self) -> VfsResult<Vec<forensicnomicon::report::Finding>> {
Ok(Vec::new())
}
}
pub type DynFs = Arc<dyn FileSystem>;