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