os/fs/
simple_fs.rs

1//! SimpleFS - 简单测试文件系统
2//!
3//! 该模块提供了一个**轻量级的只读文件系统**,用于测试和调试。镜像在编译时嵌入内核。
4//!
5//! # 设计概览
6//!
7//! ## 镜像格式
8//!
9//! ```text
10//! +------------------+
11//! | Header (512B)    |  Magic: "RAMDISK\0", File count
12//! +------------------+
13//! | File Entry 1     |  Header (32B) + Name + Data
14//! +------------------+
15//! | File Entry 2     |
16//! | ...              |
17//! +------------------+
18//! ```
19//!
20//! ## 加载流程
21//!
22//! 1. 编译时 `build.rs` 生成镜像并嵌入
23//! 2. 启动时从 `include_bytes!` 加载到 RamDisk
24//! 3. 解析镜像构建目录树
25//!
26//! # 组件
27//!
28//! - [`SimpleFs`] - 文件系统结构,实现 `FileSystem` trait
29//! - `SimpleFsInode` - 内部 Inode 实现
30//!
31//! # 使用示例
32//!
33//! ```rust
34//! use crate::fs::init_simple_fs;
35//!
36//! // 从编译时嵌入的镜像加载
37//! init_simple_fs()?;
38//!
39//! // 读取预加载的文件
40//! let hello = vfs_load_file("/bin/hello")?;
41//! ```
42//!
43//! # 特点
44//!
45//! - **只读**:运行时不可修改
46//! - **快速启动**:无需磁盘 I/O
47//! - **测试友好**:提供一致的测试环境
48//! - **自动路径创建**:支持多级路径(如 `bin/hello`)
49
50use crate::sync::SpinLock;
51use crate::vfs::*;
52use crate::{device::block::BlockDriver, uapi::time::TimeSpec};
53use alloc::collections::BTreeMap;
54use alloc::string::String;
55use alloc::sync::Arc;
56use alloc::vec;
57use alloc::vec::Vec;
58use core::sync::atomic::{AtomicU64, Ordering};
59
60/// 简单的内存文件系统(用于测试)
61pub struct SimpleFs {
62    device: Option<Arc<dyn BlockDriver>>, // 可选的块设备
63    root: Arc<SimpleFsInode>,
64}
65
66impl SimpleFs {
67    /// 创建新的简单文件系统
68    pub fn new() -> Arc<Self> {
69        let root = Arc::new(SimpleFsInode::new_dir(
70            1,
71            FileMode::S_IRUSR
72                | FileMode::S_IWUSR
73                | FileMode::S_IXUSR
74                | FileMode::S_IRGRP
75                | FileMode::S_IXGRP
76                | FileMode::S_IROTH
77                | FileMode::S_IXOTH,
78        ));
79        Arc::new(Self { device: None, root })
80    }
81}
82
83impl FileSystem for SimpleFs {
84    fn fs_type(&self) -> &'static str {
85        "simplefs"
86    }
87
88    fn root_inode(&self) -> Arc<dyn Inode> {
89        self.root.clone() as Arc<dyn Inode>
90    }
91
92    fn sync(&self) -> Result<(), FsError> {
93        Ok(()) // 内存文件系统无需同步
94    }
95
96    fn statfs(&self) -> Result<StatFs, FsError> {
97        Ok(StatFs {
98            block_size: 4096,
99            total_blocks: 0,
100            free_blocks: 0,
101            available_blocks: 0,
102            total_inodes: 0,
103            free_inodes: 0,
104            fsid: 0,
105            max_filename_len: 255,
106        })
107    }
108}
109
110impl SimpleFs {
111    /// 从块设备和镜像创建 SimpleFS
112    pub fn from_ramdisk(device: Arc<dyn BlockDriver>) -> Result<Self, FsError> {
113        // 1. 读取镜像头,验证魔数
114        let block_size = device.block_size();
115        let mut header_block = vec![0u8; block_size];
116        if !device.read_block(0, &mut header_block) {
117            return Err(FsError::IoError);
118        }
119
120        if &header_block[0..8] != b"RAMDISK\0" {
121            return Err(FsError::IoError);
122        }
123
124        let file_count = u32::from_le_bytes(header_block[8..12].try_into().unwrap());
125
126        // 2. 创建根目录 inode (0o755 = rwxr-xr-x)
127        let root = Arc::new(SimpleFsInode::new_dir(
128            1,
129            FileMode::S_IRUSR
130                | FileMode::S_IWUSR
131                | FileMode::S_IXUSR
132                | FileMode::S_IRGRP
133                | FileMode::S_IXGRP
134                | FileMode::S_IROTH
135                | FileMode::S_IXOTH,
136        ));
137
138        // 3. 解析镜像,填充文件树
139        let mut offset = 16;
140        for _ in 0..file_count {
141            offset = Self::parse_file_entry(device.clone(), offset, root.clone())?;
142        }
143
144        Ok(Self {
145            device: Some(device),
146            root,
147        })
148    }
149
150    /// 解析镜像中的单个文件条目并添加到父目录
151    fn parse_file_entry(
152        device: Arc<dyn BlockDriver>,
153        offset: usize,
154        parent: Arc<SimpleFsInode>,
155    ) -> Result<usize, FsError> {
156        // 读取文件头 (32字节)
157        let mut header_buf = vec![0u8; 32];
158        Self::read_at_offset(device.clone(), offset, &mut header_buf)?;
159
160        let magic = u32::from_le_bytes(header_buf[0..4].try_into().unwrap());
161        if magic != 0x46494C45 {
162            return Err(FsError::IoError);
163        }
164
165        let name_len = u32::from_le_bytes(header_buf[4..8].try_into().unwrap()) as usize;
166        let data_len = u32::from_le_bytes(header_buf[8..12].try_into().unwrap()) as usize;
167        let file_type = u32::from_le_bytes(header_buf[12..16].try_into().unwrap());
168        let mode = u32::from_le_bytes(header_buf[16..20].try_into().unwrap());
169
170        let mut cur_offset = offset + 32;
171
172        // 读取文件名
173        let name_aligned = (name_len + 3) / 4 * 4;
174        let mut name_buf = vec![0u8; name_aligned];
175        Self::read_at_offset(device.clone(), cur_offset, &mut name_buf)?;
176        let name = String::from(String::from_utf8_lossy(&name_buf[..name_len]));
177        cur_offset += name_aligned;
178
179        // 读取文件数据
180        let data_aligned = (data_len + 511) / 512 * 512;
181        let mut data_buf = vec![0u8; data_len];
182        if data_len > 0 {
183            Self::read_at_offset(device.clone(), cur_offset, &mut data_buf)?;
184        }
185        cur_offset += data_aligned;
186
187        // 创建 inode 并添加到父目录
188        let inode = if file_type == 0 {
189            // 文件 (mode as u16 转换为 FileMode)
190            let file_mode = FileMode::from_bits_truncate(mode);
191            let inode = SimpleFsInode::new_file(parent.next_inode_no(), file_mode);
192            inode.data.lock().extend_from_slice(&data_buf);
193            Arc::new(inode)
194        } else {
195            // 目录
196            let dir_mode = FileMode::from_bits_truncate(mode);
197            Arc::new(SimpleFsInode::new_dir(parent.next_inode_no(), dir_mode))
198        };
199
200        // 处理多级路径 (如 "bin/hello")
201        Self::insert_inode_by_path(&name, inode, parent)?;
202
203        Ok(cur_offset)
204    }
205
206    /// 从设备的任意偏移位置读取数据(支持跨块读取)
207    fn read_at_offset(
208        device: Arc<dyn BlockDriver>,
209        offset: usize,
210        buf: &mut [u8],
211    ) -> Result<(), FsError> {
212        let block_size = device.block_size();
213        let mut buf_offset = 0;
214
215        while buf_offset < buf.len() {
216            // 计算当前应该读取的块号和块内偏移
217            let current_offset = offset + buf_offset;
218            let block_num = current_offset / block_size;
219            let block_offset = current_offset % block_size;
220
221            let mut block_buf = vec![0u8; block_size];
222            if !device.read_block(block_num, &mut block_buf) {
223                return Err(FsError::IoError);
224            }
225
226            // 计算本次要复制的字节数
227            let copy_len = (block_size - block_offset).min(buf.len() - buf_offset);
228
229            buf[buf_offset..buf_offset + copy_len]
230                .copy_from_slice(&block_buf[block_offset..block_offset + copy_len]);
231
232            buf_offset += copy_len;
233        }
234
235        Ok(())
236    }
237
238    /// 按路径插入 inode,自动创建不存在的中间目录
239    fn insert_inode_by_path(
240        path: &str,
241        inode: Arc<SimpleFsInode>,
242        root: Arc<SimpleFsInode>,
243    ) -> Result<(), FsError> {
244        let parts: Vec<&str> = path.split('/').filter(|s| !s.is_empty()).collect();
245
246        if parts.is_empty() {
247            return Err(FsError::InvalidArgument);
248        }
249
250        let mut current = root;
251
252        // 遍历到倒数第二级,确保父目录存在
253        for part in &parts[..parts.len() - 1] {
254            let child = {
255                let children = current.children.lock();
256                children.get(*part).cloned()
257            };
258
259            if let Some(child) = child {
260                current = child;
261            } else {
262                // 创建中间目录 (0o755 = rwxr-xr-x)
263                let new_dir = Arc::new(SimpleFsInode::new_dir(
264                    current.next_inode_no(),
265                    FileMode::S_IRUSR
266                        | FileMode::S_IWUSR
267                        | FileMode::S_IXUSR
268                        | FileMode::S_IRGRP
269                        | FileMode::S_IXGRP
270                        | FileMode::S_IROTH
271                        | FileMode::S_IXOTH,
272                ));
273                current
274                    .children
275                    .lock()
276                    .insert(String::from(*part), new_dir.clone());
277                current = new_dir;
278            }
279        }
280
281        // 插入最终的文件/目录
282        let final_name = parts[parts.len() - 1];
283        current
284            .children
285            .lock()
286            .insert(String::from(final_name), inode);
287
288        Ok(())
289    }
290}
291
292/// 简单文件系统的 Inode
293struct SimpleFsInode {
294    inode_no: usize,
295    inode_type: InodeType,
296    mode: FileMode,
297    data: SpinLock<Vec<u8>>,
298    children: SpinLock<BTreeMap<String, Arc<SimpleFsInode>>>,
299}
300
301impl SimpleFsInode {
302    /// 创建文件 inode(带权限)
303    fn new_file(inode_no: u64, mode: FileMode) -> Self {
304        let file_mode = FileMode::S_IFREG | mode;
305
306        Self {
307            inode_no: inode_no as usize,
308            inode_type: InodeType::File,
309            mode: file_mode,
310            data: SpinLock::new(Vec::new()),
311            children: SpinLock::new(BTreeMap::new()),
312        }
313    }
314
315    /// 创建目录 inode(带权限)
316    fn new_dir(inode_no: u64, mode: FileMode) -> Self {
317        let dir_mode = FileMode::S_IFDIR | mode;
318
319        Self {
320            inode_no: inode_no as usize,
321            inode_type: InodeType::Directory,
322            mode: dir_mode,
323            data: SpinLock::new(Vec::new()),
324            children: SpinLock::new(BTreeMap::new()),
325        }
326    }
327
328    /// 获取下一个 inode 编号
329    fn next_inode_no(&self) -> u64 {
330        static NEXT_INODE: AtomicU64 = AtomicU64::new(2);
331        NEXT_INODE.fetch_add(1, Ordering::Relaxed)
332    }
333}
334
335impl Inode for SimpleFsInode {
336    fn metadata(&self) -> Result<InodeMetadata, FsError> {
337        let data = self.data.lock();
338        Ok(InodeMetadata {
339            inode_no: self.inode_no,
340            inode_type: self.inode_type,
341            mode: self.mode.clone(),
342            uid: 0,
343            gid: 0,
344            size: data.len(),
345            atime: TimeSpec::now(),
346            mtime: TimeSpec::now(),
347            ctime: TimeSpec::now(),
348            nlinks: 1,
349            blocks: (data.len() + 511) / 512,
350            rdev: 0,
351        })
352    }
353
354    fn read_at(&self, offset: usize, buf: &mut [u8]) -> Result<usize, FsError> {
355        if self.inode_type == InodeType::Directory {
356            return Err(FsError::IsDirectory);
357        }
358
359        let data = self.data.lock();
360        if offset >= data.len() {
361            return Ok(0);
362        }
363        let len = core::cmp::min(buf.len(), data.len() - offset);
364
365        buf[..len].copy_from_slice(&data[offset..offset + len]);
366        Ok(len)
367    }
368
369    fn write_at(&self, offset: usize, buf: &[u8]) -> Result<usize, FsError> {
370        if self.inode_type == InodeType::Directory {
371            return Err(FsError::IsDirectory);
372        }
373
374        let mut data = self.data.lock();
375        if offset + buf.len() > data.len() {
376            data.resize(offset + buf.len(), 0);
377        }
378        data[offset..offset + buf.len()].copy_from_slice(buf);
379        Ok(buf.len())
380    }
381
382    fn lookup(&self, name: &str) -> Result<Arc<dyn Inode>, FsError> {
383        if self.inode_type != InodeType::Directory {
384            return Err(FsError::NotDirectory);
385        }
386        self.children
387            .lock()
388            .get(name)
389            .cloned()
390            .ok_or(FsError::NotFound)
391            .map(|inode| inode as Arc<dyn Inode>)
392    }
393
394    fn create(&self, name: &str, mode: FileMode) -> Result<Arc<dyn Inode>, FsError> {
395        if self.inode_type != InodeType::Directory {
396            return Err(FsError::NotDirectory);
397        }
398
399        let mut children = self.children.lock();
400        if children.contains_key(name) {
401            return Err(FsError::AlreadyExists);
402        }
403
404        let new_inode = Arc::new(SimpleFsInode::new_file((children.len() + 2) as u64, mode));
405        children.insert(String::from(name), new_inode.clone());
406
407        Ok(new_inode as Arc<dyn Inode>)
408    }
409
410    fn mkdir(&self, name: &str, mode: FileMode) -> Result<Arc<dyn Inode>, FsError> {
411        if self.inode_type != InodeType::Directory {
412            return Err(FsError::NotDirectory);
413        }
414
415        let mut children = self.children.lock();
416        if children.contains_key(name) {
417            return Err(FsError::AlreadyExists);
418        }
419
420        let new_inode = Arc::new(SimpleFsInode::new_dir((children.len() + 2) as u64, mode));
421        children.insert(String::from(name), new_inode.clone());
422
423        Ok(new_inode as Arc<dyn Inode>)
424    }
425
426    fn unlink(&self, name: &str) -> Result<(), FsError> {
427        if self.inode_type != InodeType::Directory {
428            return Err(FsError::NotDirectory);
429        }
430
431        let mut children = self.children.lock();
432        children.remove(name).ok_or(FsError::NotFound)?;
433        Ok(())
434    }
435
436    fn readdir(&self) -> Result<Vec<DirEntry>, FsError> {
437        if self.inode_type != InodeType::Directory {
438            return Err(FsError::NotDirectory);
439        }
440
441        let children = self.children.lock();
442        let mut entries = Vec::new();
443
444        for (name, child) in children.iter() {
445            entries.push(DirEntry {
446                name: name.clone(),
447                inode_no: child.inode_no,
448                inode_type: child.inode_type,
449            });
450        }
451
452        Ok(entries)
453    }
454
455    fn truncate(&self, size: usize) -> Result<(), FsError> {
456        let mut data = self.data.lock();
457        data.resize(size, 0);
458        Ok(())
459    }
460
461    fn sync(&self) -> Result<(), FsError> {
462        Ok(())
463    }
464
465    fn as_any(&self) -> &dyn core::any::Any {
466        self as &dyn core::any::Any
467    }
468
469    fn symlink(&self, _name: &str, _target: &str) -> Result<Arc<dyn Inode>, FsError> {
470        Err(FsError::NotSupported)
471    }
472
473    fn link(&self, _name: &str, _target: &Arc<dyn Inode>) -> Result<(), FsError> {
474        Err(FsError::NotSupported)
475    }
476
477    fn rmdir(&self, _name: &str) -> Result<(), FsError> {
478        Err(FsError::NotSupported)
479    }
480
481    fn rename(
482        &self,
483        _old_name: &str,
484        _new_parent: Arc<dyn Inode>,
485        _new_name: &str,
486    ) -> Result<(), FsError> {
487        Err(FsError::NotSupported)
488    }
489
490    fn set_times(&self, _atime: Option<TimeSpec>, _mtime: Option<TimeSpec>) -> Result<(), FsError> {
491        Err(FsError::NotSupported)
492    }
493
494    fn readlink(&self) -> Result<String, FsError> {
495        Err(FsError::NotSupported)
496    }
497
498    fn mknod(&self, _name: &str, _mode: FileMode, _dev: u64) -> Result<Arc<dyn Inode>, FsError> {
499        Err(FsError::NotSupported)
500    }
501
502    fn chmod(&self, _mode: FileMode) -> Result<(), FsError> {
503        Err(FsError::NotSupported)
504    }
505
506    fn chown(&self, _uid: u32, _gid: u32) -> Result<(), FsError> {
507        Err(FsError::NotSupported)
508    }
509}