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 /// @brief 查找文件(考虑符号链接) 602 /// 603 /// @param path 文件路径 604 /// @param max_follow_times 最大经过的符号链接的大小 605 /// 606 /// @return Ok(Arc<dyn IndexNode>) 要寻找的目录项的inode 607 /// @return Err(SystemError) 错误码 608 pub fn lookup_follow_symlink( 609 &self, 610 path: &str, 611 max_follow_times: usize, 612 ) -> Result<Arc<dyn IndexNode>, SystemError> { 613 if self.metadata()?.file_type != FileType::Dir { 614 return Err(SystemError::ENOTDIR); 615 } 616 617 // 处理绝对路径 618 // result: 上一个被找到的inode 619 // rest_path: 还没有查找的路径 620 let (mut result, mut rest_path) = if let Some(rest) = path.strip_prefix('/') { 621 (ROOT_INODE().clone(), String::from(rest)) 622 } else { 623 // 是相对路径 624 (self.find(".")?, String::from(path)) 625 }; 626 627 // 逐级查找文件 628 while !rest_path.is_empty() { 629 // 当前这一级不是文件夹 630 if result.metadata()?.file_type != FileType::Dir { 631 return Err(SystemError::ENOTDIR); 632 } 633 634 let name; 635 636 // 寻找“/” 637 match rest_path.find('/') { 638 Some(pos) => { 639 // 找到了,设置下一个要查找的名字 640 name = String::from(&rest_path[0..pos]); 641 // 剩余的路径字符串 642 rest_path = String::from(&rest_path[pos + 1..]); 643 } 644 None => { 645 name = rest_path; 646 rest_path = String::new(); 647 } 648 } 649 650 // 遇到连续多个"/"的情况 651 if name.is_empty() { 652 continue; 653 } 654 655 let inode = result.find(&name)?; 656 657 // 处理符号链接的问题 658 if inode.metadata()?.file_type == FileType::SymLink && max_follow_times > 0 { 659 let mut content = [0u8; 256]; 660 // 读取符号链接 661 let len = inode.read_at( 662 0, 663 256, 664 &mut content, 665 SpinLock::new(FilePrivateData::Unused).lock(), 666 )?; 667 668 // 将读到的数据转换为utf8字符串(先转为str,再转为String) 669 let link_path = String::from( 670 ::core::str::from_utf8(&content[..len]).map_err(|_| SystemError::ENOTDIR)?, 671 ); 672 673 let new_path = link_path + "/" + &rest_path; 674 // 继续查找符号链接 675 return result.lookup_follow_symlink(&new_path, max_follow_times - 1); 676 } else { 677 result = inode; 678 } 679 } 680 681 return Ok(result); 682 } 683 } 684 685 /// IndexNode的元数据 686 /// 687 /// 对应Posix2008中的sys/stat.h中的定义 https://pubs.opengroup.org/onlinepubs/9699919799/basedefs/sys_stat.h.html 688 #[derive(Debug, PartialEq, Eq, Clone)] 689 pub struct Metadata { 690 /// 当前inode所在的文件系统的设备号 691 pub dev_id: usize, 692 693 /// inode号 694 pub inode_id: InodeId, 695 696 /// Inode的大小 697 /// 文件:文件大小(单位:字节) 698 /// 目录:目录项中的文件、文件夹数量 699 pub size: i64, 700 701 /// Inode所在的文件系统中,每个块的大小 702 pub blk_size: usize, 703 704 /// Inode所占的块的数目 705 pub blocks: usize, 706 707 /// inode最后一次被访问的时间 708 pub atime: PosixTimeSpec, 709 710 /// inode最后一次修改的时间 711 pub mtime: PosixTimeSpec, 712 713 /// inode的创建时间 714 pub ctime: PosixTimeSpec, 715 716 /// 文件类型 717 pub file_type: FileType, 718 719 /// 权限 720 pub mode: ModeType, 721 722 /// 硬链接的数量 723 pub nlinks: usize, 724 725 /// User ID 726 pub uid: usize, 727 728 /// Group ID 729 pub gid: usize, 730 731 /// 文件指向的设备的id(对于设备文件系统来说) 732 pub raw_dev: DeviceNumber, 733 } 734 735 impl Default for Metadata { 736 fn default() -> Self { 737 return Self { 738 dev_id: 0, 739 inode_id: InodeId::new(0), 740 size: 0, 741 blk_size: 0, 742 blocks: 0, 743 atime: PosixTimeSpec::default(), 744 mtime: PosixTimeSpec::default(), 745 ctime: PosixTimeSpec::default(), 746 file_type: FileType::File, 747 mode: ModeType::empty(), 748 nlinks: 1, 749 uid: 0, 750 gid: 0, 751 raw_dev: DeviceNumber::default(), 752 }; 753 } 754 } 755 756 #[derive(Debug, Clone)] 757 pub struct SuperBlock { 758 // type of filesystem 759 pub magic: Magic, 760 // optimal transfer block size 761 pub bsize: u64, 762 // total data blocks in filesystem 763 pub blocks: u64, 764 // free block in system 765 pub bfree: u64, 766 // 可供非特权用户使用的空闲块 767 pub bavail: u64, 768 // total inodes in filesystem 769 pub files: u64, 770 // free inodes in filesystem 771 pub ffree: u64, 772 // filesysytem id 773 pub fsid: u64, 774 // Max length of filename 775 pub namelen: u64, 776 // fragment size 777 pub frsize: u64, 778 // mount flags of filesystem 779 pub flags: u64, 780 } 781 782 impl SuperBlock { 783 pub fn new(magic: Magic, bsize: u64, namelen: u64) -> Self { 784 Self { 785 magic, 786 bsize, 787 blocks: 0, 788 bfree: 0, 789 bavail: 0, 790 files: 0, 791 ffree: 0, 792 fsid: 0, 793 namelen, 794 frsize: 0, 795 flags: 0, 796 } 797 } 798 } 799 bitflags! { 800 pub struct Magic: u64 { 801 const DEVFS_MAGIC = 0x1373; 802 const FAT_MAGIC = 0xf2f52011; 803 const KER_MAGIC = 0x3153464b; 804 const PROC_MAGIC = 0x9fa0; 805 const RAMFS_MAGIC = 0x858458f6; 806 const MOUNT_MAGIC = 61267; 807 } 808 } 809 810 /// @brief 所有文件系统都应该实现的trait 811 pub trait FileSystem: Any + Sync + Send + Debug { 812 /// @brief 获取当前文件系统的root inode的指针 813 fn root_inode(&self) -> Arc<dyn IndexNode>; 814 815 /// @brief 获取当前文件系统的信息 816 fn info(&self) -> FsInfo; 817 818 /// @brief 本函数用于实现动态转换。 819 /// 具体的文件系统在实现本函数时,最简单的方式就是:直接返回self 820 fn as_any_ref(&self) -> &dyn Any; 821 822 fn name(&self) -> &str; 823 824 fn super_block(&self) -> SuperBlock; 825 826 unsafe fn fault(&self, _pfm: &mut PageFaultMessage) -> VmFaultReason { 827 panic!( 828 "fault() has not yet been implemented for filesystem: {}", 829 crate::libs::name::get_type_name(&self) 830 ) 831 } 832 833 unsafe fn map_pages( 834 &self, 835 _pfm: &mut PageFaultMessage, 836 _start_pgoff: usize, 837 _end_pgoff: usize, 838 ) -> VmFaultReason { 839 panic!( 840 "map_pages() has not yet been implemented for filesystem: {}", 841 crate::libs::name::get_type_name(&self) 842 ) 843 } 844 } 845 846 impl DowncastArc for dyn FileSystem { 847 fn as_any_arc(self: Arc<Self>) -> Arc<dyn Any> { 848 self 849 } 850 } 851 852 #[derive(Debug)] 853 pub struct FsInfo { 854 /// 文件系统所在的块设备的id 855 pub blk_dev_id: usize, 856 /// 文件名的最大长度 857 pub max_name_len: usize, 858 } 859 860 /// @brief 861 #[repr(C)] 862 #[derive(Debug)] 863 pub struct Dirent { 864 d_ino: u64, // 文件序列号 865 d_off: i64, // dir偏移量 866 d_reclen: u16, // 目录下的记录数 867 d_type: u8, // entry的类型 868 d_name: u8, // 文件entry的名字(是一个零长数组), 本字段仅用于占位 869 } 870 871 impl Metadata { 872 pub fn new(file_type: FileType, mode: ModeType) -> Self { 873 Metadata { 874 dev_id: 0, 875 inode_id: generate_inode_id(), 876 size: 0, 877 blk_size: 0, 878 blocks: 0, 879 atime: PosixTimeSpec::default(), 880 mtime: PosixTimeSpec::default(), 881 ctime: PosixTimeSpec::default(), 882 file_type, 883 mode, 884 nlinks: 1, 885 uid: 0, 886 gid: 0, 887 raw_dev: DeviceNumber::default(), 888 } 889 } 890 } 891 pub struct FileSystemMaker { 892 function: &'static FileSystemNewFunction, 893 name: &'static str, 894 } 895 896 impl FileSystemMaker { 897 pub const fn new( 898 name: &'static str, 899 function: &'static FileSystemNewFunction, 900 ) -> FileSystemMaker { 901 FileSystemMaker { function, name } 902 } 903 904 pub fn call(&self) -> Result<Arc<dyn FileSystem>, SystemError> { 905 (self.function)() 906 } 907 } 908 909 pub type FileSystemNewFunction = fn() -> Result<Arc<dyn FileSystem>, SystemError>; 910 911 #[macro_export] 912 macro_rules! define_filesystem_maker_slice { 913 ($name:ident) => { 914 #[::linkme::distributed_slice] 915 pub static $name: [FileSystemMaker] = [..]; 916 }; 917 () => { 918 compile_error!("define_filesystem_maker_slice! requires at least one argument: slice_name"); 919 }; 920 } 921 922 /// 调用指定数组中的所有初始化器 923 #[macro_export] 924 macro_rules! producefs { 925 ($initializer_slice:ident,$filesystem:ident) => { 926 match $initializer_slice.iter().find(|&m| m.name == $filesystem) { 927 Some(maker) => maker.call(), 928 None => { 929 log::error!("mismatch filesystem type : {}", $filesystem); 930 Err(SystemError::EINVAL) 931 } 932 } 933 }; 934 } 935 936 define_filesystem_maker_slice!(FSMAKER); 937