xref: /DragonOS/kernel/src/filesystem/vfs/utils.rs (revision 1ea2daad8121b77ed704e6d7c3a09f478147441d)
1 use core::cmp::Ordering;
2 use core::fmt::Debug;
3 use core::hash::Hash;
4 
5 use alloc::string::ToString;
6 use alloc::{string::String, sync::Arc};
7 use system_error::SystemError;
8 
9 use crate::process::ProcessControlBlock;
10 
11 use super::{fcntl::AtFlags, FileType, IndexNode, ROOT_INODE};
12 
13 /// @brief 切分路径字符串,返回最左侧那一级的目录名和剩余的部分。
14 ///
15 /// 举例:对于 /123/456/789/   本函数返回的第一个值为123, 第二个值为456/789
16 #[allow(dead_code)]
17 pub fn split_path(path: &str) -> (&str, Option<&str>) {
18     let mut path_split: core::str::SplitN<&str> = path.trim_matches('/').splitn(2, "/");
19     let comp = path_split.next().unwrap_or("");
20     let rest_opt = path_split.next();
21 
22     return (comp, rest_opt);
23 }
24 
25 /// @brief 切分路径字符串,返回最右侧那一级的目录名和剩余的部分。
26 ///
27 /// 举例:对于 /123/456/789/   本函数返回的第一个值为789, 第二个值为123/456
28 pub fn rsplit_path(path: &str) -> (&str, Option<&str>) {
29     let mut path_split: core::str::RSplitN<&str> = path.trim_matches('/').rsplitn(2, "/");
30     let comp = path_split.next().unwrap_or("");
31     let rest_opt = path_split.next();
32 
33     return (comp, rest_opt);
34 }
35 
36 /// 根据dirfd和path,计算接下来开始lookup的inode和剩余的path
37 ///
38 /// ## 返回值
39 ///
40 /// 返回值为(需要执行lookup的inode, 剩余的path)
41 pub fn user_path_at(
42     pcb: &Arc<ProcessControlBlock>,
43     dirfd: i32,
44     path: &str,
45 ) -> Result<(Arc<dyn IndexNode>, String), SystemError> {
46     let mut inode = ROOT_INODE();
47     let ret_path;
48     // 如果path不是绝对路径,则需要拼接
49     if path.as_bytes()[0] != b'/' {
50         // 如果dirfd不是AT_FDCWD,则需要检查dirfd是否是目录
51         if dirfd != AtFlags::AT_FDCWD.bits() {
52             let binding = pcb.fd_table();
53             let fd_table_guard = binding.read();
54             let file = fd_table_guard
55                 .get_file_by_fd(dirfd)
56                 .ok_or(SystemError::EBADF)?;
57 
58             // drop guard 以避免无法调度的问题
59             drop(fd_table_guard);
60 
61             // 如果dirfd不是目录,则返回错误码ENOTDIR
62             if file.file_type() != FileType::Dir {
63                 return Err(SystemError::ENOTDIR);
64             }
65 
66             inode = file.inode();
67             ret_path = String::from(path);
68         } else {
69             let mut cwd = pcb.basic().cwd();
70             cwd.push('/');
71             cwd.push_str(path);
72             ret_path = cwd;
73         }
74     } else {
75         ret_path = String::from(path);
76     }
77 
78     return Ok((inode, ret_path));
79 }
80 
81 /// Directory Name
82 /// 可以用来作为原地提取目录名及比较的
83 /// Dentry的对标(x
84 ///
85 /// 简单的生成一个新的DName,以实现简单的RCU
86 #[derive(Debug)]
87 pub struct DName(pub Arc<String>);
88 
89 impl PartialEq for DName {
90     fn eq(&self, other: &Self) -> bool {
91         return *self.0 == *other.0;
92     }
93 }
94 impl Eq for DName {}
95 
96 impl Hash for DName {
97     fn hash<H: core::hash::Hasher>(&self, state: &mut H) {
98         self.0.hash(state)
99     }
100 }
101 
102 impl PartialOrd for DName {
103     fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
104         Some(self.cmp(other))
105     }
106 }
107 
108 impl Ord for DName {
109     fn cmp(&self, other: &Self) -> Ordering {
110         return self.0.cmp(&other.0);
111     }
112 }
113 
114 impl Default for DName {
115     fn default() -> Self {
116         Self(Arc::new(String::new()))
117     }
118 }
119 
120 impl From<String> for DName {
121     fn from(value: String) -> Self {
122         Self(Arc::from(value))
123     }
124 }
125 
126 impl From<&str> for DName {
127     fn from(value: &str) -> Self {
128         Self(Arc::from(String::from(value)))
129     }
130 }
131 
132 impl Clone for DName {
133     fn clone(&self) -> Self {
134         Self(self.0.clone())
135     }
136 }
137 
138 impl ToString for DName {
139     fn to_string(&self) -> String {
140         (*self.0).clone()
141     }
142 }
143 
144 impl AsRef<str> for DName {
145     fn as_ref(&self) -> &str {
146         self.0.as_str()
147     }
148 }
149