From df37b1f634a36bae00b32f48ff601024eb9820d5 Mon Sep 17 00:00:00 2001 From: 4lDO2 <4ldo2@protonmail.com> Date: Mon, 11 Apr 2022 21:09:08 +0000 Subject: [PATCH] External initfs --- Cargo.lock | 17 ++- Cargo.toml | 1 + build.rs | 133 ------------------- src/arch/x86_64/rmm.rs | 68 +++++----- src/arch/x86_64/start.rs | 13 +- src/lib.rs | 2 - src/scheme/initfs.rs | 278 +++++++++++++++++++++++++++++---------- src/scheme/mod.rs | 2 +- 8 files changed, 265 insertions(+), 249 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index e2a8e4d..8781c1d 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -76,6 +76,7 @@ dependencies = [ "log", "memoffset", "raw-cpuid", + "redox-initfs", "redox_syscall", "rmm", "rustc-cfg", @@ -114,9 +115,9 @@ dependencies = [ [[package]] name = "log" -version = "0.4.14" +version = "0.4.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "51b9bbe6c47d51fc3e1a9b945965946b4c44142ab8792c50835a980d362c2710" +checksum = "6389c490849ff5bc16be905ae24bc913a9c8892e19b2341dbc175e14c341c2b8" dependencies = [ "cfg-if", ] @@ -138,13 +139,21 @@ checksum = "b4596b6d070b27117e987119b4dac604f3c58cfb0b191112e24771b2faeac1a6" [[package]] name = "raw-cpuid" -version = "10.2.0" +version = "10.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "929f54e29691d4e6a9cc558479de70db7aa3d98cd6fe7ab86d7507aa2886b9d2" +checksum = "738bc47119e3eeccc7e94c4a506901aea5e7b4944ecd0829cbebf4af04ceda12" dependencies = [ "bitflags", ] +[[package]] +name = "redox-initfs" +version = "0.1.0" +source = "git+https://gitlab.redox-os.org/redox-os/redox-initfs.git#89b8fb8984cf96c418880b7dcd9ce3d6afc3f71c" +dependencies = [ + "plain", +] + [[package]] name = "redox_syscall" version = "0.2.12" diff --git a/Cargo.toml b/Cargo.toml index 6745c0e..72b3b72 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -24,6 +24,7 @@ slab_allocator = { path = "slab_allocator", optional = true } # FIXME: There is some undefined behavior probably in the kernel, which forces us to use spin 0.9.0 and not 0.9.2. spin = "=0.9.0" rmm = { path = "rmm", default-features = false } +redox-initfs = { git = "https://gitlab.redox-os.org/redox-os/redox-initfs.git", features = ["kernel"], default-features = false } [dependencies.goblin] version = "0.2.1" diff --git a/build.rs b/build.rs index 249c9e3..678a40d 100644 --- a/build.rs +++ b/build.rs @@ -1,96 +1,5 @@ use rustc_cfg::Cfg; -use std::collections::HashMap; use std::env; -use std::fs; -use std::io::{Error, Write}; -use std::path::Path; - -// View loc folder with subfolders, get listings -// Returns touple (folder_map, file_list) -// folder_map keys are folders, and values are lists of direct childs -// file_list is a vector of all detected files with full path -fn scan_folder(loc: &Path) -> (HashMap>, Vec) { - let mut folders: HashMap> = HashMap::new(); - let mut files: Vec = Vec::new(); - let mut current = Vec::new(); - - if loc.is_dir() { - for entry in fs::read_dir(loc).unwrap() { - let entry = entry.unwrap(); - let path = entry.path(); - let path_str = String::from(path.to_str().unwrap()).replace("\\", "/"); - - current.push(path_str.clone()); - - // if folder then scan recursively - if path.is_dir() { - let (d, mut f) = scan_folder(&path); - for (key, value) in d.into_iter() { - folders.insert(key, value); - } - - files.append(&mut f); - } else { - files.push(path_str); - } - } - - current.sort(); - folders - .entry(String::from(loc.to_str().unwrap()).replace("\\", "/")) - .or_insert(current); - } else { - panic!("{:?} is not a folder!", loc); - } - - (folders, files) -} - -// Write folder/file information to output file -fn fill_from_location(f: &mut fs::File, loc: &Path) -> Result<(), Error> { - let (folders, mut files) = scan_folder(loc); - let mut folder_it: Vec<_> = folders.keys().collect(); - - let loc_str = loc.to_str().unwrap(); - let mut idx = loc_str.len(); - - if !loc_str.ends_with("/") { - idx += 1; - } - - folder_it.sort(); - files.sort(); - for dir in folder_it.iter() { - let strip: String = dir.chars().skip(idx).collect(); - write!(f, " files.insert(b\"{}\", (b\"", strip)?; - - // Write child elements separated with \n - let sub = folders.get(*dir).unwrap(); - let mut first = true; - for child in sub.iter() { - let idx = child.rfind('/').unwrap() + 1; - let (_, c) = child.split_at(idx); - if first { - write!(f, "{}", c)?; - first = false; - } else { - write!(f, "\\n{}", c)?; - } - } - write!(f, "\", true));\n")?; - } - - for name in files.iter() { - let (_, strip) = name.split_at(idx); - write!( - f, - " files.insert(b\"{}\", (include_bytes!(\"{}\"), false));\n", - strip, name - )?; - } - - Ok(()) -} #[cfg(not(target_arch = "x86_64"))] fn asm(_out_dir: &str) {} @@ -114,52 +23,10 @@ fn asm(out_dir: &str) { fn main() { println!("cargo:rustc-env=TARGET={}", env::var("TARGET").unwrap()); - println!("cargo:rerun-if-env-changed=INITFS_FOLDER"); let out_dir = env::var("OUT_DIR").unwrap(); - let dest_path = Path::new(&out_dir).join("gen.rs"); - let mut f = fs::File::create(&dest_path).unwrap(); - let src = env::var("INITFS_FOLDER"); - asm(&out_dir); - // Write header - f.write_all( - b" -mod gen { - use alloc::collections::BTreeMap; - pub fn gen() -> BTreeMap<&'static [u8], (&'static [u8], bool)> { - let mut files: BTreeMap<&'static [u8], (&'static [u8], bool)> = BTreeMap::new(); -", - ) - .unwrap(); - - match src { - Ok(v) => { - println!("cargo:rerun-if-changed={}", v); - fill_from_location(&mut f, Path::new(&v)).unwrap() - } - Err(e) => { - f.write_all( - b" files.clear();", // Silence mutability warning - ) - .unwrap(); - println!( - "cargo:warning=location not found: {}, please set proper INITFS_FOLDER.", - e - ); - } - } - - f.write_all( - b" - files - } -} -", - ) - .unwrap(); - // Build pre kstart init asm code for aarch64 let cfg = Cfg::new(env::var_os("TARGET").unwrap()).unwrap(); if cfg.target_arch == "aarch64" { diff --git a/src/arch/x86_64/rmm.rs b/src/arch/x86_64/rmm.rs index ed7e8ce..11eb527 100644 --- a/src/arch/x86_64/rmm.rs +++ b/src/arch/x86_64/rmm.rs @@ -80,7 +80,8 @@ unsafe fn inner( kernel_base: usize, kernel_size_aligned: usize, stack_base: usize, stack_size_aligned: usize, env_base: usize, env_size_aligned: usize, - acpi_base: usize, acpi_size_aligned: usize + acpi_base: usize, acpi_size_aligned: usize, + initfs_base: usize, initfs_size_aligned: usize, ) -> BuddyAllocator { // First, calculate how much memory we have let mut size = 0; @@ -137,44 +138,26 @@ unsafe fn inner( flush.ignore(); // Not the active table } - // Map stack with identity mapping - for i in 0..stack_size_aligned / A::PAGE_SIZE { - let phys = PhysicalAddress::new(stack_base + i * A::PAGE_SIZE); - let virt = A::phys_to_virt(phys); - let flags = page_flags::(virt); - let flush = mapper.map_phys( - virt, - phys, - flags - ).expect("failed to map frame"); - flush.ignore(); // Not the active table - } + let mut identity_map = |base, size_aligned| { + // Map stack with identity mapping + for i in 0..size / A::PAGE_SIZE { + let phys = PhysicalAddress::new(base + i * A::PAGE_SIZE); + let virt = A::phys_to_virt(phys); + let flags = page_flags::(virt); + let flush = mapper.map_phys( + virt, + phys, + flags + ).expect("failed to map frame"); + flush.ignore(); // Not the active table + } + }; - // Map env with identity mapping - for i in 0..env_size_aligned / A::PAGE_SIZE { - let phys = PhysicalAddress::new(env_base + i * A::PAGE_SIZE); - let virt = A::phys_to_virt(phys); - let flags = page_flags::(virt); - let flush = mapper.map_phys( - virt, - phys, - flags - ).expect("failed to map frame"); - flush.ignore(); // Not the active table - } - // Map acpi with identity mapping - for i in 0..acpi_size_aligned / A::PAGE_SIZE { - let phys = PhysicalAddress::new(acpi_base + i * A::PAGE_SIZE); - let virt = A::phys_to_virt(phys); - let flags = page_flags::(virt); - let flush = mapper.map_phys( - virt, - phys, - flags - ).expect("failed to map frame"); - flush.ignore(); // Not the active table - } + identity_map(stack_base, stack_size_aligned); + identity_map(env_base, env_size_aligned); + identity_map(acpi_base, acpi_size_aligned); + identity_map(initfs_base, initfs_size_aligned); // Ensure graphical debug region remains paged #[cfg(feature = "graphical_debug")] @@ -289,6 +272,7 @@ pub unsafe fn init( env_base: usize, env_size: usize, acpi_base: usize, acpi_size: usize, areas_base: usize, areas_size: usize, + initfs_base: usize, initfs_size: usize, ) { type A = RmmA; @@ -308,6 +292,9 @@ pub unsafe fn init( let acpi_size_aligned = ((acpi_size + (A::PAGE_SIZE - 1))/A::PAGE_SIZE) * A::PAGE_SIZE; let acpi_end = acpi_base + acpi_size_aligned; + let initfs_size_aligned = ((initfs_size + (A::PAGE_SIZE - 1))/A::PAGE_SIZE) * A::PAGE_SIZE; + let initfs_end = initfs_base + initfs_size_aligned; + let bootloader_areas = slice::from_raw_parts( areas_base as *const BootloaderMemoryEntry, areas_size / mem::size_of::() @@ -370,6 +357,10 @@ pub unsafe fn init( log::warn!("{:X}:{:X} overlaps with acpi {:X}:{:X}", base, size, acpi_base, acpi_size); new_base = cmp::max(new_base, acpi_end); } + if base < initfs_end && base + size > initfs_base { + log::warn!("{:X}:{:X} overlaps with initfs {:X}:{:X}", base, size, initfs_base, initfs_size); + new_base = cmp::max(new_base, initfs_end); + } if new_base != base { let end = base + size; @@ -394,7 +385,8 @@ pub unsafe fn init( kernel_base, kernel_size_aligned, stack_base, stack_size_aligned, env_base, env_size_aligned, - acpi_base, acpi_size_aligned + acpi_base, acpi_size_aligned, + initfs_base, initfs_size_aligned, ); *FRAME_ALLOCATOR.inner.lock() = Some(allocator); } diff --git a/src/arch/x86_64/start.rs b/src/arch/x86_64/start.rs index 33b30a5..f7e5225 100644 --- a/src/arch/x86_64/start.rs +++ b/src/arch/x86_64/start.rs @@ -52,13 +52,17 @@ pub struct KernelArgs { /// /// This field can be NULL, and if so, the system has not booted with UEFI or in some other way /// retrieved the RSDPs. The kernel or a userspace driver will thus try searching the BIOS - /// memory instead. On UEFI systems, searching is not guaranteed to actually work though. + /// memory instead. On UEFI systems, BIOS-like searching is not guaranteed to actually work though. acpi_rsdps_base: u64, /// The size of the RSDPs region. acpi_rsdps_size: u64, areas_base: u64, areas_size: u64, + + /// The physical base 64-bit pointer to the contiguous initfs. + initfs_base: u64, + initfs_size: u64, } /// The entry to Rust, all things must be initialized @@ -77,6 +81,8 @@ pub unsafe extern fn kstart(args_ptr: *const KernelArgs) -> ! { let acpi_rsdps_size = args.acpi_rsdps_size; let areas_base = args.areas_base as usize; let areas_size = args.areas_size as usize; + let initfs_base = args.initfs_base as usize; + let initfs_size = args.initfs_size as usize; // BSS should already be zero { @@ -89,6 +95,7 @@ pub unsafe extern fn kstart(args_ptr: *const KernelArgs) -> ! { // Convert env to slice let env = slice::from_raw_parts((env_base + crate::PHYS_OFFSET) as *const u8, env_size); + let initfs = slice::from_raw_parts((initfs_base + crate::PHYS_OFFSET) as *const u8, initfs_size); // Set up graphical debug #[cfg(feature = "graphical_debug")] @@ -115,6 +122,7 @@ pub unsafe extern fn kstart(args_ptr: *const KernelArgs) -> ! { info!("Env: {:X}:{:X}", env_base, env_base + env_size); info!("RSDPs: {:X}:{:X}", acpi_rsdps_base, acpi_rsdps_base + acpi_rsdps_size); info!("Areas: {:X}:{:X}", areas_base, areas_base + areas_size); + info!("Initfs: {:X}:{:X}", initfs_base, initfs_base + initfs_size); // Set up GDT before paging gdt::init(); @@ -129,6 +137,7 @@ pub unsafe extern fn kstart(args_ptr: *const KernelArgs) -> ! { env_base, env_size, acpi_rsdps_base as usize, acpi_rsdps_size as usize, areas_base, areas_size, + initfs_base, initfs_size, ); // Initialize paging @@ -187,6 +196,8 @@ pub unsafe extern fn kstart(args_ptr: *const KernelArgs) -> ! { // Initialize all of the non-core devices not otherwise needed to complete initialization device::init_noncore(); + crate::scheme::initfs::init(initfs); + // Stop graphical debug #[cfg(feature = "graphical_debug")] graphical_debug::fini(); diff --git a/src/lib.rs b/src/lib.rs index a66a4ab..b174389 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -177,8 +177,6 @@ pub extern fn userspace_init() { if let Err(err) = syscall::chdir("initfs:") { info!("Failed to enter initfs ({}).", err); - info!("Perhaps the kernel was compiled with an incorrect INITFS_FOLDER \ - environment variable value?"); panic!("Unexpected error while trying to enter initfs:."); } diff --git a/src/scheme/initfs.rs b/src/scheme/initfs.rs index 80a557d..4c7f3a5 100644 --- a/src/scheme/initfs.rs +++ b/src/scheme/initfs.rs @@ -1,137 +1,275 @@ -use alloc::collections::BTreeMap; +use core::convert::TryFrom; use core::str; use core::sync::atomic::{AtomicUsize, Ordering}; -use spin::RwLock; + +use alloc::collections::BTreeMap; +use alloc::string::String; +use alloc::vec::Vec; + +use spin::{Once, RwLock}; + +use redox_initfs::{InitFs, InodeStruct, Inode, InodeDir, InodeKind, types::Timespec}; use crate::syscall::data::Stat; use crate::syscall::error::*; use crate::syscall::flag::{MODE_DIR, MODE_FILE}; use crate::syscall::scheme::{calc_seek_offset_usize, Scheme}; -#[cfg(test)] -mod gen { - use alloc::collections::BTreeMap; - pub fn gen() -> BTreeMap<&'static [u8], (&'static [u8], bool)> { BTreeMap::new() } -} - -#[cfg(not(test))] -include!(concat!(env!("OUT_DIR"), "/gen.rs")); - struct Handle { - path: &'static [u8], - data: &'static [u8], - mode: u16, - seek: usize + inode: Inode, + seek: usize, + // TODO: Any better way to implement fpath? Or maybe work around it, e.g. by giving paths such + // as `initfs:__inodes__/`? + filename: String, } -pub struct InitFsScheme { - next_id: AtomicUsize, - files: BTreeMap<&'static [u8], (&'static [u8], bool)>, - handles: RwLock> +static NEXT_ID: AtomicUsize = AtomicUsize::new(0); +static HANDLES: RwLock> = RwLock::new(BTreeMap::new()); + +static FS: Once> = Once::new(); + +fn fs() -> Result> { + FS.get().copied().ok_or(Error::new(ENODEV)) +} +fn get_inode(inode: Inode) -> Result> { + fs()?.get_inode(inode).ok_or_else(|| Error::new(EIO)) } -impl InitFsScheme { - pub fn new() -> InitFsScheme { - InitFsScheme { - next_id: AtomicUsize::new(0), - files: gen::gen(), - handles: RwLock::new(BTreeMap::new()) +pub fn init(bytes: &'static [u8]) { + let mut called = false; + + FS.call_once(|| { + called = true; + + InitFs::new(bytes) + .expect("failed to parse initfs header") + }); + + assert!(called, "called initfs::init more than once"); +} + +fn next_id() -> usize { + let old = NEXT_ID.fetch_add(1, Ordering::Relaxed); + assert_ne!(old, usize::MAX, "usize overflow in initfs scheme"); + old +} + +pub struct InitFsScheme; + +struct Iter { + dir: InodeDir<'static>, + idx: u32, +} +impl Iterator for Iter { + type Item = Result>; + + fn next(&mut self) -> Option { + let entry = self.dir.get_entry(self.idx).map_err(|_| Error::new(EIO)); + self.idx += 1; + entry.transpose() + } + fn size_hint(&self) -> (usize, Option) { + match self.dir.entry_count().ok() { + Some(size) => { + let size = usize::try_from(size).expect("expected u32 to be convertible into usize"); + (size, Some(size)) + } + None => (0, None), } } } +fn entries_iter(dir: InodeDir<'static>) -> impl IntoIterator>> + 'static { + let mut index = 0_u32; + + core::iter::from_fn(move || { + let idx = index; + index += 1; + + dir.get_entry(idx).map_err(|_| Error::new(EIO)).transpose() + }) +} +fn inode_len(inode: InodeStruct<'static>) -> Result { + Ok(match inode.kind() { + InodeKind::File(file) => file.data().map_err(|_| Error::new(EIO))?.len(), + InodeKind::Dir(dir) => (Iter { dir, idx: 0 }) + .fold(0, |len, entry| len + entry.and_then(|entry| entry.name().map_err(|_| Error::new(EIO))).map_or(0, |name| name.len() + 1)), + InodeKind::Unknown => return Err(Error::new(EIO)), + }) +} + impl Scheme for InitFsScheme { fn open(&self, path: &str, _flags: usize, _uid: u32, _gid: u32) -> Result { - let path_trimmed = path.trim_matches('/'); + let mut components = path + // trim leading and trailing slash + .trim_matches('/') + // divide into components + .split('/') + // filter out double slashes (e.g. /usr//bin/...) + .filter(|c| !c.is_empty()); - //Have to iterate to get the path without allocation - for entry in self.files.iter() { - if entry.0 == &path_trimmed.as_bytes() { - let id = self.next_id.fetch_add(1, Ordering::SeqCst); - self.handles.write().insert(id, Handle { - path: entry.0, - data: (entry.1).0, - mode: if (entry.1).1 { MODE_DIR | 0o755 } else { MODE_FILE | 0o744 }, - seek: 0 - }); + let mut current_inode = InitFs::ROOT_INODE; - return Ok(id); + while let Some(component) = components.next() { + match component { + "." => continue, + ".." => { + let _ = components.next_back(); + continue + } + + _ => (), } + + let current_inode_struct = get_inode(current_inode)?; + + let dir = match current_inode_struct.kind() { + InodeKind::Dir(dir) => dir, + + // If we still have more components in the path, and the file tree for that + // particular branch is not all directories except the last, then that file cannot + // exist. + InodeKind::File(_) | InodeKind::Unknown => return Err(Error::new(ENOENT)), + }; + + let mut entries = Iter { + dir, + idx: 0, + }; + + current_inode = loop { + let entry_res = match entries.next() { + Some(e) => e, + None => return Err(Error::new(ENOENT)), + }; + let entry = entry_res?; + let name = entry.name().map_err(|_| Error::new(EIO))?; + if name == component.as_bytes() { + break entry.inode(); + } + }; } - Err(Error::new(ENOENT)) + let id = next_id(); + let old = HANDLES.write().insert(id, Handle { + inode: current_inode, + seek: 0_usize, + filename: path.into(), + }); + assert!(old.is_none()); + + Ok(id) } fn read(&self, id: usize, buffer: &mut [u8]) -> Result { - let mut handles = self.handles.write(); + let mut handles = HANDLES.write(); let handle = handles.get_mut(&id).ok_or(Error::new(EBADF))?; - let mut i = 0; - while i < buffer.len() && handle.seek < handle.data.len() { - buffer[i] = handle.data[handle.seek]; - i += 1; - handle.seek += 1; - } + match get_inode(handle.inode)?.kind() { + InodeKind::Dir(dir) => { + let mut bytes_read = 0; + let mut bytes_skipped = 0; - Ok(i) + for entry_res in (Iter { dir, idx: 0 }) { + let entry = entry_res?; + let name = entry.name().map_err(|_| Error::new(EIO))?; + let entry_len = name.len() + 1; + + let to_skip = core::cmp::min(handle.seek - bytes_skipped, entry_len); + let max_to_read = core::cmp::min(entry_len - to_skip, buffer.len()); + + let to_copy = entry_len.saturating_sub(to_skip).saturating_sub(1); + buffer[bytes_read..bytes_read + to_copy].copy_from_slice(&name[..to_copy]); + + if to_copy.saturating_sub(to_skip) == 1 { + buffer[bytes_read + to_copy] = b'\n'; + bytes_read += 1; + } + + bytes_read += to_copy; + bytes_skipped += to_skip; + } + + handle.seek = handle.seek.checked_add(bytes_read).ok_or(Error::new(EOVERFLOW))?; + + Ok(bytes_read) + } + InodeKind::File(file) => { + let data = file.data().map_err(|_| Error::new(EIO))?; + let src_buf = &data[core::cmp::min(handle.seek, data.len())..]; + + let to_copy = core::cmp::min(src_buf.len(), buffer.len()); + buffer[..to_copy].copy_from_slice(&src_buf[..to_copy]); + + handle.seek = handle.seek.checked_add(to_copy).ok_or(Error::new(EOVERFLOW))?; + + Ok(to_copy) + } + InodeKind::Unknown => return Err(Error::new(EIO)), + } } fn seek(&self, id: usize, pos: isize, whence: usize) -> Result { - let mut handles = self.handles.write(); + let mut handles = HANDLES.write(); let handle = handles.get_mut(&id).ok_or(Error::new(EBADF))?; - let new_offset = calc_seek_offset_usize(handle.seek, pos, whence, handle.data.len())?; + + let new_offset = calc_seek_offset_usize(handle.seek, pos, whence, inode_len(get_inode(handle.inode)?)?)?; handle.seek = new_offset as usize; Ok(new_offset) } fn fcntl(&self, id: usize, _cmd: usize, _arg: usize) -> Result { - let handles = self.handles.read(); + let handles = HANDLES.read(); let _handle = handles.get(&id).ok_or(Error::new(EBADF))?; Ok(0) } fn fpath(&self, id: usize, buf: &mut [u8]) -> Result { - let handles = self.handles.read(); + let handles = HANDLES.read(); let handle = handles.get(&id).ok_or(Error::new(EBADF))?; - //TODO: Copy scheme part in kernel - let mut i = 0; + // TODO: Copy scheme part in kernel let scheme_path = b"initfs:"; - while i < buf.len() && i < scheme_path.len() { - buf[i] = scheme_path[i]; - i += 1; - } + let scheme_bytes = core::cmp::min(scheme_path.len(), buf.len()); + buf[..scheme_bytes].copy_from_slice(&scheme_path[..scheme_bytes]); - let mut j = 0; - while i < buf.len() && j < handle.path.len() { - buf[i] = handle.path[j]; - i += 1; - j += 1; - } + let source = handle.filename.as_bytes(); + let path_bytes = core::cmp::min(buf.len() - scheme_bytes, source.len()); + buf[scheme_bytes..scheme_bytes + path_bytes].copy_from_slice(&source[..path_bytes]); - Ok(i) + Ok(scheme_bytes + path_bytes) } fn fstat(&self, id: usize, stat: &mut Stat) -> Result { - let handles = self.handles.read(); + let handles = HANDLES.read(); let handle = handles.get(&id).ok_or(Error::new(EBADF))?; - stat.st_mode = handle.mode; - stat.st_uid = 0; - stat.st_gid = 0; - stat.st_size = handle.data.len() as u64; + let Timespec { sec, nsec } = fs()?.image_creation_time(); + + let inode = get_inode(handle.inode)?; + + stat.st_mode = inode.mode() | match inode.kind() { InodeKind::Dir(_) => MODE_DIR, InodeKind::File(_) => MODE_FILE, _ => 0 }; + stat.st_uid = inode.uid(); + stat.st_gid = inode.gid(); + stat.st_size = u64::try_from(inode_len(inode)?).unwrap_or(u64::MAX); + + stat.st_ctime = sec.get(); + stat.st_ctime_nsec = nsec.get(); + stat.st_mtime = sec.get(); + stat.st_mtime_nsec = nsec.get(); Ok(0) } fn fsync(&self, id: usize) -> Result { - let handles = self.handles.read(); + let handles = HANDLES.read(); let _handle = handles.get(&id).ok_or(Error::new(EBADF))?; Ok(0) } fn close(&self, id: usize) -> Result { - self.handles.write().remove(&id).ok_or(Error::new(EBADF)).and(Ok(0)) + let _ = HANDLES.write().remove(&id).ok_or(Error::new(EBADF))?; + Ok(0) } } diff --git a/src/scheme/mod.rs b/src/scheme/mod.rs index f54b445..f8f1a1b 100644 --- a/src/scheme/mod.rs +++ b/src/scheme/mod.rs @@ -165,7 +165,7 @@ impl SchemeList { self.insert(ns, "kernel/acpi", |scheme_id| Arc::new(AcpiScheme::new(scheme_id))).unwrap(); } self.insert(ns, "debug", |scheme_id| Arc::new(DebugScheme::new(scheme_id))).unwrap(); - self.insert(ns, "initfs", |_| Arc::new(InitFsScheme::new())).unwrap(); + self.insert(ns, "initfs", |_| Arc::new(InitFsScheme)).unwrap(); self.insert(ns, "irq", |scheme_id| Arc::new(IrqScheme::new(scheme_id))).unwrap(); self.insert(ns, "proc", |scheme_id| Arc::new(ProcScheme::new(scheme_id))).unwrap(); self.insert(ns, "thisproc", |_| Arc::new(ProcScheme::restricted())).unwrap();