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