Skip to main content

proka_kernel/fs/
vfs.rs

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    /// 文件或目录不存在
22    NotFound,
23    /// 文件或目录已存在
24    AlreadyExists,
25    /// 路径不是目录
26    NotADirectory,
27    /// 路径不是文件
28    NotAFile,
29    /// 权限不足
30    PermissionDenied,
31    /// 设备错误
32    DeviceError(DeviceError),
33    /// 无效的参数
34    InvalidArgument,
35    /// IO 错误
36    IoError,
37    /// 符号链接深度过深
38    MaxSymlinkDepth,
39    /// 文件系统类型不支持
40    FsTypeNotSupported,
41    /// 路径为空
42    EmptyPath,
43    /// 功能未实现
44    NotImplemented,
45    /// 目录非空
46    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    /// 文件
58    File,
59    /// 目录
60    Dir,
61    /// 符号链接
62    SymLink,
63    /// 设备
64    Device,
65}
66
67/// 文件或目录的元数据
68#[derive(Debug, Clone, Eq, PartialEq, Default)]
69pub struct Metadata {
70    /// 文件大小
71    pub size: u64,
72    /// UNIX权限位,如0o755
73    pub permissions: u32,
74    /// 用户ID
75    pub uid: u32,
76    /// 组ID
77    pub gid: u32,
78    /// 创建时间 (秒)
79    pub ctime: u64,
80    /// 最后修改时间 (秒)
81    pub mtime: u64,
82    /// 占用的块数
83    pub blocks: u64,
84    /// 硬链接数量
85    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(&current_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}