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