1 pub mod core; 2 pub mod fcntl; 3 pub mod file; 4 pub mod mount; 5 pub mod open; 6 pub mod syscall; 7 pub mod utils; 8 9 use ::core::{any::Any, fmt::Debug, sync::atomic::AtomicUsize}; 10 use alloc::{string::String, sync::Arc, vec::Vec}; 11 use intertrait::CastFromSync; 12 use system_error::SystemError; 13 14 use crate::{ 15 driver::base::{ 16 block::block_device::BlockDevice, char::CharDevice, device::device_number::DeviceNumber, 17 }, 18 ipc::pipe::LockedPipeInode, 19 libs::{ 20 casting::DowncastArc, 21 spinlock::{SpinLock, SpinLockGuard}, 22 }, 23 mm::{fault::PageFaultMessage, VmFaultReason}, 24 time::PosixTimeSpec, 25 }; 26 27 use self::{ 28 core::generate_inode_id, 29 file::{FileMode, PageCache}, 30 syscall::ModeType, 31 utils::DName, 32 }; 33 pub use self::{core::ROOT_INODE, file::FilePrivateData, mount::MountFS}; 34 35 /// vfs容许的最大的路径名称长度 36 pub const MAX_PATHLEN: usize = 1024; 37 38 // 定义inode号 39 int_like!(InodeId, AtomicInodeId, usize, AtomicUsize); 40 41 /// 文件的类型 42 #[derive(Debug, Clone, Copy, PartialEq, Eq)] 43 pub enum FileType { 44 /// 文件 45 File, 46 /// 文件夹 47 Dir, 48 /// 块设备 49 BlockDevice, 50 /// 字符设备 51 CharDevice, 52 /// 帧缓冲设备 53 FramebufferDevice, 54 /// kvm设备 55 KvmDevice, 56 /// 管道文件 57 Pipe, 58 /// 符号链接 59 SymLink, 60 /// 套接字 61 Socket, 62 } 63 64 #[allow(dead_code)] 65 #[derive(Debug, Clone)] 66 pub enum SpecialNodeData { 67 /// 管道文件 68 Pipe(Arc<LockedPipeInode>), 69 /// 字符设备 70 CharDevice(Arc<dyn CharDevice>), 71 /// 块设备 72 BlockDevice(Arc<dyn BlockDevice>), 73 } 74 75 /* these are defined by POSIX and also present in glibc's dirent.h */ 76 /// 完整含义请见 http://www.gnu.org/software/libc/manual/html_node/Directory-Entries.html 77 #[allow(dead_code)] 78 pub const DT_UNKNOWN: u16 = 0; 79 /// 命名管道,或者FIFO 80 pub const DT_FIFO: u16 = 1; 81 // 字符设备 82 pub const DT_CHR: u16 = 2; 83 // 目录 84 pub const DT_DIR: u16 = 4; 85 // 块设备 86 pub const DT_BLK: u16 = 6; 87 // 常规文件 88 pub const DT_REG: u16 = 8; 89 // 符号链接 90 pub const DT_LNK: u16 = 10; 91 // 是一个socket 92 pub const DT_SOCK: u16 = 12; 93 // 这个是抄Linux的,还不知道含义 94 #[allow(dead_code)] 95 pub const DT_WHT: u16 = 14; 96 #[allow(dead_code)] 97 pub const DT_MAX: u16 = 16; 98 99 /// vfs容许的最大的符号链接跳转次数 100 pub const VFS_MAX_FOLLOW_SYMLINK_TIMES: usize = 8; 101 102 impl FileType { 103 pub fn get_file_type_num(&self) -> u16 { 104 return match self { 105 FileType::File => DT_REG, 106 FileType::Dir => DT_DIR, 107 FileType::BlockDevice => DT_BLK, 108 FileType::CharDevice => DT_CHR, 109 FileType::KvmDevice => DT_CHR, 110 FileType::Pipe => DT_FIFO, 111 FileType::SymLink => DT_LNK, 112 FileType::Socket => DT_SOCK, 113 FileType::FramebufferDevice => DT_CHR, 114 }; 115 } 116 } 117 118 bitflags! { 119 /// @brief inode的状态(由poll方法返回) 120 pub struct PollStatus: u8 { 121 const WRITE = 1u8 << 0; 122 const READ = 1u8 << 1; 123 const ERROR = 1u8 << 2; 124 } 125 } 126 127 pub trait IndexNode: Any + Sync + Send + Debug + CastFromSync { 128 fn mmap(&self, _start: usize, _len: usize, _offset: usize) -> Result<(), SystemError> { 129 return Err(SystemError::ENOSYS); 130 } 131 /// @brief 打开文件 132 /// 133 /// @return 成功:Ok() 134 /// 失败:Err(错误码) 135 fn open( 136 &self, 137 _data: SpinLockGuard<FilePrivateData>, 138 _mode: &FileMode, 139 ) -> Result<(), SystemError> { 140 // 若文件系统没有实现此方法,则返回“不支持” 141 return Err(SystemError::ENOSYS); 142 } 143 144 /// @brief 关闭文件 145 /// 146 /// @return 成功:Ok() 147 /// 失败:Err(错误码) 148 fn close(&self, _data: SpinLockGuard<FilePrivateData>) -> Result<(), SystemError> { 149 // 若文件系统没有实现此方法,则返回“不支持” 150 return Err(SystemError::ENOSYS); 151 } 152 153 /// @brief 在inode的指定偏移量开始,读取指定大小的数据 154 /// 155 /// @param offset 起始位置在Inode中的偏移量 156 /// @param len 要读取的字节数 157 /// @param buf 缓冲区. 请注意,必须满足@buf.len()>=@len 158 /// @param _data 各文件系统系统所需私有信息 159 /// 160 /// @return 成功:Ok(读取的字节数) 161 /// 失败:Err(Posix错误码) 162 fn read_at( 163 &self, 164 offset: usize, 165 len: usize, 166 buf: &mut [u8], 167 _data: SpinLockGuard<FilePrivateData>, 168 ) -> Result<usize, SystemError>; 169 170 /// @brief 在inode的指定偏移量开始,写入指定大小的数据(从buf的第0byte开始写入) 171 /// 172 /// @param offset 起始位置在Inode中的偏移量 173 /// @param len 要写入的字节数 174 /// @param buf 缓冲区. 请注意,必须满足@buf.len()>=@len 175 /// @param _data 各文件系统系统所需私有信息 176 /// 177 /// @return 成功:Ok(写入的字节数) 178 /// 失败:Err(Posix错误码) 179 fn write_at( 180 &self, 181 offset: usize, 182 len: usize, 183 buf: &[u8], 184 _data: SpinLockGuard<FilePrivateData>, 185 ) -> Result<usize, SystemError>; 186 187 /// @brief 获取当前inode的状态。 188 /// 189 /// @return PollStatus结构体 190 fn poll(&self, _private_data: &FilePrivateData) -> Result<usize, SystemError> { 191 // 若文件系统没有实现此方法,则返回“不支持” 192 return Err(SystemError::ENOSYS); 193 } 194 195 /// @brief 获取inode的元数据 196 /// 197 /// @return 成功:Ok(inode的元数据) 198 /// 失败:Err(错误码) 199 fn metadata(&self) -> Result<Metadata, SystemError> { 200 // 若文件系统没有实现此方法,则返回“不支持” 201 return Err(SystemError::ENOSYS); 202 } 203 204 /// @brief 设置inode的元数据 205 /// 206 /// @return 成功:Ok() 207 /// 失败:Err(错误码) 208 fn set_metadata(&self, _metadata: &Metadata) -> Result<(), SystemError> { 209 // 若文件系统没有实现此方法,则返回“不支持” 210 return Err(SystemError::ENOSYS); 211 } 212 213 /// @brief 重新设置文件的大小 214 /// 215 /// 如果文件大小增加,则文件内容不变,但是文件的空洞部分会被填充为0 216 /// 如果文件大小减小,则文件内容会被截断 217 /// 218 /// @return 成功:Ok() 219 /// 失败:Err(错误码) 220 fn resize(&self, _len: usize) -> Result<(), SystemError> { 221 // 若文件系统没有实现此方法,则返回“不支持” 222 return Err(SystemError::ENOSYS); 223 } 224 225 /// @brief 在当前目录下创建一个新的inode 226 /// 227 /// @param name 目录项的名字 228 /// @param file_type 文件类型 229 /// @param mode 权限 230 /// 231 /// @return 创建成功:返回Ok(新的inode的Arc指针) 232 /// @return 创建失败:返回Err(错误码) 233 fn create( 234 &self, 235 name: &str, 236 file_type: FileType, 237 mode: ModeType, 238 ) -> Result<Arc<dyn IndexNode>, SystemError> { 239 // 若文件系统没有实现此方法,则默认调用其create_with_data方法。如果仍未实现,则会得到一个Err(-ENOSYS)的返回值 240 return self.create_with_data(name, file_type, mode, 0); 241 } 242 243 /// @brief 在当前目录下创建一个新的inode,并传入一个简单的data字段,方便进行初始化。 244 /// 245 /// @param name 目录项的名字 246 /// @param file_type 文件类型 247 /// @param mode 权限 248 /// @param data 用于初始化该inode的数据。(为0则表示忽略此字段)对于不同的文件系统来说,代表的含义可能不同。 249 /// 250 /// @return 创建成功:返回Ok(新的inode的Arc指针) 251 /// @return 创建失败:返回Err(错误码) 252 fn create_with_data( 253 &self, 254 _name: &str, 255 _file_type: FileType, 256 _mode: ModeType, 257 _data: usize, 258 ) -> Result<Arc<dyn IndexNode>, SystemError> { 259 // 若文件系统没有实现此方法,则返回“不支持” 260 return Err(SystemError::ENOSYS); 261 } 262 263 /// @brief 在当前目录下,创建一个名为Name的硬链接,指向另一个IndexNode 264 /// 265 /// @param name 硬链接的名称 266 /// @param other 要被指向的IndexNode的Arc指针 267 /// 268 /// @return 成功:Ok() 269 /// 失败:Err(错误码) 270 fn link(&self, _name: &str, _other: &Arc<dyn IndexNode>) -> Result<(), SystemError> { 271 // 若文件系统没有实现此方法,则返回“不支持” 272 return Err(SystemError::ENOSYS); 273 } 274 275 /// @brief 在当前目录下,删除一个名为Name的硬链接 276 /// 277 /// @param name 硬链接的名称 278 /// 279 /// @return 成功:Ok() 280 /// 失败:Err(错误码) 281 fn unlink(&self, _name: &str) -> Result<(), SystemError> { 282 // 若文件系统没有实现此方法,则返回“不支持” 283 return Err(SystemError::ENOSYS); 284 } 285 286 /// @brief 删除文件夹 287 /// 288 /// @param name 文件夹名称 289 /// 290 /// @return 成功 Ok(()) 291 /// @return 失败 Err(错误码) 292 fn rmdir(&self, _name: &str) -> Result<(), SystemError> { 293 return Err(SystemError::ENOSYS); 294 } 295 296 /// 将指定的`old_name`子目录项移动到target目录下, 并予以`new_name`。 297 /// 298 /// # Behavior 299 /// 如果old_name所指向的inode与target的相同,那么则直接**执行重命名的操作**。 300 fn move_to( 301 &self, 302 _old_name: &str, 303 _target: &Arc<dyn IndexNode>, 304 _new_name: &str, 305 ) -> Result<(), SystemError> { 306 // 若文件系统没有实现此方法,则返回“不支持” 307 return Err(SystemError::ENOSYS); 308 } 309 310 /// @brief 寻找一个名为Name的inode 311 /// 312 /// @param name 要寻找的inode的名称 313 /// 314 /// @return 成功:Ok() 315 /// 失败:Err(错误码) 316 fn find(&self, _name: &str) -> Result<Arc<dyn IndexNode>, SystemError> { 317 // 若文件系统没有实现此方法,则返回“不支持” 318 return Err(SystemError::ENOSYS); 319 } 320 321 /// @brief 根据inode号,获取子目录项的名字 322 /// 323 /// @param ino inode号 324 /// 325 /// @return 成功:Ok() 326 /// 失败:Err(错误码) 327 fn get_entry_name(&self, _ino: InodeId) -> Result<String, SystemError> { 328 // 若文件系统没有实现此方法,则返回“不支持” 329 return Err(SystemError::ENOSYS); 330 } 331 332 /// @brief 根据inode号,获取子目录项的名字和元数据 333 /// 334 /// @param ino inode号 335 /// 336 /// @return 成功:Ok(String, Metadata) 337 /// 失败:Err(错误码) 338 fn get_entry_name_and_metadata(&self, ino: InodeId) -> Result<(String, Metadata), SystemError> { 339 // 如果有条件,请在文件系统中使用高效的方式实现本接口,而不是依赖这个低效率的默认实现。 340 let name = self.get_entry_name(ino)?; 341 let entry = self.find(&name)?; 342 return Ok((name, entry.metadata()?)); 343 } 344 345 /// @brief io control接口 346 /// 347 /// @param cmd 命令 348 /// @param data 数据 349 /// 350 /// @return 成功:Ok() 351 /// 失败:Err(错误码) 352 fn ioctl( 353 &self, 354 _cmd: u32, 355 _data: usize, 356 _private_data: &FilePrivateData, 357 ) -> Result<usize, SystemError> { 358 // 若文件系统没有实现此方法,则返回“不支持” 359 return Err(SystemError::ENOSYS); 360 } 361 362 fn kernel_ioctl( 363 &self, 364 _arg: Arc<dyn crate::net::event_poll::KernelIoctlData>, 365 _data: &FilePrivateData, 366 ) -> Result<usize, SystemError> { 367 return Err(SystemError::ENOSYS); 368 } 369 370 /// @brief 获取inode所在的文件系统的指针 371 fn fs(&self) -> Arc<dyn FileSystem>; 372 373 /// @brief 本函数用于实现动态转换。 374 /// 具体的文件系统在实现本函数时,最简单的方式就是:直接返回self 375 fn as_any_ref(&self) -> &dyn Any; 376 377 /// @brief 列出当前inode下的所有目录项的名字 378 fn list(&self) -> Result<Vec<String>, SystemError>; 379 380 /// # mount - 挂载文件系统 381 /// 382 /// 将给定的文件系统挂载到当前的文件系统节点上。 383 /// 384 /// 该函数是`MountFS`结构体的实例方法,用于将一个新的文件系统挂载到调用它的`MountFS`实例上。 385 /// 386 /// ## 参数 387 /// 388 /// - `fs`: `Arc<dyn FileSystem>` - 要挂载的文件系统的共享引用。 389 /// 390 /// ## 返回值 391 /// 392 /// - `Ok(Arc<MountFS>)`: 新的挂载文件系统的共享引用。 393 /// - `Err(SystemError)`: 挂载过程中出现的错误。 394 /// 395 /// ## 错误处理 396 /// 397 /// - 如果文件系统不是目录类型,则返回`SystemError::ENOTDIR`错误。 398 /// - 如果当前路径已经是挂载点,则返回`SystemError::EBUSY`错误。 399 /// 400 /// ## 副作用 401 /// 402 /// - 该函数会在`MountFS`实例上创建一个新的挂载点。 403 /// - 该函数会在全局的挂载列表中记录新的挂载关系。 404 fn mount(&self, _fs: Arc<dyn FileSystem>) -> Result<Arc<MountFS>, SystemError> { 405 return Err(SystemError::ENOSYS); 406 } 407 408 /// # mount_from - 从给定的目录挂载已有挂载信息的文件系统 409 /// 410 /// 这个函数将一个已有挂载信息的文件系统从给定的目录挂载到当前目录。 411 /// 412 /// ## 参数 413 /// 414 /// - `from`: Arc<dyn IndexNode> - 要挂载的目录的引用。 415 /// 416 /// ## 返回值 417 /// 418 /// - Ok(Arc<MountFS>): 挂载的新文件系统的引用。 419 /// - Err(SystemError): 如果发生错误,返回系统错误。 420 /// 421 /// ## 错误处理 422 /// 423 /// - 如果给定的目录不是目录类型,返回`SystemError::ENOTDIR`。 424 /// - 如果当前目录已经是挂载点的根目录,返回`SystemError::EBUSY`。 425 /// 426 /// ## 副作用 427 /// 428 /// - 系统初始化用,其他情况不应调用此函数 429 fn mount_from(&self, _des: Arc<dyn IndexNode>) -> Result<Arc<MountFS>, SystemError> { 430 return Err(SystemError::ENOSYS); 431 } 432 433 /// # umount - 卸载当前Inode下的文件系统 434 /// 435 /// 该函数是特定于`MountFS`实现的,其他文件系统不应实现此函数。 436 /// 437 /// ## 参数 438 /// 439 /// 无 440 /// 441 /// ## 返回值 442 /// 443 /// - Ok(Arc<MountFS>): 卸载的文件系统的引用。 444 /// - Err(SystemError): 如果发生错误,返回系统错误。 445 /// 446 /// ## 行为 447 /// 448 /// - 查找路径 449 /// - 定位到父文件系统的挂载点 450 /// - 将挂载点与子文件系统的根进行叠加 451 /// - 判断是否为子文件系统的根 452 /// - 调用父文件系统挂载点的`_umount`方法进行卸载 453 fn umount(&self) -> Result<Arc<MountFS>, SystemError> { 454 return Err(SystemError::ENOSYS); 455 } 456 457 /// # absolute_path 获取目录项绝对路径 458 /// 459 /// ## 参数 460 /// 461 /// 无 462 /// 463 /// ## 返回值 464 /// 465 /// - Ok(String): 路径 466 /// - Err(SystemError): 文件系统不支持dname parent api 467 /// 468 /// ## Behavior 469 /// 470 /// 该函数只能被MountFS实现,其他文件系统不应实现这个函数 471 /// 472 /// # Performance 473 /// 474 /// 这是一个O(n)的路径查询,并且在未实现DName缓存的文件系统中,性能极差; 475 /// 即使实现了DName也尽量不要用。 476 fn absolute_path(&self) -> Result<String, SystemError> { 477 return Err(SystemError::ENOSYS); 478 } 479 480 /// @brief 截断当前inode到指定的长度。如果当前文件长度小于len,则不操作。 481 /// 482 /// @param len 要被截断到的目标长度 483 fn truncate(&self, _len: usize) -> Result<(), SystemError> { 484 return Err(SystemError::ENOSYS); 485 } 486 487 /// @brief 将当前inode的内容同步到具体设备上 488 fn sync(&self) -> Result<(), SystemError> { 489 return Ok(()); 490 } 491 492 /// ## 创建一个特殊文件节点 493 /// - _filename: 文件名 494 /// - _mode: 权限信息 495 fn mknod( 496 &self, 497 _filename: &str, 498 _mode: ModeType, 499 _dev_t: DeviceNumber, 500 ) -> Result<Arc<dyn IndexNode>, SystemError> { 501 return Err(SystemError::ENOSYS); 502 } 503 504 /// # mkdir - 新建名称为`name`的目录项 505 /// 506 /// 当目录下已有名称为`name`的文件夹时,返回该目录项的引用;否则新建`name`文件夹,并返回该引用。 507 /// 508 /// 该函数会检查`name`目录是否已存在,如果存在但类型不为文件夹,则会返回`EEXIST`错误。 509 /// 510 /// # 参数 511 /// 512 /// - `name`: &str - 要新建的目录项的名称。 513 /// - `mode`: ModeType - 设置目录项的权限模式。 514 /// 515 /// # 返回值 516 /// 517 /// - `Ok(Arc<dyn IndexNode>)`: 成功时返回`name`目录项的共享引用。 518 /// - `Err(SystemError)`: 出错时返回错误信息。 519 fn mkdir(&self, name: &str, mode: ModeType) -> Result<Arc<dyn IndexNode>, SystemError> { 520 match self.find(name) { 521 Ok(inode) => { 522 if inode.metadata()?.file_type == FileType::Dir { 523 Ok(inode) 524 } else { 525 Err(SystemError::EEXIST) 526 } 527 } 528 Err(SystemError::ENOENT) => self.create(name, FileType::Dir, mode), 529 Err(err) => Err(err), 530 } 531 } 532 533 /// ## 返回特殊文件的inode 534 fn special_node(&self) -> Option<SpecialNodeData> { 535 None 536 } 537 538 /// # dname - 返回目录名 539 /// 540 /// 此函数用于返回一个目录名。 541 /// 542 /// ## 参数 543 /// 544 /// 无 545 /// 546 /// ## 返回值 547 /// - Ok(DName): 成功时返回一个目录名。 548 /// - Err(SystemError): 如果系统不支持此操作,则返回一个系统错误。 549 fn dname(&self) -> Result<DName, SystemError> { 550 return Err(SystemError::ENOSYS); 551 } 552 553 /// # parent - 返回父目录的引用 554 /// 555 /// 当该目录是当前文件系统的根目录时,返回自身的引用。 556 /// 557 /// ## 参数 558 /// 559 /// 无 560 /// 561 /// ## 返回值 562 /// 563 /// - Ok(Arc<dyn IndexNode>): A reference to the parent directory 564 /// - Err(SystemError): If there is an error in finding the parent directory 565 fn parent(&self) -> Result<Arc<dyn IndexNode>, SystemError> { 566 return self.find(".."); 567 } 568 569 fn page_cache(&self) -> Option<Arc<PageCache>> { 570 log::error!( 571 "function page_cache() has not yet been implemented for inode:{}", 572 crate::libs::name::get_type_name(&self) 573 ); 574 None 575 } 576 } 577 578 impl DowncastArc for dyn IndexNode { 579 fn as_any_arc(self: Arc<Self>) -> Arc<dyn Any> { 580 self 581 } 582 } 583 584 impl dyn IndexNode { 585 /// @brief 将当前Inode转换为一个具体的结构体(类型由T指定) 586 /// 如果类型正确,则返回Some,否则返回None 587 pub fn downcast_ref<T: IndexNode>(&self) -> Option<&T> { 588 return self.as_any_ref().downcast_ref::<T>(); 589 } 590 591 /// @brief 查找文件(不考虑符号链接) 592 /// 593 /// @param path 文件路径 594 /// 595 /// @return Ok(Arc<dyn IndexNode>) 要寻找的目录项的inode 596 /// @return Err(SystemError) 错误码 597 pub fn lookup(&self, path: &str) -> Result<Arc<dyn IndexNode>, SystemError> { 598 return self.lookup_follow_symlink(path, 0); 599 } 600 601 pub fn lookup_follow_symlink( 602 &self, 603 path: &str, 604 max_follow_times: usize, 605 ) -> Result<Arc<dyn IndexNode>, SystemError> { 606 return self.do_lookup_follow_symlink(path, max_follow_times, true); 607 } 608 609 pub fn lookup_follow_symlink2( 610 &self, 611 path: &str, 612 max_follow_times: usize, 613 follow_final_symlink: bool, 614 ) -> Result<Arc<dyn IndexNode>, SystemError> { 615 return self.do_lookup_follow_symlink(path, max_follow_times, follow_final_symlink); 616 } 617 618 /// # 查找文件 619 /// 查找指定路径的文件,考虑符号链接的存在,并可选择是否返回最终路径的符号链接文件本身。 620 /// 621 /// ## 参数 622 /// - `path`: 文件路径 623 /// - `max_follow_times`: 最大经过的符号链接的数量 624 /// - `follow_final_symlink`: 是否跟随最后的符号链接 625 /// 626 /// ## 返回值 627 /// - `Ok(Arc<dyn IndexNode>)`: 要寻找的目录项的inode 628 /// - `Err(SystemError)`: 错误码,表示查找过程中遇到的错误 629 /// 630 /// ## Safety 631 /// 此函数在处理符号链接时可能会遇到循环引用的情况,`max_follow_times` 参数用于限制符号链接的跟随次数以避免无限循环。 632 #[inline(never)] 633 pub fn do_lookup_follow_symlink( 634 &self, 635 path: &str, 636 max_follow_times: usize, 637 follow_final_symlink: bool, 638 ) -> Result<Arc<dyn IndexNode>, SystemError> { 639 if self.metadata()?.file_type != FileType::Dir { 640 return Err(SystemError::ENOTDIR); 641 } 642 643 // 处理绝对路径 644 // result: 上一个被找到的inode 645 // rest_path: 还没有查找的路径 646 let (mut result, mut rest_path) = if let Some(rest) = path.strip_prefix('/') { 647 (ROOT_INODE().clone(), String::from(rest)) 648 } else { 649 // 是相对路径 650 (self.find(".")?, String::from(path)) 651 }; 652 653 // 逐级查找文件 654 while !rest_path.is_empty() { 655 // 当前这一级不是文件夹 656 if result.metadata()?.file_type != FileType::Dir { 657 return Err(SystemError::ENOTDIR); 658 } 659 660 let name; 661 // 寻找“/” 662 match rest_path.find('/') { 663 Some(pos) => { 664 name = String::from(&rest_path[0..pos]); 665 rest_path = String::from(&rest_path[pos + 1..]); 666 } 667 None => { 668 name = rest_path; 669 rest_path = String::new(); 670 } 671 } 672 673 // 遇到连续多个"/"的情况 674 if name.is_empty() { 675 continue; 676 } 677 678 let inode = result.find(&name)?; 679 let file_type = inode.metadata()?.file_type; 680 // 如果已经是路径的最后一个部分,并且不希望跟随最后的符号链接 681 if rest_path.is_empty() && !follow_final_symlink && file_type == FileType::SymLink { 682 // 返回符号链接本身 683 return Ok(inode); 684 } 685 686 // 跟随符号链接跳转 687 if file_type == FileType::SymLink && max_follow_times > 0 { 688 let mut content = [0u8; 256]; 689 // 读取符号链接 690 691 let len = inode.read_at( 692 0, 693 256, 694 &mut content, 695 SpinLock::new(FilePrivateData::Unused).lock(), 696 )?; 697 698 // 将读到的数据转换为utf8字符串(先转为str,再转为String) 699 let link_path = String::from( 700 ::core::str::from_utf8(&content[..len]).map_err(|_| SystemError::EINVAL)?, 701 ); 702 let new_path = link_path + "/" + &rest_path; 703 704 // 继续查找符号链接 705 return result.lookup_follow_symlink2( 706 &new_path, 707 max_follow_times - 1, 708 follow_final_symlink, 709 ); 710 } else { 711 result = inode; 712 } 713 } 714 715 return Ok(result); 716 } 717 } 718 719 /// IndexNode的元数据 720 /// 721 /// 对应Posix2008中的sys/stat.h中的定义 https://pubs.opengroup.org/onlinepubs/9699919799/basedefs/sys_stat.h.html 722 #[derive(Debug, PartialEq, Eq, Clone)] 723 pub struct Metadata { 724 /// 当前inode所在的文件系统的设备号 725 pub dev_id: usize, 726 727 /// inode号 728 pub inode_id: InodeId, 729 730 /// Inode的大小 731 /// 文件:文件大小(单位:字节) 732 /// 目录:目录项中的文件、文件夹数量 733 pub size: i64, 734 735 /// Inode所在的文件系统中,每个块的大小 736 pub blk_size: usize, 737 738 /// Inode所占的块的数目 739 pub blocks: usize, 740 741 /// inode最后一次被访问的时间 742 pub atime: PosixTimeSpec, 743 744 /// inode最后一次修改的时间 745 pub mtime: PosixTimeSpec, 746 747 /// inode的创建时间 748 pub ctime: PosixTimeSpec, 749 750 /// 文件类型 751 pub file_type: FileType, 752 753 /// 权限 754 pub mode: ModeType, 755 756 /// 硬链接的数量 757 pub nlinks: usize, 758 759 /// User ID 760 pub uid: usize, 761 762 /// Group ID 763 pub gid: usize, 764 765 /// 文件指向的设备的id(对于设备文件系统来说) 766 pub raw_dev: DeviceNumber, 767 } 768 769 impl Default for Metadata { 770 fn default() -> Self { 771 return Self { 772 dev_id: 0, 773 inode_id: InodeId::new(0), 774 size: 0, 775 blk_size: 0, 776 blocks: 0, 777 atime: PosixTimeSpec::default(), 778 mtime: PosixTimeSpec::default(), 779 ctime: PosixTimeSpec::default(), 780 file_type: FileType::File, 781 mode: ModeType::empty(), 782 nlinks: 1, 783 uid: 0, 784 gid: 0, 785 raw_dev: DeviceNumber::default(), 786 }; 787 } 788 } 789 790 #[derive(Debug, Clone)] 791 pub struct SuperBlock { 792 // type of filesystem 793 pub magic: Magic, 794 // optimal transfer block size 795 pub bsize: u64, 796 // total data blocks in filesystem 797 pub blocks: u64, 798 // free block in system 799 pub bfree: u64, 800 // 可供非特权用户使用的空闲块 801 pub bavail: u64, 802 // total inodes in filesystem 803 pub files: u64, 804 // free inodes in filesystem 805 pub ffree: u64, 806 // filesysytem id 807 pub fsid: u64, 808 // Max length of filename 809 pub namelen: u64, 810 // fragment size 811 pub frsize: u64, 812 // mount flags of filesystem 813 pub flags: u64, 814 } 815 816 impl SuperBlock { 817 pub fn new(magic: Magic, bsize: u64, namelen: u64) -> Self { 818 Self { 819 magic, 820 bsize, 821 blocks: 0, 822 bfree: 0, 823 bavail: 0, 824 files: 0, 825 ffree: 0, 826 fsid: 0, 827 namelen, 828 frsize: 0, 829 flags: 0, 830 } 831 } 832 } 833 bitflags! { 834 pub struct Magic: u64 { 835 const DEVFS_MAGIC = 0x1373; 836 const FAT_MAGIC = 0xf2f52011; 837 const KER_MAGIC = 0x3153464b; 838 const PROC_MAGIC = 0x9fa0; 839 const RAMFS_MAGIC = 0x858458f6; 840 const MOUNT_MAGIC = 61267; 841 } 842 } 843 844 /// @brief 所有文件系统都应该实现的trait 845 pub trait FileSystem: Any + Sync + Send + Debug { 846 /// @brief 获取当前文件系统的root inode的指针 847 fn root_inode(&self) -> Arc<dyn IndexNode>; 848 849 /// @brief 获取当前文件系统的信息 850 fn info(&self) -> FsInfo; 851 852 /// @brief 本函数用于实现动态转换。 853 /// 具体的文件系统在实现本函数时,最简单的方式就是:直接返回self 854 fn as_any_ref(&self) -> &dyn Any; 855 856 fn name(&self) -> &str; 857 858 fn super_block(&self) -> SuperBlock; 859 860 unsafe fn fault(&self, _pfm: &mut PageFaultMessage) -> VmFaultReason { 861 panic!( 862 "fault() has not yet been implemented for filesystem: {}", 863 crate::libs::name::get_type_name(&self) 864 ) 865 } 866 867 unsafe fn map_pages( 868 &self, 869 _pfm: &mut PageFaultMessage, 870 _start_pgoff: usize, 871 _end_pgoff: usize, 872 ) -> VmFaultReason { 873 panic!( 874 "map_pages() has not yet been implemented for filesystem: {}", 875 crate::libs::name::get_type_name(&self) 876 ) 877 } 878 } 879 880 impl DowncastArc for dyn FileSystem { 881 fn as_any_arc(self: Arc<Self>) -> Arc<dyn Any> { 882 self 883 } 884 } 885 886 #[derive(Debug)] 887 pub struct FsInfo { 888 /// 文件系统所在的块设备的id 889 pub blk_dev_id: usize, 890 /// 文件名的最大长度 891 pub max_name_len: usize, 892 } 893 894 /// @brief 895 #[repr(C)] 896 #[derive(Debug)] 897 pub struct Dirent { 898 d_ino: u64, // 文件序列号 899 d_off: i64, // dir偏移量 900 d_reclen: u16, // 目录下的记录数 901 d_type: u8, // entry的类型 902 d_name: u8, // 文件entry的名字(是一个零长数组), 本字段仅用于占位 903 } 904 905 impl Metadata { 906 pub fn new(file_type: FileType, mode: ModeType) -> Self { 907 Metadata { 908 dev_id: 0, 909 inode_id: generate_inode_id(), 910 size: 0, 911 blk_size: 0, 912 blocks: 0, 913 atime: PosixTimeSpec::default(), 914 mtime: PosixTimeSpec::default(), 915 ctime: PosixTimeSpec::default(), 916 file_type, 917 mode, 918 nlinks: 1, 919 uid: 0, 920 gid: 0, 921 raw_dev: DeviceNumber::default(), 922 } 923 } 924 } 925 pub struct FileSystemMaker { 926 function: &'static FileSystemNewFunction, 927 name: &'static str, 928 } 929 930 impl FileSystemMaker { 931 pub const fn new( 932 name: &'static str, 933 function: &'static FileSystemNewFunction, 934 ) -> FileSystemMaker { 935 FileSystemMaker { function, name } 936 } 937 938 pub fn call( 939 &self, 940 data: Option<&dyn FileSystemMakerData>, 941 ) -> Result<Arc<dyn FileSystem>, SystemError> { 942 (self.function)(data) 943 } 944 } 945 946 pub trait FileSystemMakerData: Send + Sync { 947 fn as_any(&self) -> &dyn Any; 948 } 949 950 pub type FileSystemNewFunction = 951 fn(data: Option<&dyn FileSystemMakerData>) -> Result<Arc<dyn FileSystem>, SystemError>; 952 953 #[macro_export] 954 macro_rules! define_filesystem_maker_slice { 955 ($name:ident) => { 956 #[::linkme::distributed_slice] 957 pub static $name: [FileSystemMaker] = [..]; 958 }; 959 () => { 960 compile_error!("define_filesystem_maker_slice! requires at least one argument: slice_name"); 961 }; 962 } 963 964 /// 调用指定数组中的所有初始化器 965 #[macro_export] 966 macro_rules! producefs { 967 ($initializer_slice:ident,$filesystem:ident,$raw_data : ident) => { 968 match $initializer_slice.iter().find(|&m| m.name == $filesystem) { 969 Some(maker) => { 970 let mount_data = match $filesystem { 971 "overlay" => OverlayMountData::from_row($raw_data).ok(), 972 _ => None, 973 }; 974 let data: Option<&dyn FileSystemMakerData> = 975 mount_data.as_ref().map(|d| d as &dyn FileSystemMakerData); 976 977 maker.call(data) 978 } 979 None => { 980 log::error!("mismatch filesystem type : {}", $filesystem); 981 Err(SystemError::EINVAL) 982 } 983 } 984 }; 985 } 986 987 define_filesystem_maker_slice!(FSMAKER); 988