xref: /DragonOS/kernel/src/filesystem/vfs/core.rs (revision 45b8371173b070028457f7ee64be33f68b4f9ada)
1 use core::{
2     hint::spin_loop,
3     ptr::null_mut,
4     sync::atomic::{AtomicUsize, Ordering},
5 };
6 
7 use alloc::{boxed::Box, format, string::ToString, sync::Arc};
8 
9 use crate::{
10     arch::asm::current::current_pcb,
11     driver::disk::ahci::{self},
12     filesystem::{
13         devfs::DevFS,
14         fat::fs::FATFileSystem,
15         procfs::ProcFS,
16         ramfs::RamFS,
17         vfs::{file::File, mount::MountFS, FileSystem, FileType},
18     },
19     include::bindings::bindings::{EBADF, ENAMETOOLONG, ENOENT, ENOTDIR, EPERM, PAGE_4K_SIZE},
20     io::SeekFrom,
21     kerror, kinfo,
22 };
23 
24 use super::{file::FileMode, utils::rsplit_path, IndexNode, InodeId};
25 
26 /// @brief 原子地生成新的Inode号。
27 /// 请注意,所有的inode号都需要通过该函数来生成.全局的inode号,除了以下两个特殊的以外,都是唯一的
28 /// 特殊的两个inode号:
29 /// [0]: 对应'.'目录项
30 /// [1]: 对应'..'目录项
31 pub fn generate_inode_id() -> InodeId {
32     static INO: AtomicUsize = AtomicUsize::new(1);
33     return INO.fetch_add(1, Ordering::SeqCst);
34 }
35 
36 static mut __ROOT_INODE: *mut Arc<dyn IndexNode> = null_mut();
37 
38 /// @brief 获取全局的根节点
39 #[inline(always)]
40 #[allow(non_snake_case)]
41 pub fn ROOT_INODE() -> Arc<dyn IndexNode> {
42     unsafe {
43         return __ROOT_INODE.as_ref().unwrap().clone();
44     }
45 }
46 
47 #[no_mangle]
48 pub extern "C" fn vfs_init() -> i32 {
49     // 使用Ramfs作为默认的根文件系统
50     let ramfs = RamFS::new();
51     let mount_fs = MountFS::new(ramfs, None);
52     let root_inode = Box::leak(Box::new(mount_fs.root_inode()));
53 
54     unsafe {
55         __ROOT_INODE = root_inode;
56     }
57 
58     // 创建文件夹
59     root_inode
60         .create("proc", FileType::Dir, 0o777)
61         .expect("Failed to create /proc");
62     root_inode
63         .create("dev", FileType::Dir, 0o777)
64         .expect("Failed to create /dev");
65 
66     // // 创建procfs实例
67     let procfs: Arc<ProcFS> = ProcFS::new();
68 
69     // procfs挂载
70     let _t = root_inode
71         .find("proc")
72         .expect("Cannot find /proc")
73         .mount(procfs)
74         .expect("Failed to mount procfs.");
75     kinfo!("ProcFS mounted.");
76 
77     // 创建 devfs 实例
78     let devfs: Arc<DevFS> = DevFS::new();
79     // devfs 挂载
80     let _t = root_inode
81         .find("dev")
82         .expect("Cannot find /dev")
83         .mount(devfs)
84         .expect("Failed to mount devfs");
85     kinfo!("DevFS mounted.");
86 
87     let root_inode = ROOT_INODE().list().expect("VFS init failed");
88     if root_inode.len() > 0 {
89         kinfo!("Successfully initialized VFS!");
90     }
91     return 0;
92 }
93 
94 /// @brief 真正执行伪文件系统迁移的过程
95 ///
96 /// @param mountpoint_name 在根目录下的挂载点的名称
97 /// @param inode 原本的挂载点的inode
98 fn do_migrate(
99     new_root_inode: Arc<dyn IndexNode>,
100     mountpoint_name: &str,
101     fs: &MountFS,
102 ) -> Result<(), i32> {
103     let r = new_root_inode.find(mountpoint_name);
104     let mountpoint = if r.is_err() {
105         new_root_inode
106             .create(mountpoint_name, FileType::Dir, 0o777)
107             .expect(format!("Failed to create '/{mountpoint_name}'").as_str())
108     } else {
109         r.unwrap()
110     };
111     // 迁移挂载点
112     mountpoint
113         .mount(fs.inner_filesystem())
114         .expect(format!("Failed to migrate {mountpoint_name}").as_str());
115     return Ok(());
116 }
117 
118 /// @brief 迁移伪文件系统的inode
119 /// 请注意,为了避免删掉了伪文件系统内的信息,因此没有在原root inode那里调用unlink.
120 fn migrate_virtual_filesystem(new_fs: Arc<dyn FileSystem>) -> Result<(), i32> {
121     kinfo!("VFS: Migrating filesystems...");
122 
123     // ==== 在这里获取要被迁移的文件系统的inode ===
124     let binding = ROOT_INODE().find("proc").expect("ProcFS not mounted!").fs();
125     let proc: &MountFS = binding.as_any_ref().downcast_ref::<MountFS>().unwrap();
126     let binding = ROOT_INODE().find("dev").expect("DevFS not mounted!").fs();
127     let dev: &MountFS = binding.as_any_ref().downcast_ref::<MountFS>().unwrap();
128 
129     let new_fs = MountFS::new(new_fs, None);
130     // 获取新的根文件系统的根节点的引用
131     let new_root_inode = Box::leak(Box::new(new_fs.root_inode()));
132 
133     // 把上述文件系统,迁移到新的文件系统下
134     do_migrate(new_root_inode.clone(), "proc", proc)?;
135     do_migrate(new_root_inode.clone(), "dev", dev)?;
136 
137     unsafe {
138         // drop旧的Root inode
139         let old_root_inode: Box<Arc<dyn IndexNode>> = Box::from_raw(__ROOT_INODE);
140         __ROOT_INODE = null_mut();
141         drop(old_root_inode);
142 
143         // 设置全局的新的ROOT Inode
144         __ROOT_INODE = new_root_inode;
145     }
146 
147     kinfo!("VFS: Migrate filesystems done!");
148 
149     return Ok(());
150 }
151 
152 #[no_mangle]
153 pub extern "C" fn mount_root_fs() -> i32 {
154     kinfo!("Try to mount FAT32 as root fs...");
155     let partiton: Arc<crate::io::disk_info::Partition> =
156         ahci::get_disks_by_name("ahci_disk_0".to_string())
157             .unwrap()
158             .0
159             .lock()
160             .partitions[0]
161             .clone();
162 
163     let fatfs: Result<Arc<FATFileSystem>, i32> = FATFileSystem::new(partiton);
164     if fatfs.is_err() {
165         kerror!(
166             "Failed to initialize fatfs, code={:?}",
167             fatfs.as_ref().err()
168         );
169         loop {
170             spin_loop();
171         }
172     }
173     let fatfs: Arc<FATFileSystem> = fatfs.unwrap();
174     let r = migrate_virtual_filesystem(fatfs);
175     if r.is_err() {
176         kerror!("Failed to migrate virtual filesystem to FAT32!");
177         loop {
178             spin_loop();
179         }
180     }
181     kinfo!("Successfully migrate rootfs to FAT32!");
182 
183     return 0;
184 }
185 
186 /// @brief 为当前进程打开一个文件
187 pub fn do_open(path: &str, mode: FileMode) -> Result<i32, i32> {
188     // 文件名过长
189     if path.len() > PAGE_4K_SIZE as usize {
190         return Err(-(ENAMETOOLONG as i32));
191     }
192 
193     let inode: Result<Arc<dyn IndexNode>, i32> = ROOT_INODE().lookup(path);
194 
195     let inode: Arc<dyn IndexNode> = if inode.is_err() {
196         let errno = inode.unwrap_err();
197         // 文件不存在,且需要创建
198         if mode.contains(FileMode::O_CREAT)
199             && !mode.contains(FileMode::O_DIRECTORY)
200             && errno == -(ENOENT as i32)
201         {
202             let (filename, parent_path) = rsplit_path(path);
203             // 查找父目录
204             let parent_inode: Arc<dyn IndexNode> =
205                 ROOT_INODE().lookup(parent_path.unwrap_or("/"))?;
206             // 创建文件
207             let inode: Arc<dyn IndexNode> = parent_inode.create(filename, FileType::File, 0o777)?;
208             inode
209         } else {
210             // 不需要创建文件,因此返回错误码
211             return Err(errno);
212         }
213     } else {
214         inode.unwrap()
215     };
216 
217     let file_type: FileType = inode.metadata()?.file_type;
218     // 如果要打开的是文件夹,而目标不是文件夹
219     if mode.contains(FileMode::O_DIRECTORY) && file_type != FileType::Dir {
220         return Err(-(ENOTDIR as i32));
221     }
222 
223     // 如果O_TRUNC,并且,打开模式包含O_RDWR或O_WRONLY,清空文件
224     if mode.contains(FileMode::O_TRUNC)
225         && (mode.contains(FileMode::O_RDWR) || mode.contains(FileMode::O_WRONLY))
226         && file_type == FileType::File
227     {
228         inode.truncate(0)?;
229     }
230 
231     // 创建文件对象
232     let mut file: File = File::new(inode, mode)?;
233 
234     // 打开模式为“追加”
235     if mode.contains(FileMode::O_APPEND) {
236         file.lseek(SeekFrom::SeekEnd(0))?;
237     }
238 
239     // 把文件对象存入pcb
240     return current_pcb().alloc_fd(file);
241 }
242 
243 /// @brief 根据文件描述符,读取文件数据。尝试读取的数据长度与buf的长度相同。
244 ///
245 /// @param fd 文件描述符编号
246 /// @param buf 输出缓冲区。
247 ///
248 /// @return Ok(usize) 成功读取的数据的字节数
249 /// @return Err(i32) 读取失败,返回posix错误码
250 pub fn do_read(fd: i32, buf: &mut [u8]) -> Result<usize, i32> {
251     let file: Option<&mut File> = current_pcb().get_file_mut_by_fd(fd);
252     if file.is_none() {
253         return Err(-(EBADF as i32));
254     }
255     let file: &mut File = file.unwrap();
256 
257     return file.read(buf.len(), buf);
258 }
259 
260 /// @brief 根据文件描述符,向文件写入数据。尝试写入的数据长度与buf的长度相同。
261 ///
262 /// @param fd 文件描述符编号
263 /// @param buf 输入缓冲区。
264 ///
265 /// @return Ok(usize) 成功写入的数据的字节数
266 /// @return Err(i32) 写入失败,返回posix错误码
267 pub fn do_write(fd: i32, buf: &[u8]) -> Result<usize, i32> {
268     let file: Option<&mut File> = current_pcb().get_file_mut_by_fd(fd);
269     if file.is_none() {
270         return Err(-(EBADF as i32));
271     }
272     let file: &mut File = file.unwrap();
273 
274     return file.write(buf.len(), buf);
275 }
276 
277 /// @brief 调整文件操作指针的位置
278 ///
279 /// @param fd 文件描述符编号
280 /// @param seek 调整的方式
281 ///
282 /// @return Ok(usize) 调整后,文件访问指针相对于文件头部的偏移量
283 /// @return Err(i32) 调整失败,返回posix错误码
284 pub fn do_lseek(fd: i32, seek: SeekFrom) -> Result<usize, i32> {
285     let file: Option<&mut File> = current_pcb().get_file_mut_by_fd(fd);
286     if file.is_none() {
287         return Err(-(EBADF as i32));
288     }
289     let file: &mut File = file.unwrap();
290     return file.lseek(seek);
291 }
292 
293 /// @brief 创建文件/文件夹
294 pub fn do_mkdir(path: &str, _mode: FileMode) -> Result<u64, i32> {
295     // 文件名过长
296     if path.len() > PAGE_4K_SIZE as usize {
297         return Err(-(ENAMETOOLONG as i32));
298     }
299 
300     let inode: Result<Arc<dyn IndexNode>, i32> = ROOT_INODE().lookup(path);
301 
302     if inode.is_err() {
303         let errno = inode.unwrap_err();
304         // 文件不存在,且需要创建
305         if errno == -(ENOENT as i32) {
306             let (filename, parent_path) = rsplit_path(path);
307             // 查找父目录
308             let parent_inode: Arc<dyn IndexNode> =
309                 ROOT_INODE().lookup(parent_path.unwrap_or("/"))?;
310             // 创建文件夹
311             let _create_inode: Arc<dyn IndexNode> =
312                 parent_inode.create(filename, FileType::Dir, 0o777)?;
313         } else {
314             // 不需要创建文件,因此返回错误码
315             return Err(errno);
316         }
317     }
318 
319     return Ok(0);
320 }
321 
322 /// @breif 删除文件夹
323 pub fn do_remove_dir(path: &str) -> Result<u64, i32> {
324     // 文件名过长
325     if path.len() > PAGE_4K_SIZE as usize {
326         return Err(-(ENAMETOOLONG as i32));
327     }
328 
329     let inode: Result<Arc<dyn IndexNode>, i32> = ROOT_INODE().lookup(path);
330 
331     if inode.is_err() {
332         let errno = inode.unwrap_err();
333         // 文件不存在
334         if errno == -(ENOENT as i32) {
335             return Err(-(ENOENT as i32));
336         }
337     }
338 
339     let (filename, parent_path) = rsplit_path(path);
340     // 查找父目录
341     let parent_inode: Arc<dyn IndexNode> = ROOT_INODE().lookup(parent_path.unwrap_or("/"))?;
342 
343     if parent_inode.metadata()?.file_type != FileType::Dir {
344         return Err(-(ENOTDIR as i32));
345     }
346 
347     let target_inode: Arc<dyn IndexNode> = parent_inode.find(filename)?;
348     if target_inode.metadata()?.file_type != FileType::Dir {
349         return Err(-(ENOTDIR as i32));
350     }
351 
352     // 删除文件夹
353     parent_inode.rmdir(filename)?;
354 
355     return Ok(0);
356 }
357 
358 /// @brief 删除文件
359 pub fn do_unlink_at(path: &str, _mode: FileMode) -> Result<u64, i32> {
360     // 文件名过长
361     if path.len() > PAGE_4K_SIZE as usize {
362         return Err(-(ENAMETOOLONG as i32));
363     }
364 
365     let inode: Result<Arc<dyn IndexNode>, i32> = ROOT_INODE().lookup(path);
366 
367     if inode.is_err() {
368         let errno = inode.clone().unwrap_err();
369         // 文件不存在,且需要创建
370         if errno == -(ENOENT as i32) {
371             return Err(-(ENOENT as i32));
372         }
373     }
374     // 禁止在目录上unlink
375     if inode.unwrap().metadata()?.file_type == FileType::Dir {
376         return Err(-(EPERM as i32));
377     }
378 
379     let (filename, parent_path) = rsplit_path(path);
380     // 查找父目录
381     let parent_inode: Arc<dyn IndexNode> = ROOT_INODE().lookup(parent_path.unwrap_or("/"))?;
382 
383     if parent_inode.metadata()?.file_type != FileType::Dir {
384         return Err(-(ENOTDIR as i32));
385     }
386 
387     // 删除文件
388     parent_inode.unlink(filename)?;
389 
390     return Ok(0);
391 }
392