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