diff --git a/Cargo.lock b/Cargo.lock index 5268bc42..40ead83e 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -11,6 +11,12 @@ dependencies = [ "tock-registers", ] +[[package]] +name = "anyhow" +version = "1.0.102" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f202df86484c868dbad7eaa557ef785d5c66295e41b460ef922eca0723b842c" + [[package]] name = "arm-pl011-uart" version = "0.4.0" @@ -58,6 +64,17 @@ version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9330f8b2ff13f34540b44e946ef35111825727b38d33286ef986142615121801" +[[package]] +name = "chacha20" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6f8d983286843e49675a4b7a2d174efe136dc93a18d69130dd18198a6c167601" +dependencies = [ + "cfg-if", + "cpufeatures", + "rand_core", +] + [[package]] name = "colored" version = "3.1.1" @@ -67,6 +84,15 @@ dependencies = [ "windows-sys 0.61.2", ] +[[package]] +name = "cpufeatures" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8b2a41393f66f16b0823bb79094d54ac5fbd34ab292ddafb9a0456ac9f87d201" +dependencies = [ + "libc", +] + [[package]] name = "crc" version = "3.4.0" @@ -90,13 +116,19 @@ checksum = "d0a5c400df2834b80a4c3327b3aad3a4c4cd4de0629063962b03235697506a28" [[package]] name = "deranged" -version = "0.5.6" +version = "0.5.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cc3dc5ad92c2e2d1c193bbbbdf2ea477cb81331de4f3103f267ca18368b988c4" +checksum = "7cd812cc2bc1d69d4764bd80df88b4317eaef9e773c75226407d9bc0876b211c" dependencies = [ "powerfmt", ] +[[package]] +name = "equivalent" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "877a4ace8713b0bcf2a4e7eec82529c029f1d0619886d18145fea96c3ffe5c0f" + [[package]] name = "errno" version = "0.3.14" @@ -110,7 +142,7 @@ dependencies = [ [[package]] name = "ext4-view" version = "0.9.3" -source = "git+https://github.com/arihant2math/ext4-view-rs.git?branch=main#86785325204a60c02a74d2975db19af570878965" +source = "git+https://github.com/arihant2math/ext4-view-rs.git?branch=main#cb9a222d37f7b90d3b92068cad8d86d042171471" dependencies = [ "async-trait", "bitflags", @@ -123,6 +155,12 @@ version = "0.4.18" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1f95f0bda5ff920492f6573294d8e3a99b75ee2e5ef93ab313fc6d517fa46785" +[[package]] +name = "foldhash" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d9c4f5dac5e15c24eb999c26181a6ca40b39fe946cbe4c263c7209467bc83af2" + [[package]] name = "futures" version = "0.3.32" @@ -204,21 +242,62 @@ checksum = "084c6b182b01dec54ff12986b9cc8859a9b0d92b074f878c382a4481a070e66e" [[package]] name = "getrandom" -version = "0.3.4" +version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "899def5c37c4fd7b2664648c28120ecec138e4d395b459e5ca34f9cce2dd77fd" +checksum = "139ef39800118c7683f2fd3c98c1b23c09ae076556b435f8e9064ae108aaeeec" dependencies = [ "cfg-if", "libc", "r-efi", + "rand_core", "wasip2", + "wasip3", +] + +[[package]] +name = "hashbrown" +version = "0.15.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9229cfe53dfd69f0609a49f65461bd93001ea1ef889cd5529dd176593f5338a1" +dependencies = [ + "foldhash", +] + +[[package]] +name = "hashbrown" +version = "0.16.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "841d1cc9bed7f9236f321df977030373f4a4163ae1a7dbfe1a51a2c1a51d9100" + +[[package]] +name = "heck" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea" + +[[package]] +name = "id-arena" +version = "2.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3d3067d79b975e8844ca9eb072e16b31c3c1c36928edf9c6789548c524d0d954" + +[[package]] +name = "indexmap" +version = "2.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7714e70437a7dc3ac8eb7e6f8df75fd8eb422675fc7678aff7364301092b1017" +dependencies = [ + "equivalent", + "hashbrown 0.16.1", + "serde", + "serde_core", ] [[package]] name = "intrusive-collections" -version = "0.9.7" +version = "0.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "189d0897e4cbe8c75efedf3502c18c887b05046e59d28404d4d8e46cbc4d1e86" +checksum = "ec0375b6b871e424e9e052e1107d57dc6952f77ff882bd4bf74333a833779bab" dependencies = [ "memoffset", ] @@ -238,6 +317,12 @@ version = "1.0.17" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "92ecc6618181def0457392ccd0ee51198e065e016d1d527a7ac1b6dc7c1f09d2" +[[package]] +name = "leb128fmt" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "09edd9e8b54e49e587e4f6295a7d29c3ea94d469cb40ab8ca70b288248a81db2" + [[package]] name = "libc" version = "0.2.182" @@ -408,12 +493,13 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "439ee305def115ba05938db6eb1644ff94165c5ab5e9420d1c1bcedbba909391" [[package]] -name = "ppv-lite86" -version = "0.2.21" +name = "prettyplease" +version = "0.2.37" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "85eae3c4ed2f50dcfe72643da4befc30deadb458a9b590d720cde2f2b1e97da9" +checksum = "479ca8adacdd7ce8f1fb39ce9ecccbfe93a3f1344b3d0d97f20bc0196208f62b" dependencies = [ - "zerocopy", + "proc-macro2", + "syn", ] [[package]] @@ -442,32 +528,20 @@ checksum = "69cdb34c158ceb288df11e18b4bd39de994f6657d83847bdffdbd7f346754b0f" [[package]] name = "rand" -version = "0.9.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6db2770f06117d490610c7488547d543617b21bfa07796d7a12f6f1bd53850d1" -dependencies = [ - "rand_chacha", - "rand_core", -] - -[[package]] -name = "rand_chacha" -version = "0.9.0" +version = "0.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d3022b5f1df60f26e1ffddd6c66e8aa15de382ae63b3a0c1bfc0e4d3e3f325cb" +checksum = "bc266eb313df6c5c09c1c7b1fbe2510961e5bcd3add930c1e31f7ed9da0feff8" dependencies = [ - "ppv-lite86", + "chacha20", + "getrandom", "rand_core", ] [[package]] name = "rand_core" -version = "0.9.5" +version = "0.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "76afc826de14238e6e8c374ddcc1fa19e374fd8dd986b0d2af0d02377261d83c" -dependencies = [ - "getrandom", -] +checksum = "0c8d0fd677905edcbeedbf2edb6494d676f0e98d54d5cf9bda0b061cb8fb8aba" [[package]] name = "redox_syscall" @@ -521,6 +595,21 @@ version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" +[[package]] +name = "semver" +version = "1.0.27" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d767eb0aabc880b29956c35734170f26ed551a859dbd361d140cdbeca61ab1e2" + +[[package]] +name = "serde" +version = "1.0.228" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9a8e94ea7f378bd32cbbd37198a4a91436180c5bb472411e48b5ec2e2124ae9e" +dependencies = [ + "serde_core", +] + [[package]] name = "serde_core" version = "1.0.228" @@ -541,6 +630,19 @@ dependencies = [ "syn", ] +[[package]] +name = "serde_json" +version = "1.0.149" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "83fc039473c5595ace860d8c4fafa220ff474b3fc6bfdb4293327f1a37e94d86" +dependencies = [ + "itoa", + "memchr", + "serde", + "serde_core", + "zmij", +] + [[package]] name = "signal-hook-registry" version = "1.4.8" @@ -675,6 +777,12 @@ version = "1.0.24" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e6e4313cd5fcd3dad5cafa179702e2b244f760991f45397d14d4ebf38247da75" +[[package]] +name = "unicode-xid" +version = "0.2.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ebc1c04c71510c7f702b52b7c350734c9ff1295c464a03335b00bb84fc54f853" + [[package]] name = "usertest" version = "0.1.0" @@ -700,6 +808,49 @@ dependencies = [ "wit-bindgen", ] +[[package]] +name = "wasip3" +version = "0.4.0+wasi-0.3.0-rc-2026-01-06" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5428f8bf88ea5ddc08faddef2ac4a67e390b88186c703ce6dbd955e1c145aca5" +dependencies = [ + "wit-bindgen", +] + +[[package]] +name = "wasm-encoder" +version = "0.244.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "990065f2fe63003fe337b932cfb5e3b80e0b4d0f5ff650e6985b1048f62c8319" +dependencies = [ + "leb128fmt", + "wasmparser", +] + +[[package]] +name = "wasm-metadata" +version = "0.244.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bb0e353e6a2fbdc176932bbaab493762eb1255a7900fe0fea1a2f96c296cc909" +dependencies = [ + "anyhow", + "indexmap", + "wasm-encoder", + "wasmparser", +] + +[[package]] +name = "wasmparser" +version = "0.244.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "47b807c72e1bac69382b3a6fb3dbe8ea4c0ed87ff5629b8685ae6b9a611028fe" +dependencies = [ + "bitflags", + "hashbrown 0.15.5", + "indexmap", + "semver", +] + [[package]] name = "windows-link" version = "0.2.1" @@ -794,23 +945,111 @@ name = "wit-bindgen" version = "0.51.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d7249219f66ced02969388cf2bb044a09756a083d0fab1e566056b04d9fbcaa5" +dependencies = [ + "wit-bindgen-rust-macro", +] + +[[package]] +name = "wit-bindgen-core" +version = "0.51.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ea61de684c3ea68cb082b7a88508a8b27fcc8b797d738bfc99a82facf1d752dc" +dependencies = [ + "anyhow", + "heck", + "wit-parser", +] + +[[package]] +name = "wit-bindgen-rust" +version = "0.51.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b7c566e0f4b284dd6561c786d9cb0142da491f46a9fbed79ea69cdad5db17f21" +dependencies = [ + "anyhow", + "heck", + "indexmap", + "prettyplease", + "syn", + "wasm-metadata", + "wit-bindgen-core", + "wit-component", +] + +[[package]] +name = "wit-bindgen-rust-macro" +version = "0.51.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0c0f9bfd77e6a48eccf51359e3ae77140a7f50b1e2ebfe62422d8afdaffab17a" +dependencies = [ + "anyhow", + "prettyplease", + "proc-macro2", + "quote", + "syn", + "wit-bindgen-core", + "wit-bindgen-rust", +] + +[[package]] +name = "wit-component" +version = "0.244.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9d66ea20e9553b30172b5e831994e35fbde2d165325bec84fc43dbf6f4eb9cb2" +dependencies = [ + "anyhow", + "bitflags", + "indexmap", + "log", + "serde", + "serde_derive", + "serde_json", + "wasm-encoder", + "wasm-metadata", + "wasmparser", + "wit-parser", +] + +[[package]] +name = "wit-parser" +version = "0.244.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ecc8ac4bc1dc3381b7f59c34f00b67e18f910c2c0f50015669dde7def656a736" +dependencies = [ + "anyhow", + "id-arena", + "indexmap", + "log", + "semver", + "serde", + "serde_derive", + "serde_json", + "unicode-xid", + "wasmparser", +] [[package]] name = "zerocopy" -version = "0.8.39" +version = "0.8.40" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "db6d35d663eadb6c932438e763b262fe1a70987f9ae936e60158176d710cae4a" +checksum = "a789c6e490b576db9f7e6b6d661bcc9799f7c0ac8352f56ea20193b2681532e5" dependencies = [ "zerocopy-derive", ] [[package]] name = "zerocopy-derive" -version = "0.8.39" +version = "0.8.40" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4122cd3169e94605190e77839c9a40d40ed048d305bfdc146e7df40ab0f3e517" +checksum = "f65c489a7071a749c849713807783f70672b28094011623e200cb86dcb835953" dependencies = [ "proc-macro2", "quote", "syn", ] + +[[package]] +name = "zmij" +version = "1.0.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b8848ee67ecc8aedbaf3e4122217aff892639231befc6a1b58d29fff4c2cabaa" diff --git a/Cargo.toml b/Cargo.toml index 98527b19..3be11f8e 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,13 @@ [workspace] members = ["libkernel", "moss-macros", "usertest"] +[workspace.dependencies] +async-trait = "0.1.89" +bitflags = "2.11" +log = "0.4" +paste = "1.0.15" +rand = { version = "0.10", default-features = false } + [workspace.lints.clippy] semicolon_if_nothing_returned = "warn" uninlined_format_args = "warn" @@ -18,20 +25,21 @@ bench = false [dependencies] libkernel = { path = "libkernel" } moss-macros = { path = "moss-macros" } + aarch64-cpu = "11.1.0" arm-pl011-uart = { version = "0.4.0", default-features = false } -tock-registers = "0.10.1" -log = "0.4.27" +async-trait = { workspace = true } +bitflags = { workspace = true } fdt-parser = "0.4.16" -paste = "1.0.15" -object = { version = "0.38.0", default-features = false, features = ["core", "elf", "read_core"] } -async-trait = "0.1.88" +futures = { version = "0.3.31", default-features = false, features = ["alloc", "async-await"] } getargs = { version = "0.5.0", default-features = false } +log = { workspace = true } +object = { version = "0.38.0", default-features = false, features = ["core", "elf", "read_core"] } +paste = { workspace = true } ringbuf = { version = "0.4.8", default-features = false, features = ["alloc"] } -bitflags = "2.9.1" -futures = { version = "0.3.31", default-features = false, features = ["alloc", "async-await"] } -rand = { version = "0.9.2", default-features = false, features = ["small_rng"] } +rand = { workspace = true } rustc-hash = { version = "2.1", default-features = false } +tock-registers = "0.10.1" [build-dependencies] time = { version = "0.3.47", features = ["formatting", "macros"] } # For build timestamping via build.rs diff --git a/libkernel/Cargo.toml b/libkernel/Cargo.toml index f4d6425b..3e0befaa 100644 --- a/libkernel/Cargo.toml +++ b/libkernel/Cargo.toml @@ -4,19 +4,19 @@ version = "0.0.0" edition = "2024" [dependencies] +async-trait = { workspace = true } +bitflags = { workspace = true } ext4-view = { git = "https://github.com/arihant2math/ext4-view-rs.git", branch = "main" } -paste = "1.0.15" -thiserror = { version = "2.0.12", default-features = false } -tock-registers = "0.10.1" -log = "0.4.27" -async-trait = "0.1.88" +intrusive-collections = { version = "0.10.0", default-features = false } +log = { workspace = true } object = { version = "0.38.0", default-features = false, features = ["core", "elf", "read_core"] } -bitflags = "2.9.1" +paste = { workspace = true } ringbuf = { version = "0.4.8", default-features = false, features = ["alloc"] } -intrusive-collections = { version = "0.9.7", default-features = false } +thiserror = { version = "2.0.12", default-features = false } +tock-registers = "0.10.1" [dev-dependencies] -rand = "0.9.1" +rand = { workspace = true, features = ["default"] } tokio = { version = "1.47.1", features = ["full"] } [lints] diff --git a/libkernel/src/fs/filesystems/ext4/mod.rs b/libkernel/src/fs/filesystems/ext4/mod.rs index a94e8b24..e20d8443 100644 --- a/libkernel/src/fs/filesystems/ext4/mod.rs +++ b/libkernel/src/fs/filesystems/ext4/mod.rs @@ -5,6 +5,7 @@ #![allow(unused_imports)] use crate::error::FsError; +use crate::fs::path::Path; use crate::fs::pathbuf::PathBuf; use crate::fs::{DirStream, Dirent}; use crate::proc::ids::{Gid, Uid}; @@ -28,9 +29,11 @@ use async_trait::async_trait; use core::error::Error; use core::marker::PhantomData; use core::num::NonZeroU32; +use core::time::Duration; use ext4_view::{ - AsyncIterator, AsyncSkip, Ext4, Ext4Read, Ext4Write, File, FollowSymlinks, Metadata, ReadDir, - get_dir_entry_inode_by_name, + AsyncIterator, AsyncSkip, Ext4, Ext4Read, Ext4Write, File, FollowSymlinks, + InodeCreationOptions, InodeFlags, InodeMode, Metadata, ReadDir, get_dir_entry_inode_by_name, + write_at, }; use log::error; @@ -61,7 +64,11 @@ impl From for KernelError { match err { ext4_view::Ext4Error::NotFound => KernelError::Fs(FsError::NotFound), ext4_view::Ext4Error::NotADirectory => KernelError::Fs(FsError::NotADirectory), - ext4_view::Ext4Error::Corrupt(_) => KernelError::Fs(FsError::InvalidFs), + ext4_view::Ext4Error::AlreadyExists => KernelError::Fs(FsError::AlreadyExists), + ext4_view::Ext4Error::Corrupt(c) => { + error!("Corrupt EXT4 filesystem: {c}, likely a bug"); + KernelError::Fs(FsError::InvalidFs) + } e => { error!("Unmapped EXT4 error: {e:?}"); KernelError::Other("EXT4 error") @@ -199,24 +206,7 @@ where } let fs = self.fs_ref.upgrade().unwrap(); - let mut file = File::open_inode(&fs.inner, inner.clone())?; - - file.seek_to(offset).await?; - - // `ext4_view::File::write_bytes` may write fewer bytes than requested - // if the write crosses a block boundary. Loop until we've written - // all bytes. - let mut total_written = 0; - while total_written < buf.len() { - let bytes_written = file.write_bytes(&buf[total_written..]).await?; - if bytes_written == 0 { - break; // Should not happen unless disk is full - } - total_written += bytes_written; - } - - // Update inode metadata in case size changed. - *inner = file.into_inode(); + let total_written = write_at(&fs.inner, &mut inner, buf, offset).await?; Ok(total_written) } @@ -276,15 +266,94 @@ where async fn create( &self, - _name: &str, - _file_type: FileType, - _permissions: FilePermissions, + name: &str, + file_type: FileType, + permissions: FilePermissions, ) -> Result> { - Err(KernelError::NotSupported) + let fs = self.fs_ref.upgrade().unwrap(); + let mut inner = self.inner.lock().await; + let mut new_inode = if matches!(file_type, FileType::File) { + fs.inner + .create_inode(InodeCreationOptions { + file_type: ext4_view::FileType::Regular, + mode: InodeMode::S_IFREG | InodeMode::from_bits(permissions.bits()).unwrap(), + uid: 0, + gid: 0, + time: Default::default(), + flags: InodeFlags::empty(), + }) + .await? + } else if matches!(file_type, FileType::Directory) { + let old_links_count = inner.links_count(); + inner.set_links_count(old_links_count + 1); + let mut inode = fs + .inner + .create_inode(InodeCreationOptions { + file_type: ext4_view::FileType::Directory, + mode: InodeMode::S_IFDIR | InodeMode::from_bits(permissions.bits()).unwrap(), + uid: 0, + gid: 0, + time: Default::default(), + flags: InodeFlags::empty(), + }) + .await?; + ext4_view::init_directory(&fs.inner, &mut inode, inner.index).await?; + inode + } else { + return Err(KernelError::NotSupported); + }; + fs.inner + .link(&inner, name.to_string(), &mut new_inode) + .await?; + let new_path = self.path.join(name); + Ok(Arc::new(Ext4Inode:: { + fs_ref: self.fs_ref.clone(), + id: new_inode.index, + inner: Mutex::new(new_inode), + path: new_path, + })) + } + + async fn link(&self, name: &str, inode: Arc) -> Result<()> { + let inner = self.inner.lock().await; + if inner.file_type() != ext4_view::FileType::Directory { + return Err(KernelError::NotSupported); + } + let fs = self.fs_ref.upgrade().unwrap(); + // TODO: This forces the other inode out of sync + // Check fs ids match + if inode.id().fs_id() != fs.id() { + return Err(KernelError::Fs(FsError::CrossDevice)); + } + let mut other_inode = ext4_view::Inode::read( + &fs.inner, + (inode.id().inode_id() as u32).try_into().unwrap(), + ) + .await?; + let file_type = other_inode.file_type(); + fs.inner + .link(&inner, name.to_string(), &mut other_inode) + .await?; + Ok(()) } - async fn unlink(&self, _name: &str) -> Result<()> { - Err(KernelError::NotSupported) + async fn unlink(&self, name: &str) -> Result<()> { + let inner = self.inner.lock().await; + if inner.file_type() != ext4_view::FileType::Directory { + return Err(KernelError::NotSupported); + } + let fs = self.fs_ref.upgrade().unwrap(); + let child_inode = get_dir_entry_inode_by_name( + &fs.inner, + &inner, + ext4_view::DirEntryName::try_from(name) + .map_err(|_| KernelError::Fs(FsError::InvalidInput))?, + ) + .await?; + fs.inner + .unlink(&inner, name.to_string(), child_inode) + .await?; + Ok(()) } async fn readdir(&self, start_offset: u64) -> Result> { @@ -313,6 +382,115 @@ where .map(|p| PathBuf::from(p.to_str().unwrap()))?) } + async fn rename_from( + &self, + old_parent: Arc, + old_name: &str, + new_name: &str, + no_replace: bool, + ) -> Result<()> { + if old_name == new_name && old_parent.id().inode_id() == self.id().inode_id() { + return Ok(()); + } + + let old_parent_id = old_parent.id(); + let fs = self.fs_ref.upgrade().unwrap(); + + let old_parent_inode = ext4_view::Inode::read( + &fs.inner, + (old_parent_id.inode_id() as u32).try_into().unwrap(), + ) + .await?; + + let inner = self.inner.lock().await; + + // inode being moved (source) + let mut child_inode = get_dir_entry_inode_by_name( + &fs.inner, + &old_parent_inode, + ext4_view::DirEntryName::try_from(old_name) + .map_err(|_| KernelError::Fs(FsError::InvalidInput))?, + ) + .await?; + + // Check if destination exists and handle overwrite constraints. + let dst_lookup = get_dir_entry_inode_by_name( + &fs.inner, + &inner, + ext4_view::DirEntryName::try_from(new_name) + .map_err(|_| KernelError::Fs(FsError::InvalidInput))?, + ) + .await; + + if no_replace && dst_lookup.is_ok() { + return Err(KernelError::Fs(FsError::AlreadyExists)); + } + + if let Ok(target_inode) = dst_lookup { + let target_kind = target_inode.file_type(); + let source_kind = child_inode.file_type(); + + if target_kind == ext4_view::FileType::Directory { + let target_is_empty = fs + .inner + .read_dir(&self.path.join(new_name)) + .await? + .all(|e| { + let Ok(entry) = e else { + // If we fail to read the directory, be conservative and treat it as non-empty. + return false; + }; + let name = entry.file_name().as_str().unwrap(); + name == "." || name == ".." + }) + .await; + + if !target_is_empty { + return Err(KernelError::Fs(FsError::DirectoryNotEmpty)); + } + if source_kind != ext4_view::FileType::Directory { + return Err(KernelError::Fs(FsError::IsADirectory)); + } + } else if source_kind == ext4_view::FileType::Directory { + // Can't replace non-directory with a directory. + return Err(KernelError::Fs(FsError::NotADirectory)); + } + + // Overwrite: remove destination entry first. + fs.inner + .unlink(&inner, new_name.to_string(), target_inode) + .await?; + } + + // Link into destination parent, then unlink from source parent. + fs.inner + .link(&inner, new_name.to_string(), &mut child_inode) + .await?; + fs.inner + .unlink(&old_parent_inode, old_name.to_string(), child_inode) + .await?; + Ok(()) + } + + async fn symlink(&self, name: &str, target: &Path) -> Result<()> { + let inner = self.inner.lock().await; + if inner.file_type() != ext4_view::FileType::Directory { + return Err(KernelError::NotSupported); + } + let fs = self.fs_ref.upgrade().unwrap(); + fs.inner + .symlink( + &inner, + name.to_string(), + ext4_view::PathBuf::new(target.as_str().as_bytes()), + 0, + 0, + Duration::from_secs(0), + ) + .await?; + Ok(()) + } + async fn sync(&self) -> Result<()> { let mut inner = self.inner.lock().await; let fs = self.fs_ref.upgrade().ok_or(FsError::InvalidFs)?; diff --git a/libkernel/src/memory/allocators/frame.rs b/libkernel/src/memory/allocators/frame.rs index 3a7e5dae..87ebcd55 100644 --- a/libkernel/src/memory/allocators/frame.rs +++ b/libkernel/src/memory/allocators/frame.rs @@ -42,7 +42,7 @@ pub struct Frame { pub pfn: PageFrame, } -intrusive_adapter!(pub FrameAdapter = UnsafeRef: Frame { link: LinkedListLink }); +intrusive_adapter!(pub FrameAdapter = UnsafeRef: Frame { link => LinkedListLink }); impl Frame { pub fn new(pfn: PageFrame) -> Self { diff --git a/libkernel/src/memory/allocators/slab/heap.rs b/libkernel/src/memory/allocators/slab/heap.rs index b6dbdfc8..3cb03328 100644 --- a/libkernel/src/memory/allocators/slab/heap.rs +++ b/libkernel/src/memory/allocators/slab/heap.rs @@ -179,7 +179,7 @@ mod tests { }, test::MockCpuOps, }; - use rand::{Rng, rng}; + use rand::{RngExt, rng}; use std::{ cell::RefCell, ops::{Deref, DerefMut}, diff --git a/libkernel/src/memory/allocators/smalloc.rs b/libkernel/src/memory/allocators/smalloc.rs index 27a645c0..4c1b6a0c 100644 --- a/libkernel/src/memory/allocators/smalloc.rs +++ b/libkernel/src/memory/allocators/smalloc.rs @@ -507,7 +507,7 @@ mod tests { ops::{Deref, DerefMut}, }; - use rand::{Rng, SeedableRng}; + use rand::{RngExt, SeedableRng}; use crate::{ error::KernelError, diff --git a/moss-macros/Cargo.toml b/moss-macros/Cargo.toml index d26745d9..036eaf44 100644 --- a/moss-macros/Cargo.toml +++ b/moss-macros/Cargo.toml @@ -8,8 +8,8 @@ proc-macro = true [dependencies] proc-macro2 = "1.0" -syn = "2.0" quote = "1.0" +syn = "2.0" [lints] workspace = true diff --git a/src/arch/arm64/exceptions/syscall.rs b/src/arch/arm64/exceptions/syscall.rs index 2a7fd08a..ae84d00b 100644 --- a/src/arch/arm64/exceptions/syscall.rs +++ b/src/arch/arm64/exceptions/syscall.rs @@ -201,6 +201,7 @@ pub async fn handle_syscall() { 0x18 => sys_dup3(arg1.into(), arg2.into(), arg3 as _), 0x19 => sys_fcntl(arg1.into(), arg2 as _, arg3 as _).await, 0x1d => sys_ioctl(arg1.into(), arg2 as _, arg3 as _).await, + 0x20 => Ok(0), // sys_flock is a noop 0x22 => sys_mkdirat(arg1.into(), TUA::from_value(arg2 as _), arg3 as _).await, 0x23 => sys_unlinkat(arg1.into(), TUA::from_value(arg2 as _), arg3 as _).await, 0x24 => { diff --git a/src/kernel/rand.rs b/src/kernel/rand.rs index 0588ac40..fd471581 100644 --- a/src/kernel/rand.rs +++ b/src/kernel/rand.rs @@ -8,7 +8,7 @@ use crate::{ use alloc::vec::Vec; use libkernel::error::Result; use libkernel::memory::address::TUA; -use rand::{RngCore, SeedableRng, rngs::SmallRng}; +use rand::{Rng, SeedableRng, rngs::SmallRng}; pub async fn sys_getrandom(ubuf: TUA, size: isize, _flags: u32) -> Result { let buf = {