1use crate::drivers::{Device, DeviceError, DEVICE_MANAGER};
2extern crate alloc;
3use super::fs_impl;
4use alloc::format;
5use alloc::{
6 collections::BTreeMap,
7 string::{String, ToString},
8 sync::Arc,
9 vec::Vec,
10};
11use core::any::Any;
12use lazy_static::lazy_static;
13use spin::{Mutex, RwLock};
14
15lazy_static! {
16 pub static ref VFS: Vfs = Vfs::new();
17}
18
19#[derive(Debug, PartialEq, Eq, Clone, Copy)]
20pub enum VfsError {
21 NotFound,
23 AlreadyExists,
25 NotADirectory,
27 NotAFile,
29 PermissionDenied,
31 DeviceError(DeviceError),
33 InvalidArgument,
35 IoError,
37 MaxSymlinkDepth,
39 FsTypeNotSupported,
41 EmptyPath,
43 NotImplemented,
45 DirectoryNotEmpty,
47}
48
49impl From<DeviceError> for VfsError {
50 fn from(e: DeviceError) -> Self {
51 VfsError::DeviceError(e)
52 }
53}
54
55#[derive(Debug, Clone, Copy, PartialEq, Eq)]
56pub enum VNodeType {
57 File,
59 Dir,
61 SymLink,
63 Device,
65}
66
67#[derive(Debug, Clone, Eq, PartialEq, Default)]
69pub struct Metadata {
70 pub size: u64,
72 pub permissions: u32,
74 pub uid: u32,
76 pub gid: u32,
78 pub ctime: u64,
80 pub mtime: u64,
82 pub blocks: u64,
84 pub nlinks: u64,
86}
87
88pub trait FileSystem: Send + Sync {
89 fn mount(
90 &self,
91 device: Option<Arc<Device>>,
92 args: Option<&[&str]>,
93 ) -> Result<Arc<dyn Inode>, VfsError>;
94 fn fs_type(&self) -> &'static str;
95}
96
97pub trait Inode: Send + Sync + core::fmt::Debug {
98 fn metadata(&self) -> Result<Metadata, VfsError>;
99 fn set_metadata(&self, metadata: &Metadata) -> Result<(), VfsError>;
100 fn node_type(&self) -> VNodeType;
101 fn read_at(&self, offset: u64, buf: &mut [u8]) -> Result<usize, VfsError>;
102 fn write_at(&self, offset: u64, buf: &[u8]) -> Result<usize, VfsError>;
103 fn truncate(&self, size: u64) -> Result<(), VfsError>;
104 fn sync(&self) -> Result<(), VfsError>;
105 fn lookup(&self, name: &str) -> Result<Arc<dyn Inode>, VfsError>;
106 fn create(&self, name: &str, typ: VNodeType) -> Result<Arc<dyn Inode>, VfsError>;
107
108 fn create_symlink(&self, name: &str, target: &str) -> Result<Arc<dyn Inode>, VfsError> {
109 let _ = (name, target);
110 Err(VfsError::NotImplemented)
111 }
112
113 fn create_device(&self, name: &str, device: Arc<Device>) -> Result<Arc<dyn Inode>, VfsError> {
114 let _ = (name, device);
115 Err(VfsError::NotImplemented)
116 }
117
118 fn unlink(&self, name: &str) -> Result<(), VfsError>;
119
120 fn rename(&self, old_name: &str, new_name: &str) -> Result<(), VfsError> {
121 let _ = (old_name, new_name);
122 Err(VfsError::NotImplemented)
123 }
124
125 fn list(&self) -> Result<Vec<String>, VfsError> {
126 Ok(Vec::new())
127 }
128
129 fn read_symlink(&self) -> Result<String, VfsError> {
130 Err(VfsError::NotAFile)
131 }
132
133 fn as_any(&self) -> &dyn Any;
134}
135
136pub struct File {
137 inode: Arc<dyn Inode>,
138 offset: Mutex<u64>,
139}
140
141impl File {
142 pub fn new(inode: Arc<dyn Inode>) -> Self {
143 Self {
144 inode,
145 offset: Mutex::new(0),
146 }
147 }
148
149 pub fn read(&self, buf: &mut [u8]) -> Result<usize, VfsError> {
150 let mut offset = self.offset.lock();
151 let len = self.inode.read_at(*offset, buf)?;
152 *offset += len as u64;
153 Ok(len)
154 }
155
156 pub fn write(&self, buf: &[u8]) -> Result<usize, VfsError> {
157 let mut offset = self.offset.lock();
158 let len = self.inode.write_at(*offset, buf)?;
159 *offset += len as u64;
160 Ok(len)
161 }
162
163 pub fn seek(&self, pos: u64) -> Result<u64, VfsError> {
164 let mut offset = self.offset.lock();
165 *offset = pos;
166 Ok(*offset)
167 }
168
169 pub fn metadata(&self) -> Result<Metadata, VfsError> {
170 self.inode.metadata()
171 }
172
173 pub fn truncate(&self, size: u64) -> Result<(), VfsError> {
174 self.inode.truncate(size)
175 }
176
177 pub fn read_all(&self) -> Result<Vec<u8>, VfsError> {
178 let metadata = self.metadata()?;
179 let mut buf = alloc::vec![0; metadata.size as usize];
180 self.inode.read_at(0, &mut buf)?;
181 Ok(buf)
182 }
183 pub fn write_all(&self, data: &[u8]) -> Result<(), VfsError> {
184 self.inode.write_at(0, data)?;
185 Ok(())
186 }
187}
188
189struct MountPoint {
190 path: String,
191 mount_point_len: usize,
192 root: Arc<dyn Inode>,
193}
194
195pub struct Vfs {
196 root: RwLock<Option<Arc<dyn Inode>>>,
197 mounts: Mutex<Vec<MountPoint>>,
198 fs_registry: RwLock<BTreeMap<&'static str, Arc<dyn FileSystem>>>,
199}
200
201pub type WalkEntry = (String, Vec<String>, Vec<String>);
202
203impl Default for Vfs {
204 fn default() -> Self {
205 let mut registry: BTreeMap<&'static str, Arc<dyn FileSystem>> = BTreeMap::new();
206 let kernfs = Arc::new(fs_impl::kernfs::KernFs::new());
207 registry.insert("kernfs", kernfs.clone());
208 registry.insert("memfs", Arc::new(fs_impl::memfs::MemFs));
209
210 let mounts = alloc::vec![MountPoint {
211 path: "kernel".to_string(),
212 mount_point_len: 6,
213 root: kernfs.root(),
214 }];
215
216 Self {
217 root: RwLock::new(None),
218 mounts: Mutex::new(mounts),
219 fs_registry: RwLock::new(registry),
220 }
221 }
222}
223
224impl Vfs {
225 pub fn new() -> Self {
226 Self::default()
227 }
228
229 pub fn init_root(&self, root: Arc<dyn Inode>) {
230 *self.root.write() = Some(root);
231 }
232
233 pub fn register_fs(&self, fs: Arc<dyn FileSystem>) {
234 self.fs_registry.write().insert(fs.fs_type(), fs);
235 }
236
237 pub fn mount(
238 &self,
239 device_str: Option<&str>,
240 mount_point: &str,
241 fs_type: &str,
242 args: Option<&[&str]>,
243 ) -> Result<(), VfsError> {
244 let fs = self
245 .fs_registry
246 .read()
247 .get(fs_type)
248 .cloned()
249 .ok_or(VfsError::FsTypeNotSupported)?;
250
251 let device_manager = DEVICE_MANAGER.read();
252 let device = if let Some(dev) = device_str {
253 device_manager.get_device(dev)
254 } else {
255 None
256 };
257
258 let root_inode = fs.mount(device, args)?;
259
260 let parent_path = if mount_point == "/" {
261 None
262 } else {
263 mount_point.rsplit_once('/').map(|(p, _)| p)
264 };
265 if let Some(parent_path_str) = parent_path {
266 let parent_inode = self.lookup(parent_path_str)?;
267 if parent_inode.node_type() != VNodeType::Dir {
268 return Err(VfsError::NotADirectory);
269 }
270 }
271
272 let normalized_mount_point = mount_point.trim_matches('/').to_string();
273 if normalized_mount_point.is_empty() {
274 return Err(VfsError::InvalidArgument);
275 }
276
277 self.mounts.lock().push(MountPoint {
278 path: normalized_mount_point.clone(),
279 mount_point_len: normalized_mount_point.len(),
280 root: root_inode,
281 });
282
283 Ok(())
284 }
285
286 pub fn lookup(&self, path: &str) -> Result<Arc<dyn Inode>, VfsError> {
287 self.path_to_inode(path, 0)
288 }
289
290 pub fn open(&self, path: &str) -> Result<Arc<File>, VfsError> {
291 let inode = self.lookup(path)?;
292 if inode.node_type() != VNodeType::File && inode.node_type() != VNodeType::Device {
293 return Err(VfsError::NotAFile);
294 }
295 Ok(Arc::new(File::new(inode)))
296 }
297
298 pub fn create_file(&self, path: &str) -> Result<Arc<dyn Inode>, VfsError> {
299 let (parent_path, name) = self.split_path(path)?;
300 let parent_inode = self.lookup(parent_path)?;
301 if parent_inode.node_type() != VNodeType::Dir {
302 return Err(VfsError::NotADirectory);
303 }
304 parent_inode.create(name, VNodeType::File)
305 }
306
307 pub fn create_dir(&self, path: &str) -> Result<Arc<dyn Inode>, VfsError> {
308 let (parent_path, name) = self.split_path(path)?;
309 let parent_inode = self.lookup(parent_path)?;
310 if parent_inode.node_type() != VNodeType::Dir {
311 return Err(VfsError::NotADirectory);
312 }
313 parent_inode.create(name, VNodeType::Dir)
314 }
315
316 pub fn create_symlink(
317 &self,
318 target_path: &str,
319 link_path: &str,
320 ) -> Result<Arc<dyn Inode>, VfsError> {
321 let (parent_path, name) = self.split_path(link_path)?;
322 let parent_inode = self.lookup(parent_path)?;
323 if parent_inode.node_type() != VNodeType::Dir {
324 return Err(VfsError::NotADirectory);
325 }
326 parent_inode.create_symlink(name, target_path)
327 }
328
329 pub fn create_device_node(
330 &self,
331 path: &str,
332 major: u16,
333 minor: u16,
334 device_type: crate::drivers::DeviceType,
335 ) -> Result<Arc<dyn Inode>, VfsError> {
336 let (parent_path, name) = self.split_path(path)?;
337 let parent_inode = self.lookup(parent_path)?;
338 if parent_inode.node_type() != VNodeType::Dir {
339 return Err(VfsError::NotADirectory);
340 }
341
342 let device_manager = DEVICE_MANAGER.read();
343 let device = device_manager
344 .get_device_by_major_minor(major, minor)
345 .ok_or(VfsError::DeviceError(
346 crate::drivers::DeviceError::NoSuchDevice,
347 ))?;
348
349 if device.device_type() != device_type {
350 return Err(VfsError::DeviceError(
351 crate::drivers::DeviceError::InvalidParam,
352 ));
353 }
354
355 parent_inode.create_device(name, device)
356 }
357
358 pub fn remove(&self, path: &str) -> Result<(), VfsError> {
359 let (parent_path, name) = self.split_path(path)?;
360 let parent_inode = self.lookup(parent_path)?;
361 if parent_inode.node_type() != VNodeType::Dir {
362 return Err(VfsError::NotADirectory);
363 }
364 parent_inode.unlink(name)
365 }
366
367 pub fn read_dir(&self, path: &str) -> Result<Vec<String>, VfsError> {
368 let inode = self.lookup(path)?;
369 if inode.node_type() != VNodeType::Dir {
370 return Err(VfsError::NotADirectory);
371 }
372 inode.list()
373 }
374
375 pub fn rename(&self, old_path: &str, new_path: &str) -> Result<(), VfsError> {
376 let (old_parent_path, old_name) = self.split_path(old_path)?;
377 let old_parent = self.lookup(old_parent_path)?;
378
379 let (new_parent_path, new_name) = self.split_path(new_path)?;
380 let _new_parent = self.lookup(new_parent_path)?;
381
382 if old_parent_path == new_parent_path {
383 old_parent.rename(old_name, new_name)
384 } else {
385 Err(VfsError::NotImplemented)
386 }
387 }
388
389 const MAX_SYMLINK_DEPTH: u32 = 8;
390
391 fn path_to_inode(&self, path: &str, depth: u32) -> Result<Arc<dyn Inode>, VfsError> {
392 if depth > Self::MAX_SYMLINK_DEPTH {
393 return Err(VfsError::MaxSymlinkDepth);
394 }
395
396 let normalized_path = self.normalize_path(path);
397 let path = normalized_path.trim_matches('/');
398
399 if path.is_empty() {
400 return self.root.read().as_ref().cloned().ok_or(VfsError::NotFound);
401 }
402
403 let mounts = self.mounts.lock();
404 if let Some(mount) = mounts
405 .iter()
406 .filter(|m| path.starts_with(&m.path))
407 .max_by_key(|m| m.mount_point_len)
408 {
409 let subpath = path[mount.mount_point_len..].trim_matches('/');
410 if subpath.is_empty() {
411 return self.resolve_symlink_if_needed(mount.root.clone(), depth);
412 }
413 let mut current = mount.root.clone();
414 for component in subpath.split('/') {
415 if component.is_empty() || component == "." {
416 continue;
417 }
418 current = self.resolve_symlink_if_needed(current.lookup(component)?, depth)?;
419 }
420 return Ok(current);
421 }
422
423 let mut current = self
424 .root
425 .read()
426 .as_ref()
427 .cloned()
428 .ok_or(VfsError::NotFound)?;
429 for component in path.split('/') {
430 if component.is_empty() || component == "." {
431 continue;
432 }
433 current = self.resolve_symlink_if_needed(current.lookup(component)?, depth)?;
434 }
435 Ok(current)
436 }
437
438 fn resolve_symlink_if_needed(
439 &self,
440 node: Arc<dyn Inode>,
441 depth: u32,
442 ) -> Result<Arc<dyn Inode>, VfsError> {
443 if node.node_type() == VNodeType::SymLink {
444 let target_path = node.read_symlink()?;
445 self.path_to_inode(&target_path, depth + 1)
446 } else {
447 Ok(node)
448 }
449 }
450
451 fn split_path<'a>(&self, path: &'a str) -> Result<(&'a str, &'a str), VfsError> {
452 let path = path.trim_matches('/');
453 if path.is_empty() {
454 return Err(VfsError::EmptyPath);
455 }
456 if let Some((parent, name)) = path.rsplit_once('/') {
457 Ok(((if parent.is_empty() { "/" } else { parent }), name))
458 } else {
459 Ok(("/", path))
460 }
461 }
462
463 pub fn walk(&self, start_path: &str) -> Result<Vec<WalkEntry>, VfsError> {
464 let mut results = Vec::new();
465 let mut stack: Vec<String> = Vec::new();
466 let normalized_start_path = self.normalize_path(start_path);
467 stack.push(normalized_start_path);
468 while let Some(current_dir_path) = stack.pop() {
469 let current_inode = self.lookup(¤t_dir_path)?;
470 if current_inode.node_type() != VNodeType::Dir {
471 continue;
472 }
473 let entries = current_inode.list()?;
474 let mut dirnames: Vec<String> = Vec::new();
475 let mut filenames: Vec<String> = Vec::new();
476 let mut subdirs_to_visit: Vec<String> = Vec::new();
477
478 for entry_name in entries {
479 let entry_path = if current_dir_path == "/" {
480 format!("/{}", entry_name)
481 } else {
482 format!("{}/{}", current_dir_path, entry_name)
483 };
484
485 let entry_inode = match self.lookup(&entry_path) {
486 Ok(node) => node,
487 Err(_) => continue,
488 };
489
490 match entry_inode.node_type() {
491 VNodeType::Dir => {
492 dirnames.push(entry_name.clone());
493 subdirs_to_visit.push(entry_path);
494 }
495 _ => {
496 filenames.push(entry_name.clone());
497 }
498 }
499 }
500 results.push((current_dir_path.clone(), dirnames, filenames));
501 subdirs_to_visit.sort_unstable_by(|a, b| b.cmp(a));
502 for subdir_path in subdirs_to_visit {
503 stack.push(subdir_path);
504 }
505 }
506 Ok(results)
507 }
508
509 fn normalize_path(&self, path: &str) -> String {
510 let parts: Vec<&str> = path
511 .split('/')
512 .filter(|&s| !s.is_empty() && s != ".")
513 .collect();
514 let mut cleaned_parts = Vec::new();
515 for part in parts.iter() {
516 if *part == ".." {
517 if let Some(last) = cleaned_parts.last_mut() {
518 if last != &"" {
519 cleaned_parts.pop();
520 }
521 }
522 } else {
523 cleaned_parts.push(*part);
524 }
525 }
526 if cleaned_parts.is_empty() {
527 "/".to_string()
528 } else {
529 format!("/{}", cleaned_parts.join("/"))
530 }
531 }
532}