veridian_kernel/pkg/
manifest.rs1#[cfg(feature = "alloc")]
8extern crate alloc;
9
10#[cfg(feature = "alloc")]
11use alloc::{collections::BTreeMap, string::String, vec::Vec};
12
13use crate::error::KernelError;
14
15#[cfg(feature = "alloc")]
17#[derive(Debug, Clone, Copy, PartialEq, Eq)]
18pub enum FileType {
19 Binary,
21 Config,
23 Documentation,
25 Asset,
27}
28
29#[cfg(feature = "alloc")]
30impl FileType {
31 pub fn parse(s: &str) -> Self {
33 match s {
34 "config" | "conf" | "cfg" => Self::Config,
35 "doc" | "documentation" | "man" => Self::Documentation,
36 "asset" | "data" | "resource" => Self::Asset,
37 _ => Self::Binary,
38 }
39 }
40
41 pub fn from_path(path: &str) -> Self {
43 if path.contains("/etc/")
44 || path.ends_with(".conf")
45 || path.ends_with(".cfg")
46 || path.ends_with(".ini")
47 || path.ends_with(".toml")
48 || path.ends_with(".yaml")
49 || path.ends_with(".json")
50 {
51 Self::Config
52 } else if path.contains("/doc/")
53 || path.contains("/man/")
54 || path.ends_with(".md")
55 || path.ends_with(".txt")
56 || path.ends_with(".html")
57 || path.ends_with(".1")
58 {
59 Self::Documentation
60 } else if path.contains("/share/")
61 || path.ends_with(".png")
62 || path.ends_with(".svg")
63 || path.ends_with(".ico")
64 || path.ends_with(".ttf")
65 || path.ends_with(".otf")
66 {
67 Self::Asset
68 } else {
69 Self::Binary
70 }
71 }
72
73 pub fn to_byte(self) -> u8 {
75 match self {
76 Self::Binary => 0,
77 Self::Config => 1,
78 Self::Documentation => 2,
79 Self::Asset => 3,
80 }
81 }
82
83 pub fn from_byte(b: u8) -> Self {
85 match b {
86 1 => Self::Config,
87 2 => Self::Documentation,
88 3 => Self::Asset,
89 _ => Self::Binary,
90 }
91 }
92}
93
94#[cfg(feature = "alloc")]
96pub struct FileManifest {
97 entries: BTreeMap<String, Vec<FileRecord>>,
99}
100
101#[cfg(feature = "alloc")]
103#[derive(Clone)]
104pub struct FileRecord {
105 pub path: String,
107 pub size: u64,
109 pub checksum: u64,
111 pub file_type: FileType,
113}
114
115#[cfg(feature = "alloc")]
116impl FileManifest {
117 pub fn new() -> Self {
118 Self {
119 entries: BTreeMap::new(),
120 }
121 }
122
123 pub fn record_installation(&mut self, package: &str, files: Vec<FileRecord>) {
127 self.entries.insert(String::from(package), files);
128 }
129
130 pub fn verify_installation(&self, package: &str) -> Result<bool, KernelError> {
136 let records = self.entries.get(package).ok_or(KernelError::NotFound {
137 resource: "package manifest",
138 id: 0,
139 })?;
140
141 for record in records {
142 if let Some(vfs_lock) = crate::fs::try_get_vfs() {
143 let vfs = vfs_lock.read();
144 match vfs.resolve_path(&record.path) {
145 Ok(node) => {
146 if let Ok(metadata) = node.metadata() {
147 if metadata.size as u64 != record.size {
148 return Ok(false);
149 }
150 }
151 }
152 Err(_) => return Ok(false),
153 }
154 }
155 }
156
157 Ok(true)
158 }
159
160 pub fn get_package_files(&self, package: &str) -> Option<&[FileRecord]> {
162 self.entries.get(package).map(|v| v.as_slice())
163 }
164
165 pub fn find_file_owner(&self, path: &str) -> Option<String> {
169 for (package, records) in &self.entries {
170 if records.iter().any(|r| r.path == path) {
171 return Some(package.clone());
172 }
173 }
174 None
175 }
176
177 pub fn remove_package(&mut self, package: &str) -> Option<Vec<FileRecord>> {
182 self.entries.remove(package)
183 }
184
185 pub fn list_config_files(&self, package: &str) -> Vec<&FileRecord> {
187 self.entries
188 .get(package)
189 .map(|records| {
190 records
191 .iter()
192 .filter(|r| r.file_type == FileType::Config)
193 .collect()
194 })
195 .unwrap_or_else(Vec::new)
196 }
197
198 pub fn list_doc_files(&self, package: &str) -> Vec<&FileRecord> {
200 self.entries
201 .get(package)
202 .map(|records| {
203 records
204 .iter()
205 .filter(|r| r.file_type == FileType::Documentation)
206 .collect()
207 })
208 .unwrap_or_else(Vec::new)
209 }
210
211 pub fn package_count(&self) -> usize {
213 self.entries.len()
214 }
215}
216
217#[cfg(feature = "alloc")]
218impl Default for FileManifest {
219 fn default() -> Self {
220 Self::new()
221 }
222}
223
224#[cfg(feature = "alloc")]
229pub fn fnv1a_hash(data: &[u8]) -> u64 {
230 const FNV_OFFSET_BASIS: u64 = 0xcbf2_9ce4_8422_2325;
231 const FNV_PRIME: u64 = 0x0100_0000_01b3;
232
233 let mut hash = FNV_OFFSET_BASIS;
234 for &byte in data {
235 hash ^= byte as u64;
236 hash = hash.wrapping_mul(FNV_PRIME);
237 }
238 hash
239}