diff --git a/Cargo.lock b/Cargo.lock index cdeae99868..0fed4b0899 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2,12 +2,40 @@ # It is not intended for manual editing. version = 3 +[[package]] +name = "autocfg" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0c4b4d0bd25bd0b74681c0ad21497610ce1b7c91b1022cd21c80c6fbdd9476b0" + [[package]] name = "bitflags" version = "2.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b048fb63fd8b5923fc5aa7b340d8e156aec7ec02f0c78fa8a6ddc2613f6f71de" +[[package]] +name = "equivalent" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5" + +[[package]] +name = "hashbrown" +version = "0.14.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e5274423e17b7c9fc20b6e7e208532f9b19825d82dfd615708b70edd83df41f1" + +[[package]] +name = "indexmap" +version = "2.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "68b900aa2f7301e21c36462b170ee99994de34dff39a4a6a528e80e7376d07e5" +dependencies = [ + "equivalent", + "hashbrown", +] + [[package]] name = "libc" version = "0.2.158" @@ -29,10 +57,12 @@ dependencies = [ name = "ramfs" version = "0.1.0" dependencies = [ + "indexmap", "libredox", "redox-daemon", "redox-scheme", "redox_syscall", + "slab", ] [[package]] @@ -47,9 +77,9 @@ dependencies = [ [[package]] name = "redox-scheme" -version = "0.2.1" +version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2148c23b7ed5bf1cc3919b4830e4bf2a674a5d3691c619317624ccd78d13a3ac" +checksum = "98d040cfa6370d9c6b1a5987247272f19ea4722f1064e66ad2e077c152b82ea3" dependencies = [ "libredox", "redox_syscall", @@ -57,9 +87,18 @@ dependencies = [ [[package]] name = "redox_syscall" -version = "0.5.3" +version = "0.5.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2a908a6e00f1fdd0dfd9c0eb08ce85126f6d8bbda50017e74bc4a4b7d4a926a4" +checksum = "0884ad60e090bf1345b93da0a5de8923c93884cd03f40dfcfddd3b4bee661853" dependencies = [ "bitflags", ] + +[[package]] +name = "slab" +version = "0.4.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f92a496fb766b417c996b9c5e57daf2f7ad3b0bebe1ccfca4856390e3d3bb67" +dependencies = [ + "autocfg", +] diff --git a/Cargo.toml b/Cargo.toml index 517251bc61..b720c682ec 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -10,6 +10,8 @@ description = "In-memory filesystem for Redox, which is useful for early logging [dependencies] redox-daemon = "0.1.2" -redox_syscall = "0.5.1" -redox-scheme = "0.2.1" +redox_syscall = "0.5.3" +redox-scheme = "0.2.2" libredox = "0.1.3" +indexmap = "2.5.0" +slab = "0.4.9" diff --git a/src/filesystem.rs b/src/filesystem.rs index 29ac216817..ed180bd618 100644 --- a/src/filesystem.rs +++ b/src/filesystem.rs @@ -1,14 +1,12 @@ use std::collections::BTreeMap; use std::convert::TryInto; -use std::ffi::OsStr; use std::{fs, iter, time}; -use std::os::unix::ffi::OsStrExt; use std::os::unix::io::AsRawFd; +use indexmap::IndexMap; use syscall::error::{EACCES, EIO, ENFILE, ENOENT}; -use syscall::flag::{O_RDONLY, O_STAT}; -use syscall::{Error, Result, StatVfs, TimeSpec, MODE_DIR}; +use syscall::{Error, Result, TimeSpec, MODE_DIR}; use super::scheme::current_perm; @@ -17,7 +15,6 @@ pub struct File { pub mode: u16, pub uid: u32, pub gid: u32, - pub ino: usize, pub nlink: usize, pub open_handles: usize, @@ -31,33 +28,18 @@ pub struct File { } #[derive(Clone, Debug)] -pub struct DirEntry { - pub name: Vec, - pub inode: usize, -} +pub struct Inode(pub usize); #[derive(Debug)] pub enum FileData { File(Vec), - Directory(Vec), + Directory(IndexMap), } impl FileData { pub fn size(&self) -> usize { match self { &Self::File(ref data) => data.len(), - &Self::Directory(ref names) => names.iter().map(|dentry| dentry.name.len()).sum(), - } - } - pub fn as_directory(&self) -> Option<&[DirEntry]> { - match self { - &Self::Directory(ref inner) => Some(inner), - _ => None, - } - } - pub fn as_directory_mut(&mut self) -> Option<&mut Vec> { - match self { - &mut Self::Directory(ref mut inner) => Some(inner), - _ => None, + &Self::Directory(_) => 0, } } } @@ -87,14 +69,13 @@ impl Filesystem { mtime: cur_time, mode: MODE_DIR | 0o755, - ino: Self::ROOT_INODE, nlink: 1, open_handles: 0, uid: 0, gid: 0, - data: FileData::Directory(Vec::new()), + data: FileData::Directory(IndexMap::new()), } } pub fn get_block_size(&self) -> Result { @@ -111,7 +92,7 @@ impl Filesystem { self.last_inode_number = next; Ok(next) } - fn resolve_generic(&self, mut parts: Vec<&[u8]>, uid: u32, gid: u32) -> Result { + fn resolve_generic(&self, mut parts: Vec<&str>, uid: u32, gid: u32) -> Result { let mut current_file = self .files .get(&Self::ROOT_INODE) @@ -121,9 +102,8 @@ impl Filesystem { let mut i = 0; loop { - let part = match parts.get(i) { - Some(p) => p, - None => break, + let Some(&part) = parts.get(i) else { + break; }; let dentries = match current_file.data { FileData::Directory(ref dentries) => dentries, @@ -134,25 +114,19 @@ impl Filesystem { return Err(Error::new(EACCES)); } - if part == b"." || part == b".." { + if part == "." || part == ".." { parts.remove(i); } - let part = parts.get(i).unwrap(); - if part == b".." { - if i > 0 { - i -= 1; - parts.remove(i); - } + let part = *parts.get(i).unwrap(); + if part == ".." && i > 0 { + i -= 1; + parts.remove(i); } - let part = parts.get(i).unwrap(); + let part = *parts.get(i).unwrap(); - let entry = dentries - .iter() - .find(|dentry| &dentry.name == part) - .ok_or(Error::new(ENOENT))?; - current_file = self.files.get(&entry.inode).ok_or(Error::new(EIO))?; - current_inode = entry.inode; + current_inode = dentries.get(part).ok_or(Error::new(ENOENT))?.0; + current_file = self.files.get(¤t_inode).ok_or(Error::new(EIO))?; i += 1; } @@ -160,14 +134,11 @@ impl Filesystem { } pub fn resolve_except_last<'a>( &self, - mut path_bytes: &'a [u8], + path_bytes: &'a str, uid: u32, gid: u32, - ) -> Result<(usize, Option<&'a [u8]>)> { - if path_bytes.first() == Some(&b'/') { - path_bytes = &path_bytes[1..] - } - let mut parts = path_components_iter(path_bytes).collect::>(); + ) -> Result<(usize, Option<&'a str>)> { + let mut parts = path_components_iter(path_bytes.trim_start_matches('/')).collect::>(); let last = if parts.len() >= 1 { Some(parts.pop().unwrap()) @@ -177,17 +148,14 @@ impl Filesystem { Ok((self.resolve_generic(parts, uid, gid)?, last)) } - pub fn resolve(&self, mut path_bytes: &[u8], uid: u32, gid: u32) -> Result { - if path_bytes.first() == Some(&b'/') { - path_bytes = &path_bytes[1..] - } - let parts = path_components_iter(path_bytes).collect::>(); + pub fn resolve(&self, path: &str, uid: u32, gid: u32) -> Result { + let parts = path_components_iter(path.trim_start_matches('/')).collect::>(); self.resolve_generic(parts, uid, gid) } } -pub fn path_components_iter(bytes: &[u8]) -> impl Iterator + '_ { - let components_iter = bytes.split(|c| c == &b'/'); +pub fn path_components_iter(bytes: &str) -> impl Iterator + '_ { + let components_iter = bytes.split(|c| c == '/'); components_iter.filter(|item| !item.is_empty()) } pub fn current_time() -> TimeSpec { @@ -196,7 +164,7 @@ pub fn current_time() -> TimeSpec { let duration = match sys_time.duration_since(time::SystemTime::UNIX_EPOCH) { Ok(d) => d, Err(e) => { - eprintln!("Apparently the signed 32-bit integer has overflowed; the time is now before the Unix epoch..."); + eprintln!("The time is apparently now before the Unix epoch..."); let negative_duration = e.duration(); diff --git a/src/main.rs b/src/main.rs index 20ad47d17f..b95ec68d9a 100644 --- a/src/main.rs +++ b/src/main.rs @@ -3,7 +3,7 @@ use std::{env, process}; mod filesystem; mod scheme; -use redox_scheme::{RequestKind, SignalBehavior}; +use redox_scheme::{RequestKind, SignalBehavior, V2}; use self::scheme::Scheme; @@ -11,8 +11,7 @@ fn main() { let scheme_name = env::args().nth(1).expect("Usage:\n\tramfs SCHEME_NAME"); redox_daemon::Daemon::new(move |daemon| { - let socket = redox_scheme::Socket::::create(&scheme_name) - .expect("ramfs: failed to create socket"); + let socket = redox_scheme::Socket::::create(&scheme_name).expect("ramfs: failed to create socket"); let mut scheme = Scheme::new(scheme_name).expect("ramfs: failed to initialize scheme"); diff --git a/src/scheme.rs b/src/scheme.rs index 2a24c850e1..c103abb74a 100644 --- a/src/scheme.rs +++ b/src/scheme.rs @@ -1,8 +1,8 @@ -use std::collections::BTreeMap; use std::convert::{TryFrom, TryInto}; use std::os::unix::io::AsRawFd; -use std::{cmp, ops}; +use indexmap::IndexMap; +use syscall::dirent::{DirEntry, DirentBuf, DirentKind}; use syscall::error::{ EACCES, EBADF, EBADFD, EEXIST, EINVAL, EIO, EISDIR, ENOMEM, ENOSYS, ENOTDIR, ENOTEMPTY, EOVERFLOW, @@ -11,30 +11,15 @@ use syscall::flag::{ O_ACCMODE, O_CREAT, O_DIRECTORY, O_EXCL, O_RDONLY, O_RDWR, O_STAT, O_TRUNC, O_WRONLY, }; use syscall::schemev2::NewFdFlags; -use syscall::{Error, EventFlags, Map, Result, Stat, StatVfs, TimeSpec}; -use syscall::{MODE_DIR, MODE_FILE, MODE_PERM, MODE_TYPE, SEEK_CUR, SEEK_END, SEEK_SET}; +use syscall::{Error, EventFlags, Result, Stat, StatVfs, TimeSpec, ENOENT}; +use syscall::{MODE_DIR, MODE_FILE, MODE_PERM, MODE_TYPE}; use redox_scheme::{CallerCtx, OpenResult, SchemeMut}; -use crate::filesystem::{self, DirEntry, File, FileData, Filesystem}; - -#[derive(Clone)] -struct Handle { - inode: usize, - - // TODO: fcntl_flags? - opened_as_read: bool, // opened with O_RDONLY or O_RDWR - opened_as_write: bool, // opened with O_WRONLY or O_RDWR - - // the three first bits of mode >> 6 if uid matched, mode >> 3 if gid matched, otherwise mode - // >> 0. - current_perm: u8, -} +use crate::filesystem::{self, File, FileData, Filesystem, Inode}; pub struct Scheme { scheme_name: String, - handles: BTreeMap, - next_fd: usize, filesystem: Filesystem, } impl Scheme { @@ -42,21 +27,19 @@ impl Scheme { pub fn new(scheme_name: String) -> Result { Ok(Self { scheme_name, - handles: BTreeMap::new(), filesystem: Filesystem::new()?, - next_fd: 0, }) } /// Remove a directory entry, where the entry can be both a file or a directory. Used by both /// `unlink` and `rmdir`. pub fn remove_dentry( &mut self, - path: &[u8], + path: &str, uid: u32, gid: u32, directory: bool, ) -> Result { - let removed_entry = { + let removed_inode = { let (parent_dir_inode, name_to_delete) = self.filesystem.resolve_except_last(path, uid, gid)?; let name_to_delete = name_to_delete.ok_or(Error::new(EINVAL))?; // can't remove root @@ -71,16 +54,11 @@ impl Scheme { return Err(Error::new(EACCES)); } - let dentries = parent.data.as_directory_mut().ok_or(Error::new(EBADF))?; + let FileData::Directory(ref mut dentries) = parent.data else { + return Err(Error::new(ENOTDIR)); + }; - let (position, entry_inode) = dentries - .iter() - .enumerate() - .find(|(_, d)| d.name == name_to_delete) - .unwrap(); - let entry_inode = entry_inode.inode; - - let removed_entry = dentries.remove(position); + let Inode(entry_inode) = dentries.shift_remove(name_to_delete).ok_or(Error::new(ENOENT))?; if let Some(File { data: FileData::Directory(ref data), @@ -100,35 +78,35 @@ impl Scheme { parent.nlink -= 1; // '..' of subdirectory } - removed_entry + entry_inode }; - let removed_inode = self + let removed_inode_info = self .filesystem .files - .get_mut(&removed_entry.inode) + .get_mut(&removed_inode) .ok_or(Error::new(EIO))?; - if let FileData::File(_) = removed_inode.data { + if let FileData::File(_) = removed_inode_info.data { if directory { return Err(Error::new(EISDIR)); } - removed_inode.nlink -= 1; // only the parent entry + removed_inode_info.nlink -= 1; // only the parent entry } else { if !directory { return Err(Error::new(ENOTDIR)); } - removed_inode.nlink -= 2; // both the parent entry and '.' + removed_inode_info.nlink -= 2; // both the parent entry and '.' } - if removed_inode.nlink == 0 && removed_inode.open_handles == 0 { - self.filesystem.files.remove(&removed_entry.inode); + if removed_inode_info.nlink == 0 && removed_inode_info.open_handles == 0 { + self.filesystem.files.remove(&removed_inode); } Ok(0) } - fn open_existing(&mut self, path: &[u8], flags: usize, uid: u32, gid: u32) -> Result { + fn open_existing(&mut self, path: &str, flags: usize, uid: u32, gid: u32) -> Result { let inode = self.filesystem.resolve(path, uid, gid)?; let file = self .filesystem @@ -151,7 +129,6 @@ impl Scheme { let current_perm = current_perm(file, uid, gid); check_permissions(flags, current_perm)?; - let opened_as_read = flags & O_ACCMODE == O_RDONLY || flags & O_ACCMODE == O_RDWR; let opened_as_write = flags & O_ACCMODE == O_WRONLY || flags & O_ACCMODE == O_RDWR; if flags & O_TRUNC == O_TRUNC && opened_as_write { @@ -166,24 +143,19 @@ impl Scheme { file.open_handles += 1; - Ok(Handle { - inode, - opened_as_read, - opened_as_write, - current_perm, - }) + Ok(Inode(inode)) } } impl SchemeMut for Scheme { fn xopen(&mut self, path: &str, flags: usize, ctx: &CallerCtx) -> Result { - let exists = self.filesystem.resolve(path.as_bytes(), 0, 0).is_ok(); + let exists = self.filesystem.resolve(path, 0, 0).is_ok(); if flags & O_CREAT != 0 && flags & O_EXCL != 0 && exists { return Err(Error::new(EEXIST)); } - let handle = if flags & O_CREAT != 0 && exists { - self.open_existing(path.as_bytes(), flags, ctx.uid, ctx.gid)? + let inode = if flags & O_CREAT != 0 && exists { + self.open_existing(path, flags, ctx.uid, ctx.gid)?.0 } else if flags & O_CREAT != 0 { if flags & O_STAT != 0 { return Err(Error::new(EINVAL)); @@ -191,7 +163,7 @@ impl SchemeMut for Scheme { let (parent_dir_inode, new_name) = self.filesystem - .resolve_except_last(path.as_bytes(), ctx.uid, ctx.gid)?; + .resolve_except_last(path, ctx.uid, ctx.gid)?; let new_name = new_name.ok_or(Error::new(EINVAL))?; // cannot mkdir / let current_time = filesystem::current_time(); @@ -215,10 +187,9 @@ impl SchemeMut for Scheme { mtime: current_time, gid: ctx.gid, uid: ctx.uid, - ino: new_inode_number, mode, nlink: 2, // parent entry, "." - data: FileData::Directory(Vec::new()), + data: FileData::Directory(IndexMap::new()), open_handles: 1, } } else { @@ -236,7 +207,6 @@ impl SchemeMut for Scheme { mtime: current_time, gid: ctx.gid, uid: ctx.uid, - ino: new_inode_number, mode, nlink: 1, data: FileData::File(Vec::new()), @@ -255,63 +225,38 @@ impl SchemeMut for Scheme { .ok_or(Error::new(EIO))?; match parent_file.data { FileData::File(_) => return Err(Error::new(EIO)), - FileData::Directory(ref mut entries) => entries.push(DirEntry { - name: new_name.to_owned(), - inode: new_inode_number, - }), + FileData::Directory(ref mut entries) => { + entries.insert(new_name.to_owned(), Inode(new_inode_number)); + } } - Handle { - inode: new_inode_number, - opened_as_read: flags & O_ACCMODE == O_RDONLY || flags & O_ACCMODE == O_RDWR, - opened_as_write: flags & O_ACCMODE == O_WRONLY || flags & O_ACCMODE == O_RDWR, - current_perm, - } + new_inode_number } else { - self.open_existing(path.as_bytes(), flags, ctx.uid, ctx.gid)? + self.open_existing(path, flags, ctx.uid, ctx.gid)?.0 }; - - let fd = self.next_fd; - self.next_fd += 1; - - self.handles.insert(fd, handle); - - Ok(OpenResult::ThisScheme { - number: fd, - flags: NewFdFlags::POSITIONED, - }) + Ok(OpenResult::ThisScheme { number: inode, flags: NewFdFlags::POSITIONED }) } fn rmdir(&mut self, path: &str, uid: u32, gid: u32) -> Result { - self.remove_dentry(path.as_bytes(), uid, gid, true) + self.remove_dentry(path, uid, gid, true) } fn unlink(&mut self, path: &str, uid: u32, gid: u32) -> Result { - self.remove_dentry(path.as_bytes(), uid, gid, false) + self.remove_dentry(path, uid, gid, false) } - fn dup(&mut self, old_fd: usize, _buf: &[u8]) -> Result { - let handle = self - .handles - .get_mut(&old_fd) - .ok_or(Error::new(EBADF))? - .clone(); - - let fd = self.next_fd; - self.next_fd += 1; - - self.handles.insert(fd, handle); - Ok(fd) + fn dup(&mut self, old_inode: usize, _buf: &[u8]) -> Result { + Ok(old_inode) } - fn read(&mut self, fd: usize, buf: &mut [u8], offset: u64, _fcntl_flags: u32) -> Result { - let handle = self.handles.get_mut(&fd).ok_or(Error::new(EBADF))?; + fn read(&mut self, inode: usize, buf: &mut [u8], offset: u64, fcntl_flags: u32) -> Result { let Ok(offset) = usize::try_from(offset) else { return Ok(0); }; + let file = self .filesystem .files - .get_mut(&handle.inode) + .get_mut(&inode) .ok_or(Error::new(EBADFD))?; - if !handle.opened_as_read { + if !matches!((fcntl_flags as usize) & O_ACCMODE, O_RDONLY | O_RDWR) { return Err(Error::new(EBADF)); } @@ -320,64 +265,47 @@ impl SchemeMut for Scheme { if file.mode & MODE_TYPE == MODE_DIR { return Err(Error::new(EBADFD)); } - - if offset >= bytes.len() { - return Ok(0); - } - let src = buf.get(..offset).unwrap_or(&[]); - let to_copy = src.len().min(buf.len()); - buf[..to_copy].copy_from_slice(&bytes[offset..][..to_copy]); - Ok(to_copy) - } - FileData::Directory(ref entries) => { - if file.mode & MODE_TYPE != MODE_DIR { - return Err(Error::new(EBADFD)); - } - // directories require the execute permission to be listed - if handle.current_perm & 0o1 == 0 { - return Err(Error::new(EBADF)); - } - - let mut bytes_to_skip = offset; - let mut bytes_left_to_read = buf.len(); - let mut bytes_read = 0; - - for DirEntry { - name: entry_bytes, .. - } in entries - { - // skip the whole entry if it fits - if bytes_to_skip >= entry_bytes.len() { - bytes_to_skip -= entry_bytes.len(); - continue; - } - - let bytes_to_read = - cmp::min(entry_bytes.len() + 1 - bytes_to_skip, bytes_left_to_read); - - let entry_bytes = - &entry_bytes[bytes_to_skip..bytes_to_skip + bytes_to_read - 1]; - bytes_to_skip -= bytes_to_skip; - - buf[bytes_read..bytes_read + bytes_to_read - 1] - .copy_from_slice(&entry_bytes[..bytes_to_read - 1]); - buf[bytes_read + bytes_to_read - 1] = b'\n'; - bytes_left_to_read -= bytes_to_read; - bytes_read += bytes_to_read; - } - Ok(bytes_read) + let src_bytes = bytes.get(offset..).unwrap_or(&[]); + let bytes_to_read = src_bytes.len().min(buf.len()); + buf[..bytes_to_read].copy_from_slice(&src_bytes[..bytes_to_read]); + Ok(bytes_to_read) } + FileData::Directory(_) => return Err(Error::new(EISDIR)), } } - fn write(&mut self, fd: usize, buf: &[u8], offset: u64, _fcntl_flags: u32) -> Result { - let handle = self.handles.get_mut(&fd).ok_or(Error::new(EBADF))?; - let Ok(offset) = usize::try_from(offset) else { - return Ok(0); + fn getdents<'buf>(&mut self, inode: usize, mut buf: DirentBuf<&'buf mut [u8]>, opaque_offset: u64) -> Result> { + let Ok(offset) = usize::try_from(opaque_offset) else { + return Ok(buf); }; let file = self .filesystem .files - .get_mut(&handle.inode) + .get_mut(&inode) + .ok_or(Error::new(EBADFD))?; + + let FileData::Directory(ref dir) = file.data else { + return Err(Error::new(ENOTDIR)); + }; + + for (i, (dent_name, Inode(dent_inode))) in dir.iter().enumerate().skip(offset) { + buf.entry(DirEntry { + inode: *dent_inode as u64, + name: dent_name, + kind: DirentKind::Unspecified, + next_opaque_id: i as u64 + 1, + })?; + } + Ok(buf) + } + fn write(&mut self, inode: usize, buf: &[u8], offset: u64, _fcntl_flags: u32) -> Result { + let Ok(offset) = usize::try_from(offset) else { + return Ok(0); + }; + + let file = self + .filesystem + .files + .get_mut(&inode) .ok_or(Error::new(EBADFD))?; if let &mut FileData::File(ref mut bytes) = &mut file.data { @@ -399,25 +327,11 @@ impl SchemeMut for Scheme { Err(Error::new(EISDIR)) } } - fn fsize(&mut self, fd: usize) -> Result { - let handle = self.handles.get_mut(&fd).ok_or(Error::new(EBADF))?; + fn fchmod(&mut self, inode: usize, mode: u16) -> Result { let file = self .filesystem .files - .get_mut(&handle.inode) - .ok_or(Error::new(EBADFD))?; - - file.data - .size() - .try_into() - .map_err(|_| Error::new(EOVERFLOW)) - } - fn fchmod(&mut self, fd: usize, mode: u16) -> Result { - let handle = self.handles.get_mut(&fd).ok_or(Error::new(EBADF))?; - let file = self - .filesystem - .files - .get_mut(&handle.inode) + .get_mut(&inode) .ok_or(Error::new(EBADFD))?; let cur_type = file.mode & MODE_TYPE; @@ -432,12 +346,11 @@ impl SchemeMut for Scheme { Ok(0) } - fn fchown(&mut self, fd: usize, uid: u32, gid: u32) -> Result { - let handle = self.handles.get_mut(&fd).ok_or(Error::new(EBADF))?; + fn fchown(&mut self, inode: usize, uid: u32, gid: u32) -> Result { let file = self .filesystem .files - .get_mut(&handle.inode) + .get_mut(&inode) .ok_or(Error::new(EBADFD))?; file.uid = uid; @@ -445,52 +358,31 @@ impl SchemeMut for Scheme { Ok(0) } - fn fcntl(&mut self, fd: usize, _cmd: usize, _arg: usize) -> Result { - if !self.handles.contains_key(&fd) { - return Err(Error::new(EBADF)); - } + fn fcntl(&mut self, _inode: usize, _cmd: usize, _arg: usize) -> Result { Ok(0) } - fn fevent(&mut self, fd: usize, _flags: EventFlags) -> Result { - if !self.handles.contains_key(&fd) { - return Err(Error::new(EBADF)); - } + fn fevent(&mut self, _inode: usize, _flags: EventFlags) -> Result { + // TODO? Err(Error::new(ENOSYS)) } - fn mmap_prep( - &mut self, - fd: usize, - _offset: u64, - _size: usize, - _flags: syscall::MapFlags, - ) -> Result { - if !self.handles.contains_key(&fd) { - return Err(Error::new(EBADF)); - } + fn mmap_prep(&mut self, _inode: usize, _offset: u64, _size: usize, _flags: syscall::MapFlags) -> Result { // TODO Err(Error::new(ENOSYS)) } - fn fpath(&mut self, fd: usize, _buf: &mut [u8]) -> Result { - if !self.handles.contains_key(&fd) { - return Err(Error::new(EBADF)); - } + fn fpath(&mut self, _inode: usize, _buf: &mut [u8]) -> Result { // TODO Err(Error::new(ENOSYS)) } - fn frename(&mut self, fd: usize, _path: &str, _uid: u32, _gid: u32) -> Result { - if !self.handles.contains_key(&fd) { - return Err(Error::new(EBADF)); - } + fn frename(&mut self, _inode: usize, _path: &str, _uid: u32, _gid: u32) -> Result { // TODO Err(Error::new(ENOSYS)) } - fn fstat(&mut self, fd: usize, stat: &mut Stat) -> Result { - let handle = self.handles.get_mut(&fd).ok_or(Error::new(EBADF))?; + fn fstat(&mut self, inode: usize, stat: &mut Stat) -> Result { let block_size = self.filesystem.block_size(); let file = self .filesystem .files - .get_mut(&handle.inode) + .get_mut(&inode) .ok_or(Error::new(EBADFD))?; let size = file.data.size().try_into().or(Err(Error::new(EOVERFLOW)))?; @@ -499,13 +391,13 @@ impl SchemeMut for Scheme { st_mode: file.mode, st_uid: file.uid, st_gid: file.gid, - st_ino: handle.inode.try_into().or(Err(Error::new(EOVERFLOW)))?, + st_ino: inode.try_into().map_err(|_| Error::new(EOVERFLOW))?, st_nlink: file.nlink.try_into().or(Err(Error::new(EOVERFLOW)))?, st_dev: 0, st_size: size, st_blksize: block_size, - st_blocks: div_round_up(size, u64::from(block_size)), + st_blocks: size.next_multiple_of(u64::from(block_size)), st_atime: file .atime @@ -543,10 +435,7 @@ impl SchemeMut for Scheme { Ok(0) } - fn fstatvfs(&mut self, fd: usize, stat: &mut StatVfs) -> Result { - if !self.handles.contains_key(&fd) { - return Err(Error::new(EBADF)); - } + fn fstatvfs(&mut self, _inode: usize, stat: &mut StatVfs) -> Result { let abi_stat = libredox::call::fstatvfs(self.filesystem.memory_file.as_raw_fd() as usize)?; // TODO: From impl *stat = StatVfs { @@ -558,18 +447,14 @@ impl SchemeMut for Scheme { Ok(0) } - fn fsync(&mut self, fd: usize) -> Result { - if !self.handles.contains_key(&fd) { - return Err(Error::new(EBADF)); - } + fn fsync(&mut self, _inode: usize) -> Result { Ok(0) } - fn ftruncate(&mut self, fd: usize, size: usize) -> Result { - let handle = self.handles.get_mut(&fd).ok_or(Error::new(EBADF))?; + fn ftruncate(&mut self, inode: usize, size: usize) -> Result { let file = self .filesystem .files - .get_mut(&handle.inode) + .get_mut(&inode) .ok_or(Error::new(EBADFD))?; if file.mode & MODE_TYPE == MODE_DIR { @@ -589,12 +474,11 @@ impl SchemeMut for Scheme { } Ok(0) } - fn futimens(&mut self, fd: usize, times: &[TimeSpec]) -> Result { - let handle = self.handles.get_mut(&fd).ok_or(Error::new(EBADF))?; + fn futimens(&mut self, inode: usize, times: &[TimeSpec]) -> Result { let file = self .filesystem .files - .get_mut(&handle.inode) + .get_mut(&inode) .ok_or(Error::new(EBADFD))?; let new_atime = *times.get(0).ok_or(Error::new(EINVAL))?; @@ -605,32 +489,21 @@ impl SchemeMut for Scheme { Ok(0) } - fn close(&mut self, fd: usize) -> Result { - let inode_num = self.handles.remove(&fd).ok_or(Error::new(EBADF))?.inode; - let inode = self + fn close(&mut self, inode: usize) -> Result { + let inode_info = self .filesystem .files - .get_mut(&inode_num) + .get_mut(&inode) .ok_or(Error::new(EIO))?; - inode.open_handles -= 1; + inode_info.open_handles -= 1; - if inode.nlink == 0 && inode.open_handles == 0 { - self.filesystem.files.remove(&inode_num); + if inode_info.nlink == 0 && inode_info.open_handles == 0 { + self.filesystem.files.remove(&inode); } Ok(0) } } -fn div_round_up(numer: T, denom: T) -> T -where - T: Copy - + ops::Add - + ops::Sub - + ops::Div - + From, -{ - (numer + (denom - T::from(1u8))) / denom -} pub fn current_perm(file: &crate::filesystem::File, uid: u32, gid: u32) -> u8 { let perm = file.mode & MODE_PERM;