//! VFS + ramfs, used directly from the kernel (no user mode involved). #![no_std] #![no_main] #![feature(custom_test_frameworks)] #![test_runner(rust_kernel::test_runner)] #![reexport_test_harness_main = "test_main"] extern crate alloc; use alloc::{string::String, vec}; use bootloader::{BootInfo, entry_point}; use core::panic::PanicInfo; use rust_kernel::errno::Errno; use rust_kernel::fs::file::{File, InodeFile}; use rust_kernel::fs::{self, InodeKind, ramfs::RamFs}; use rust_kernel::memory::{self, BootInfoFrameAllocator}; use rust_kernel::allocator; use x86_64::VirtAddr; entry_point!(main); fn main(boot_info: &'static BootInfo) -> ! { rust_kernel::init(); let phys_mem_offset = VirtAddr::new(boot_info.physical_memory_offset); let mut mapper = unsafe { memory::init(phys_mem_offset) }; let mut frame_allocator = unsafe { BootInfoFrameAllocator::init(&boot_info.memory_map) }; allocator::init_heap(&mut mapper, &mut frame_allocator).expect("heap initialization failed"); fs::init(); test_main(); rust_kernel::hlt_loop(); } #[test_case] fn read_boot_files() { let file = InodeFile::open(fs::lookup("/hello.txt").unwrap()).unwrap(); let mut buf = [0u8; 64]; let n = file.read(&mut buf).unwrap(); assert!(buf[..n].starts_with(b"Hello from the ramfs!")); assert_eq!(file.read(&mut buf), Ok(0)); // EOF assert_eq!(fs::lookup("/etc/motd").unwrap().kind(), InodeKind::File); assert_eq!(fs::lookup("/etc").unwrap().kind(), InodeKind::Directory); assert_eq!(fs::lookup("//etc/./motd").unwrap().kind(), InodeKind::File); } #[test_case] fn lookup_errors() { assert_eq!(fs::lookup("/nope").err(), Some(Errno::ENOENT)); assert_eq!(fs::lookup("/hello.txt/x").err(), Some(Errno::ENOTDIR)); assert_eq!(fs::lookup("relative").err(), Some(Errno::EINVAL)); assert_eq!(InodeFile::open(fs::lookup("/etc").unwrap()).err(), Some(Errno::EISDIR)); } #[test_case] fn mounts_are_separate_file_systems() { // /tmp is its own ramfs: files created there don't show up in "/"'s tmp dir. fs::create("/tmp/a.txt", InodeKind::File).unwrap(); assert!(fs::lookup("/tmp/a.txt").is_ok()); let root_tmp_dir = fs::lookup("/").unwrap().lookup("tmp").unwrap(); assert_eq!(root_tmp_dir.list().unwrap().len(), 0); assert_eq!(fs::create("/tmp/a.txt", InodeKind::File).err(), Some(Errno::EEXIST)); // Mount a third one; the longest matching mount point wins. fs::create("/tmp/deeper", InodeKind::Directory).unwrap(); fs::mount("/tmp/deeper", RamFs::new()).unwrap(); assert_eq!(fs::lookup("/tmp/deeper").unwrap().list().unwrap().len(), 0); assert_eq!(fs::mount("/tmp/deeper", RamFs::new()).err(), Some(Errno::EEXIST)); assert_eq!(fs::mounts().len(), 3); } #[test_case] fn write_grow_and_list() { let inode = fs::create("/tmp/grow.bin", InodeKind::File).unwrap(); inode.write_at(4, b"abc").unwrap(); // gap is filled with zeros let mut buf = vec![0xffu8; 10]; assert_eq!(inode.read_at(0, &mut buf), Ok(7)); assert_eq!(&buf[..7], b"\0\0\0\0abc"); let names = fs::lookup("/").unwrap().list().unwrap(); assert_eq!(names, vec![String::from("etc"), String::from("hello.txt"), String::from("tmp")]); } #[panic_handler] fn panic(info: &PanicInfo) -> ! { rust_kernel::test_panic_handler(info) }