xref: /DragonOS/kernel/src/filesystem/vfs/utils.rs (revision 83ed0ebc293d5a10245089f627f52770fd5b9dd4)
1 use alloc::{string::String, sync::Arc};
2 
3 use crate::{process::ProcessControlBlock, syscall::SystemError};
4 
5 use super::{fcntl::AtFlags, FileType, IndexNode, ROOT_INODE};
6 
7 /// @brief 切分路径字符串,返回最左侧那一级的目录名和剩余的部分。
8 ///
9 /// 举例:对于 /123/456/789/   本函数返回的第一个值为123, 第二个值为456/789
10 #[allow(dead_code)]
11 pub fn split_path(path: &str) -> (&str, Option<&str>) {
12     let mut path_split: core::str::SplitN<&str> = path.trim_matches('/').splitn(2, "/");
13     let comp = path_split.next().unwrap_or("");
14     let rest_opt = path_split.next();
15 
16     return (comp, rest_opt);
17 }
18 
19 /// @brief 切分路径字符串,返回最右侧那一级的目录名和剩余的部分。
20 ///
21 /// 举例:对于 /123/456/789/   本函数返回的第一个值为789, 第二个值为123/456
22 pub fn rsplit_path(path: &str) -> (&str, Option<&str>) {
23     let mut path_split: core::str::RSplitN<&str> = path.trim_matches('/').rsplitn(2, "/");
24     let comp = path_split.next().unwrap_or("");
25     let rest_opt = path_split.next();
26 
27     return (comp, rest_opt);
28 }
29 
30 /// 根据dirfd和path,计算接下来开始lookup的inode和剩余的path
31 ///
32 /// ## 返回值
33 ///
34 /// 返回值为(需要执行lookup的inode, 剩余的path)
35 pub fn user_path_at(
36     pcb: &Arc<ProcessControlBlock>,
37     dirfd: i32,
38     path: &str,
39 ) -> Result<(Arc<dyn IndexNode>, String), SystemError> {
40     let mut inode = ROOT_INODE();
41     let ret_path;
42     // 如果path不是绝对路径,则需要拼接
43     if path.as_bytes()[0] != b'/' {
44         // 如果dirfd不是AT_FDCWD,则需要检查dirfd是否是目录
45         if dirfd != AtFlags::AT_FDCWD.bits() {
46             let binding = pcb.fd_table();
47             let fd_table_guard = binding.read();
48             let file = fd_table_guard
49                 .get_file_by_fd(dirfd)
50                 .ok_or(SystemError::EBADF)?;
51 
52             // drop guard 以避免无法调度的问题
53             drop(fd_table_guard);
54 
55             let file_guard = file.lock();
56             // 如果dirfd不是目录,则返回错误码ENOTDIR
57             if file_guard.file_type() != FileType::Dir {
58                 return Err(SystemError::ENOTDIR);
59             }
60 
61             inode = file_guard.inode();
62             ret_path = String::from(path);
63         } else {
64             let mut cwd = pcb.basic().cwd();
65             cwd.push('/');
66             cwd.push_str(path);
67             ret_path = cwd;
68         }
69     } else {
70         ret_path = String::from(path);
71     }
72 
73     return Ok((inode, ret_path));
74 }
75