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