From 2b51b024f79f2e4b226fa60aaccc6c0dc6fb5e4a Mon Sep 17 00:00:00 2001 From: pjht Date: Tue, 19 Nov 2024 10:42:32 -0600 Subject: [PATCH] Initial commit --- .cargo/config.toml | 5 + .gitignore | 1 + Cargo.lock | 391 ++++++++++++++++++++++++++++++++++++++++++++ Cargo.toml | 21 +++ rust-toolchain.toml | 2 + src/main.rs | 144 ++++++++++++++++ src/tempfs.rs | 263 +++++++++++++++++++++++++++++ 7 files changed, 827 insertions(+) create mode 100644 .cargo/config.toml create mode 100644 .gitignore create mode 100644 Cargo.lock create mode 100644 Cargo.toml create mode 100644 rust-toolchain.toml create mode 100644 src/main.rs create mode 100644 src/tempfs.rs diff --git a/.cargo/config.toml b/.cargo/config.toml new file mode 100644 index 0000000..bec4b7a --- /dev/null +++ b/.cargo/config.toml @@ -0,0 +1,5 @@ +[build] +target = "x86_64-unknown-mikros" + +[install] +root = "../os_build/sysroot" diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..ea8c4bf --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +/target diff --git a/Cargo.lock b/Cargo.lock new file mode 100644 index 0000000..0752101 --- /dev/null +++ b/Cargo.lock @@ -0,0 +1,391 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 4 + +[[package]] +name = "atomic-polyfill" +version = "1.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8cf2bce30dfe09ef0bfaef228b9d414faaf7e563035494d7fe092dba54b300f4" +dependencies = [ + "critical-section", +] + +[[package]] +name = "autocfg" +version = "1.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ace50bade8e6234aa140d9a2f552bbee1db4d353f69b8217bc503490fc1a9f26" + +[[package]] +name = "bitflags" +version = "2.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b048fb63fd8b5923fc5aa7b340d8e156aec7ec02f0c78fa8a6ddc2613f6f71de" +dependencies = [ + "serde", +] + +[[package]] +name = "byteorder" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" + +[[package]] +name = "cfg-if" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" + +[[package]] +name = "cobs" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "67ba02a97a2bd10f4b59b25c7973101c79642302776489e030cd13cdab09ed15" + +[[package]] +name = "critical-section" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "790eea4361631c5e7d22598ecd5723ff611904e3344ce8720784c93e3d83d40b" + +[[package]] +name = "dir_rpc" +version = "0.1.0" +dependencies = [ + "parking_lot", + "postcard", +] + +[[package]] +name = "embedded-io" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ef1a6892d9eef45c8fa6b9e0086428a2cca8491aca8f787c534a3d6d0bcb3ced" + +[[package]] +name = "embedded-io" +version = "0.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "edd0f118536f44f5ccd48bcb8b111bdc3de888b58c74639dfb034a357d0f206d" + +[[package]] +name = "file_rpc" +version = "0.1.0" +dependencies = [ + "bitflags", + "parking_lot", + "postcard", + "serde", +] + +[[package]] +name = "fs_rpc" +version = "0.1.0" +dependencies = [ + "parking_lot", + "postcard", + "serde", +] + +[[package]] +name = "hash32" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b0c35f58762feb77d74ebe43bdbc3210f09be9fe6742234d573bacc26ed92b67" +dependencies = [ + "byteorder", +] + +[[package]] +name = "heapless" +version = "0.7.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cdc6457c0eb62c71aac4bc17216026d8410337c4126773b9c5daba343f17964f" +dependencies = [ + "atomic-polyfill", + "hash32", + "rustc_version", + "serde", + "spin", + "stable_deref_trait", +] + +[[package]] +name = "libc" +version = "0.2.164" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "433bfe06b8c75da9b2e3fbea6e5329ff87748f0b144ef75306e674c3f6f7c13f" + +[[package]] +name = "lock_api" +version = "0.4.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "07af8b9cdd281b7915f413fa73f29ebd5d55d0d3f0155584dade1ff18cea1b17" +dependencies = [ + "autocfg", + "scopeguard", +] + +[[package]] +name = "parking_lot" +version = "0.12.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f1bf18183cf54e8d6059647fc3063646a1801cf30896933ec2311622cc4b9a27" +dependencies = [ + "lock_api", + "parking_lot_core", +] + +[[package]] +name = "parking_lot_core" +version = "0.9.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e401f977ab385c9e4e3ab30627d6f26d00e2c73eef317493c4ec6d468726cf8" +dependencies = [ + "cfg-if", + "libc", + "redox_syscall", + "smallvec", + "windows-targets", +] + +[[package]] +name = "postcard" +version = "1.0.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5f7f0a8d620d71c457dd1d47df76bb18960378da56af4527aaa10f515eee732e" +dependencies = [ + "cobs", + "embedded-io 0.4.0", + "embedded-io 0.6.1", + "heapless", + "postcard-derive", + "serde", +] + +[[package]] +name = "postcard-derive" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0239fa9c1d225d4b7eb69925c25c5e082307a141e470573fbbe3a817ce6a7a37" +dependencies = [ + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "proc-macro2" +version = "1.0.89" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f139b0662de085916d1fb67d2b4169d1addddda1919e696f3252b740b629986e" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "quote" +version = "1.0.37" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b5b9d34b8991d19d98081b46eacdd8eb58c6f2b201139f7c5f643cc155a633af" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "redox_syscall" +version = "0.5.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9b6dfecf2c74bce2466cabf93f6664d6998a69eb21e39f4207930065b27b771f" +dependencies = [ + "bitflags", +] + +[[package]] +name = "rustc_version" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cfcb3a22ef46e85b45de6ee7e79d063319ebb6594faafcf1c225ea92ab6e9b92" +dependencies = [ + "semver", +] + +[[package]] +name = "scopeguard" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" + +[[package]] +name = "semver" +version = "1.0.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "61697e0a1c7e512e84a621326239844a24d8207b4669b41bc18b32ea5cbf988b" + +[[package]] +name = "serde" +version = "1.0.210" +dependencies = [ + "serde_derive", +] + +[[package]] +name = "serde_derive" +version = "1.0.210" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.87", +] + +[[package]] +name = "smallvec" +version = "1.13.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3c5e1a9a646d36c3599cd173a41282daf47c44583ad367b8e6837255952e5c67" + +[[package]] +name = "spin" +version = "0.9.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6980e8d7511241f8acf4aebddbb1ff938df5eebe98691418c4468d0b72a96a67" +dependencies = [ + "lock_api", +] + +[[package]] +name = "stable_deref_trait" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a8f112729512f8e442d81f95a8a7ddf2b7c6b8a1a6f509a95864142b30cab2d3" + +[[package]] +name = "syn" +version = "1.0.109" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "syn" +version = "2.0.87" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "25aa4ce346d03a6dcd68dd8b4010bcb74e54e62c90c573f394c46eae99aba32d" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "syslog_rpc" +version = "0.1.0" +dependencies = [ + "parking_lot", + "postcard", + "syslog_structs", +] + +[[package]] +name = "syslog_structs" +version = "0.1.0" +dependencies = [ + "serde", +] + +[[package]] +name = "tmpfs" +version = "0.1.0" +dependencies = [ + "dir_rpc", + "file_rpc", + "fs_rpc", + "parking_lot", + "syslog_rpc", + "vfs_rpc", +] + +[[package]] +name = "unicode-ident" +version = "1.0.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e91b56cd4cadaeb79bbf1a5645f6b4f8dc5bde8834ad5894a8db35fda9efa1fe" + +[[package]] +name = "vfs_rpc" +version = "0.1.0" +dependencies = [ + "parking_lot", + "postcard", + "serde", +] + +[[package]] +name = "windows-targets" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973" +dependencies = [ + "windows_aarch64_gnullvm", + "windows_aarch64_msvc", + "windows_i686_gnu", + "windows_i686_gnullvm", + "windows_i686_msvc", + "windows_x86_64_gnu", + "windows_x86_64_gnullvm", + "windows_x86_64_msvc", +] + +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3" + +[[package]] +name = "windows_aarch64_msvc" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469" + +[[package]] +name = "windows_i686_gnu" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b" + +[[package]] +name = "windows_i686_gnullvm" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66" + +[[package]] +name = "windows_i686_msvc" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66" + +[[package]] +name = "windows_x86_64_gnu" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78" + +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" diff --git a/Cargo.toml b/Cargo.toml new file mode 100644 index 0000000..d966acd --- /dev/null +++ b/Cargo.toml @@ -0,0 +1,21 @@ +[package] +name = "tmpfs" +version = "0.1.0" +edition = "2021" + +[dependencies] +dir_rpc = { version = "0.1.0", path = "../dir_rpc" } +file_rpc = { version = "0.1.0", path = "../file_rpc" } +fs_rpc = { version = "0.1.0", path = "../fs_rpc" } +parking_lot = "0.12.3" +syslog_rpc = { version = "0.1.0", path = "../syslog/syslog_rpc" } +vfs_rpc = { version = "0.1.0", path = "../vfs/vfs_rpc" } + +[profile.release] +strip = true +lto = true +opt-level = "s" + +[patch.crates-io] +serde = { path = "../serde/serde" } +serde_derive = { path = "../serde/serde_derive" } diff --git a/rust-toolchain.toml b/rust-toolchain.toml new file mode 100644 index 0000000..a5535e3 --- /dev/null +++ b/rust-toolchain.toml @@ -0,0 +1,2 @@ +[toolchain] +channel = "dev-x86_64-unknown-mikros" diff --git a/src/main.rs b/src/main.rs new file mode 100644 index 0000000..6300279 --- /dev/null +++ b/src/main.rs @@ -0,0 +1,144 @@ +mod tempfs; + +use std::{ + borrow::Cow, + os::mikros::{ipc, syscalls, Errno, FileOpenMode}, + sync::Arc, +}; + +use parking_lot::Mutex; +use tempfs::TempFs; + +#[derive(Clone)] +struct Serv { + mounts: Arc>>, +} + +impl fs_rpc::Server for Serv { + fn mount(&self, _dev: &std::path::Path) -> Result { + let mut mounts = self.mounts.lock(); + if mounts.len() == u32::MAX as usize { + return Err(Errno::ENOMEM); + } + mounts.push(TempFs::new()); + Ok((mounts.len() - 1) as u64) + } + + fn open( + &self, + path: &std::path::Path, + mode: FileOpenMode, + mount_id: u64, + ) -> Result<(Option, u64), Errno> { + let mut mounts = self.mounts.lock(); + let mount = mounts.get_mut(mount_id as usize).ok_or(Errno::EBADF)?; + let fd = mount.open(path, mode)?; + Ok((None, (fd as u64) | (mount_id << 32))) + } + + fn open_dir(&self, path: &std::path::Path, mount_id: u64) -> Result<(Option, u64), Errno> { + let mut mounts = self.mounts.lock(); + let mount = mounts.get_mut(mount_id as usize).ok_or(Errno::EBADF)?; + let fd = mount.open_dir(path)?; + Ok((None, (fd as u64) | (mount_id << 32))) + } +} + +impl file_rpc::Server for Serv { + fn read(&self, fd: u64, len: usize) -> Result, Errno> { + let mount_id = fd >> 32; + let fd = fd as u32; + let mut mounts = self.mounts.lock(); + let mount = mounts.get_mut(mount_id as usize).ok_or(Errno::EBADF)?; + mount.read(fd, len).map(|buf| buf.into()) + } + + fn write(&self, fd: u64, data: &[u8]) -> Result<(), Errno> { + let mount_id = fd >> 32; + let fd = fd as u32; + let mut mounts = self.mounts.lock(); + let mount = mounts.get_mut(mount_id as usize).ok_or(Errno::EBADF)?; + mount.write(fd, data) + } + + fn close(&self, fd: u64) -> Result<(), Errno> { + let mount_id = fd >> 32; + let fd = fd as u32; + let mut mounts = self.mounts.lock(); + let mount = mounts.get_mut(mount_id as usize).ok_or(Errno::EBADF)?; + mount.close(fd) + } + + fn size(&self, fd: u64) -> Result { + let mount_id = fd >> 32; + let fd = fd as u32; + let mounts = self.mounts.lock(); + let mount = mounts.get(mount_id as usize).ok_or(Errno::EBADF)?; + mount.size(fd) + } + + fn dup(&self, fd: u64) -> Result { + let mount_id = fd >> 32; + let fd = fd as u32; + let mut mounts = self.mounts.lock(); + let mount = mounts.get_mut(mount_id as usize).ok_or(Errno::EBADF)?; + let new_fd = mount.dup(fd)?; + Ok((new_fd as u64) | (mount_id << 32)) + } + + fn seek(&self, fd: u64, pos: file_rpc::SeekFrom) -> Result { + let mount_id = fd >> 32; + let fd = fd as u32; + let mut mounts = self.mounts.lock(); + let mount = mounts.get_mut(mount_id as usize).ok_or(Errno::EBADF)?; + mount.seek(fd, pos) + } +} + +impl dir_rpc::Server for Serv { + fn next_entry(&self, fd: u64) -> Result, Errno> { + let mount_id = fd >> 32; + let fd = fd as u32; + let mut mounts = self.mounts.lock(); + let mount = mounts.get_mut(mount_id as usize).ok_or(Errno::EBADF)?; + mount.dir_next(fd) + } + + fn close(&self, fd: u64) -> Result<(), Errno> { + let mount_id = fd >> 32; + let fd = fd as u32; + let mut mounts = self.mounts.lock(); + let mount = mounts.get_mut(mount_id as usize).ok_or(Errno::EBADF)?; + mount.close(fd) + } +} + +fn main() { + let serv = Serv { + mounts: Arc::new(Mutex::new(Vec::new())), + }; + fs_rpc::register_server(Box::new(serv.clone())); + dir_rpc::register_server(Box::new(serv.clone())); + file_rpc::register_server(Box::new(serv)); + let vfs_pid; + loop { + if let Some(pid) = syscalls::try_get_registered(0) { + vfs_pid = pid; + break; + } + } + vfs_rpc::Client::new(vfs_pid).register_fs("tmpfs").unwrap(); + let syslog_pid; + loop { + if let Some(pid) = syscalls::try_get_registered(2) { + syslog_pid = pid; + break; + } + } + syslog_rpc::Client::new(syslog_pid) + .send_text_binary_message("tmpfs".to_string(), "Tmpfs initialized".to_string(), 0, []) + .unwrap(); + loop { + ipc::process_messages() + } +} diff --git a/src/tempfs.rs b/src/tempfs.rs new file mode 100644 index 0000000..6d6302a --- /dev/null +++ b/src/tempfs.rs @@ -0,0 +1,263 @@ +use std::{ + ffi::OsString, + os::mikros::{Errno, FileCreationMode, FileOpenMode}, + path::Path, +}; + +struct DirEntry { + name: OsString, + inode: usize, +} + +impl DirEntry { + fn new>(name: T, inode: usize) -> Self { + Self { + name: name.into(), + inode, + } + } +} + +enum Inode { + File(Vec), + Directory(Vec), +} + +impl Inode { + fn as_directory(&self) -> Option<&Vec> { + if let Self::Directory(v) = self { + Some(v) + } else { + None + } + } + fn as_directory_mut(&mut self) -> Option<&mut Vec> { + if let Self::Directory(v) = self { + Some(v) + } else { + None + } + } + + #[allow(unused)] + fn as_file(&self) -> Option<&Vec> { + if let Self::File(v) = self { + Some(v) + } else { + None + } + } + + fn as_file_mut(&mut self) -> Option<&mut Vec> { + if let Self::File(v) = self { + Some(v) + } else { + None + } + } + + /// Returns `true` if the inode is [`File`]. + /// + /// [`File`]: Inode::File + #[must_use] + fn is_file(&self) -> bool { + matches!(self, Self::File(..)) + } + + /// Returns `true` if the inode is [`Directory`]. + /// + /// [`Directory`]: Inode::Directory + #[must_use] + fn is_directory(&self) -> bool { + matches!(self, Self::Directory(..)) + } +} + +struct OpenFile { + pos: usize, + inode: usize, + mode: FileOpenMode, +} + +pub struct TempFs { + inodes: Vec, + open_files: Vec, +} + +impl TempFs { + pub fn new() -> Self { + Self { + inodes: vec![Inode::Directory(vec![ + DirEntry::new(".", 0), + DirEntry::new("..", 0), + ])], + open_files: Vec::new(), + } + } + + fn path_inode>(&self, path: P) -> Result { + let path = path.as_ref(); + if let Some(parent) = path.parent() { + let file_name = path.file_name().ok_or(Errno::EINVAL)?; + let dir_inode = self.path_inode(parent)?; + let dir_entries = self.inodes[dir_inode].as_directory().unwrap(); + Ok(dir_entries + .iter() + .find(|entry| entry.name == file_name) + .ok_or(Errno::ENOENT)? + .inode) + } else { + Ok(0) + } + } + + pub fn open(&mut self, path: &Path, mode: FileOpenMode) -> Result { + if self.open_files.len() == u32::MAX as usize { + return Err(Errno::ENFILE); + } + let inode = match self.path_inode(path) { + Ok(x) => x, + Err(Errno::ENOENT) => { + if !mode + .get_writing_details() + .map_or(false, |(_, y)| y != FileCreationMode::NoCreate) + { + return Err(Errno::ENOENT); + } + let parent_dir_inode = self.path_inode(path.parent().unwrap())?; + self.inodes.push(Inode::File(vec![])); + let new_file_inode = self.inodes.len() - 1; + let parent_dir = self.inodes[parent_dir_inode].as_directory_mut().unwrap(); + let file_name = path.file_name().ok_or(Errno::EINVAL)?; + parent_dir.push(DirEntry { name: file_name.to_owned(), inode: new_file_inode }); + new_file_inode + } + Err(e) => return Err(e), + }; + if !self.inodes[inode].is_file() { + return Err(Errno::EISDIR); + } + if let Some((wr_mode, _)) = mode.get_writing_details() { + if wr_mode.truncate { + self.inodes[inode].as_file_mut().unwrap().clear(); + } + } + let file = OpenFile { + pos: 0, + inode, + mode, + }; + self.open_files.push(file); + Ok((self.open_files.len() - 1) as u32) + } + + pub fn open_dir(&mut self, path: &Path) -> Result { + if self.open_files.len() == u32::MAX as usize { + return Err(Errno::ENFILE); + } + let inode = self.path_inode(path)?; + if !self.inodes[inode].is_directory() { + return Err(Errno::ENOTDIR); + } + let file = OpenFile { + pos: 0, + inode, + mode: FileOpenMode::Read, + }; + self.open_files.push(file); + Ok((self.open_files.len() - 1) as u32) + } + + pub fn read(&mut self, fd: u32, len: usize) -> Result, Errno> { + let file = self.open_files.get_mut(fd as usize).ok_or(Errno::EBADF)?; + let Inode::File(ref data) = self.inodes[file.inode] else { + return Err(Errno::EISDIR); + }; + if !file.mode.readable() { + return Err(Errno::EACCES); + } + let read_len = usize::min(data.len() - file.pos, len); + let data = data[file.pos..][..read_len].to_vec(); + file.pos += read_len; + Ok(data) + } + + pub fn write(&mut self, fd: u32, data: &[u8]) -> Result<(), Errno> { + let file = self.open_files.get_mut(fd as usize).ok_or(Errno::EBADF)?; + let Inode::File(ref mut file_data) = self.inodes[file.inode] else { + return Err(Errno::EISDIR); + }; + let Some((wr_mode, _)) = file.mode.get_writing_details() else { + return Err(Errno::EACCES); + }; + if wr_mode.append { + file.pos = file_data.len(); + } + let write_end = file.pos + data.len() - 1; + if write_end >= file_data.len() { + file_data.resize(write_end + 1, 0); + } + file_data[file.pos..][..data.len()].copy_from_slice(data); + Ok(()) + } + + pub fn close(&mut self, _fd: u32) -> Result<(), Errno> { + Ok(()) + } + + pub fn size(&self, fd: u32) -> Result { + let file = self.open_files.get(fd as usize).ok_or(Errno::EBADF)?; + let Inode::File(ref data) = self.inodes[file.inode] else { + return Err(Errno::EISDIR); + }; + Ok(data.len() as u64) + } + + pub fn dup(&mut self, fd: u32) -> Result { + Ok(fd) + } + + pub fn seek(&mut self, fd: u32, pos: file_rpc::SeekFrom) -> Result { + let file = self.open_files.get_mut(fd as usize).ok_or(Errno::EBADF)?; + let Inode::File(ref data) = self.inodes[file.inode] else { + return Err(Errno::EISDIR); + }; + match pos { + file_rpc::SeekFrom::Start(offset) => { + file.pos = offset as usize; + } + file_rpc::SeekFrom::End(offset) => { + if offset <= 0 { + file.pos = data.len() - (-offset) as usize; + } + } + file_rpc::SeekFrom::Current(offset) => { + if offset > 0 { + file.pos = usize::min(file.pos + offset as usize, data.len()); + } else { + let offset = (-offset) as usize; + if offset > file.pos { + file.pos = 0; + } else { + file.pos -= offset; + } + } + } + } + Ok(file.pos as u64) + } + + pub fn dir_next(&mut self, fd: u32) -> Result, Errno> { + let dir = self.open_files.get_mut(fd as usize).ok_or(Errno::EBADF)?; + let Inode::Directory(ref entries) = self.inodes[dir.inode] else { + return Err(Errno::ENOTDIR); + }; + if dir.pos == entries.len() { + Ok(None) + } else { + let name = entries[dir.pos].name.clone(); + dir.pos += 1; + Ok(Some(name.to_string_lossy().into_owned())) + } + } +}