forensic_rs/traits/
vfs.rs

1use std::{
2    fmt::Display,
3    path::{Path, PathBuf},
4};
5
6use crate::err::ForensicResult;
7
8pub struct VPath(PathBuf);
9
10impl From<&str> for VPath {
11    fn from(v: &str) -> Self {
12        VPath(PathBuf::from(v))
13    }
14}
15impl From<String> for VPath {
16    fn from(v: String) -> Self {
17        VPath(PathBuf::from(v))
18    }
19}
20impl From<PathBuf> for VPath {
21    fn from(v: PathBuf) -> Self {
22        VPath(v)
23    }
24}
25impl From<&Path> for VPath {
26    fn from(v: &Path) -> Self {
27        VPath(v.to_path_buf())
28    }
29}
30
31pub trait VirtualFile: std::io::Seek + std::io::Read {
32    fn metadata(&self) -> ForensicResult<VMetadata>;
33}
34
35pub trait VirtualFileSystem {
36    /// Initializes a virtual filesystem from a file. Ex: a Zip FS from a file
37    fn from_file(&self, file: Box<dyn VirtualFile>) -> ForensicResult<Box<dyn VirtualFileSystem>>;
38    /// Initializes a virtual filesystem from a filesyste. Ex: a remapping of windows routes to Linux routes.
39    fn from_fs(&self, fs: Box<dyn VirtualFileSystem>)
40        -> ForensicResult<Box<dyn VirtualFileSystem>>;
41    /// Read the entire contents of a file into a string.
42    fn read_to_string(&mut self, path: &Path) -> ForensicResult<String>;
43    /// Read the entire contents of a file into a bytes vector.
44    fn read_all(&mut self, path: &Path) -> ForensicResult<Vec<u8>>;
45    /// Read part of the content of a file into a bytes vector.
46    fn read(&mut self, path: &Path, pos: u64, buf: &mut [u8]) -> ForensicResult<usize>;
47    /// Get the metadata of a file/dir
48    fn metadata(&mut self, path: &Path) -> ForensicResult<VMetadata>;
49    /// Lists the contents of a Directory
50    fn read_dir(&mut self, path: &Path) -> ForensicResult<Vec<VDirEntry>>;
51    /// Check if the VirtualFileSystem is an abstraction over the real filesystem and not a virtual (like a ZIP file).
52    fn is_live(&self) -> bool;
53    /// Open a file
54    fn open(&mut self, path: &Path) -> ForensicResult<Box<dyn VirtualFile>>;
55    /// Allows duplicating the existing file system
56    fn duplicate(&self) -> Box<dyn VirtualFileSystem>;
57    /// Check if a file exists
58    #[allow(unused_variables)]
59    fn exists(&self, path: &Path) -> bool {
60        false
61    }
62}
63
64pub struct VMetadata {
65    /// Seconds elapsed since UNIX_EPOCH in UTC
66    ///
67    /// this is optional, because some filesystems might not support this timestamp
68    pub created: Option<usize>,
69
70    /// Seconds elapsed since UNIX_EPOCH in UTC
71    ///
72    /// this is optional, because some filesystems might not support this timestamp
73    pub accessed: Option<usize>,
74
75    /// Seconds elapsed since UNIX_EPOCH in UTC
76    ///
77    /// this is optional, because some filesystems might not support this timestamp
78    pub modified: Option<usize>,
79
80    pub file_type: VFileType,
81    pub size: u64,
82}
83
84#[derive(PartialEq)]
85pub enum VFileType {
86    File,
87    Directory,
88    Symlink,
89}
90
91impl VMetadata {
92    /// Seconds elapsed since UNIX_EPOCH in UTC
93    pub fn created(&self) -> usize {
94        self.created.unwrap_or_else(|| {
95            crate::warn!(
96                "this filesystem has no support for creation time, using UNIX_EPOCH instead"
97            );
98            0
99        })
100    }
101    /// Seconds elapsed since UNIX_EPOCH in UTC
102    pub fn accessed(&self) -> usize {
103        self.accessed.unwrap_or_else(|| {
104            crate::warn!("this filesystem has no support for access time, using UNIX_EPOCH instead");
105            0
106        })
107    }
108    /// Seconds elapsed since UNIX_EPOCH in UTC
109    pub fn modified(&self) -> usize {
110        self.modified.unwrap_or_else(|| {
111            crate::warn!(
112                "this filesystem has no support for modification time, using UNIX_EPOCH instead"
113            );
114            0
115        })
116    }
117
118    /// Seconds elapsed since UNIX_EPOCH in UTC
119    pub fn created_opt(&self) -> Option<&usize> {
120        self.created.as_ref()
121    }
122    /// Seconds elapsed since UNIX_EPOCH in UTC
123    pub fn accessed_opt(&self) -> Option<&usize> {
124        self.accessed.as_ref()
125    }
126    /// Seconds elapsed since UNIX_EPOCH in UTC
127    pub fn modified_opt(&self) -> Option<&usize> {
128        self.modified.as_ref()
129    }
130    pub fn is_file(&self) -> bool {
131        self.file_type == VFileType::File
132    }
133    pub fn is_dir(&self) -> bool {
134        self.file_type == VFileType::Directory
135    }
136    pub fn is_symlink(&self) -> bool {
137        self.file_type == VFileType::Symlink
138    }
139    pub fn len(&self) -> u64 {
140        self.size
141    }
142}
143
144pub enum VDirEntry {
145    Directory(String),
146    File(String),
147    Symlink(String),
148}
149
150impl Display for VDirEntry {
151    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
152        let content = match self {
153            VDirEntry::Directory(v) => v,
154            VDirEntry::File(v) => v,
155            VDirEntry::Symlink(v) => v,
156        };
157        write!(f, "{}", content)
158    }
159}