xref: /DragonOS/kernel/src/filesystem/vfs/utils.rs (revision dfe53cf087ef4c7b6db63d992906b062dc63e93f)
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             // 如果dirfd不是目录,则返回错误码ENOTDIR
57             if file.file_type() != FileType::Dir {
58                 return Err(SystemError::ENOTDIR);
59             }
60 
61             inode = file.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