diff --git a/Cargo.lock b/Cargo.lock index 8539206aef..701297394e 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -192,7 +192,7 @@ dependencies = [ "axruntime", "axsync", "axtask", - "bindgen", + "bindgen 0.72.1", "ctor_bare", "flatten_objects", "lazy_static", @@ -202,12 +202,12 @@ dependencies = [ [[package]] name = "arm-gic-driver" -version = "0.15.5" +version = "0.15.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "234fbc75ee659ae0fa44cdbe9a61f84cc4a107b024efd872e7ad56ad82f9ab08" +checksum = "f251a1a74133f802b55eaf5e340107b0024457aa9b2ac3c72074501bfa8509a5" dependencies = [ "aarch64-cpu 10.0.0", - "bitflags 2.9.2", + "bitflags 2.9.4", "enum_dispatch", "log", "paste", @@ -458,6 +458,7 @@ dependencies = [ "fatfs", "lazyinit", "log", + "lwext4_rust", ] [[package]] @@ -489,7 +490,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "dcba2006898d7879d456a9c34b9c9460cb536f5bf69d1d5d7d0e0f19f073368d" dependencies = [ "axerrno", - "bitflags 2.9.2", + "bitflags 2.9.4", "log", ] @@ -547,7 +548,7 @@ dependencies = [ "axerrno", "axfeat", "axio", - "bindgen", + "bindgen 0.72.1", ] [[package]] @@ -611,7 +612,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f4de04c54b63bf2ca1ff202733d2516da49d7779649cdb2f9c4ecf22909e6810" dependencies = [ "axplat-macros", - "bitflags 2.9.2", + "bitflags 2.9.4", "const-str", "crate_interface", "handler_table", @@ -751,7 +752,7 @@ dependencies = [ "axconfig-macros", "axcpu", "axplat", - "bitflags 2.9.2", + "bitflags 2.9.4", "heapless 0.9.1", "int_ratio", "kspin", @@ -759,7 +760,7 @@ dependencies = [ "log", "multiboot", "percpu", - "raw-cpuid 11.5.0", + "raw-cpuid 11.6.0", "uart_16550", "x2apic", "x86", @@ -861,11 +862,31 @@ dependencies = [ [[package]] name = "bindgen" -version = "0.72.0" +version = "0.71.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4f72209734318d0b619a5e0f5129918b848c416e122a3c4ce054e03cb87b726f" +checksum = "5f58bf3d7db68cfbac37cfc485a8d711e87e064c3d0fe0435b92f7a407f9d6b3" dependencies = [ - "bitflags 2.9.2", + "bitflags 2.9.4", + "cexpr", + "clang-sys", + "itertools", + "log", + "prettyplease", + "proc-macro2", + "quote", + "regex", + "rustc-hash", + "shlex", + "syn 2.0.106", +] + +[[package]] +name = "bindgen" +version = "0.72.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "993776b509cfb49c750f11b8f07a46fa23e0a1386ffc01fb1e7d343efc387895" +dependencies = [ + "bitflags 2.9.4", "cexpr", "clang-sys", "itertools", @@ -887,9 +908,9 @@ checksum = "2b645c5c09a7d4035949cfce1a915785aaad6f17800c35fda8a8c311c491f284" [[package]] name = "bit_field" -version = "0.10.2" +version = "0.10.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dc827186963e592360843fb5ba4b973e145841266c1357f7180c43526f2e5b61" +checksum = "1e4b40c7323adcfc0a41c4b88143ed58346ff65a288fc144329c5c45e05d70c6" [[package]] name = "bitflags" @@ -899,9 +920,9 @@ checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" [[package]] name = "bitflags" -version = "2.9.2" +version = "2.9.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6a65b545ab31d687cff52899d4890855fec459eb6afe0da6417b8a18da87aa29" +checksum = "2261d10cca569e4643e526d8dc2e62e433cc8aba21ab764233731f8d369bf394" [[package]] name = "bitmap-allocator" @@ -942,15 +963,16 @@ version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c9b24894fa5f73bbf9c72196e7f495a1f81d6218a548280a09ada4a937157692" dependencies = [ - "bitflags 2.9.2", + "bitflags 2.9.4", ] [[package]] name = "cc" -version = "1.2.33" +version = "1.2.36" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3ee0f8803222ba5a7e2777dd72ca451868909b1ac410621b676adf07280e9b5f" +checksum = "5252b3d2648e5eedbc1a6f501e3c795e07025c1e93bbf8bbdd6eef7f447a6d54" dependencies = [ + "find-msvc-tools", "shlex", ] @@ -996,9 +1018,9 @@ dependencies = [ [[package]] name = "clap" -version = "4.5.45" +version = "4.5.47" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1fc0e74a703892159f5ae7d3aac52c8e6c392f5ae5f359c70b5881d60aaac318" +checksum = "7eac00902d9d136acd712710d71823fb8ac8004ca445a89e73a41d45aa712931" dependencies = [ "clap_builder", "clap_derive", @@ -1006,9 +1028,9 @@ dependencies = [ [[package]] name = "clap_builder" -version = "4.5.44" +version = "4.5.47" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b3e7f4214277f3c7aa526a59dd3fbe306a370daee1f8b7b8c987069cd8e888a8" +checksum = "2ad9bbf750e73b5884fb8a211a9424a1906c1e156724260fdae972f31d70e1d6" dependencies = [ "anstream", "anstyle", @@ -1018,9 +1040,9 @@ dependencies = [ [[package]] name = "clap_derive" -version = "4.5.45" +version = "4.5.47" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "14cb31bb0a7d536caef2639baa7fad459e15c3144efefa6dbd1c84562c4739f6" +checksum = "bbfd7eae0b0f1a6e63d4b13c9c478de77c2eb546fba158ad50b4203dc24b9f9c" dependencies = [ "heck", "proc-macro2", @@ -1195,10 +1217,16 @@ name = "fatfs" version = "0.4.0" source = "git+https://github.com/rafalh/rust-fatfs?rev=4eccb50#4eccb50d011146fbed20e133d33b22f3c27292e7" dependencies = [ - "bitflags 2.9.2", + "bitflags 2.9.4", "log", ] +[[package]] +name = "find-msvc-tools" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7fd99930f64d146689264c637b5af2f0233a933bef0d8570e2526bf9e083192d" + [[package]] name = "flatten_objects" version = "0.2.4" @@ -1331,9 +1359,9 @@ dependencies = [ [[package]] name = "indexmap" -version = "2.10.0" +version = "2.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fe4cd85333e22411419a0bcae1297d25e58c9443848b11dc6a86fefe8c78a661" +checksum = "f2481980430f9f78649238835720ddccc57e52df14ffce1c6f37391d61b563e9" dependencies = [ "equivalent", "hashbrown", @@ -1374,9 +1402,9 @@ dependencies = [ [[package]] name = "js-sys" -version = "0.3.77" +version = "0.3.78" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1cfaf33c695fc6e08064efbc1f72ec937429614f25eef83af942d0e227c3a28f" +checksum = "0c0b063578492ceec17683ef2f8c5e89121fbd0b172cbc280635ab7567db2738" dependencies = [ "once_cell", "wasm-bindgen", @@ -1482,7 +1510,16 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7c9f0d275c70310e2a9d2fc23250c5ac826a73fa828a5f256401f85c5c554283" dependencies = [ "bit_field", - "bitflags 2.9.2", + "bitflags 2.9.4", +] + +[[package]] +name = "lwext4_rust" +version = "0.2.0" +source = "git+https://github.com/Josen-B/lwext4_rust.git#99b3e5c7262718db2002411fe55ea0362a23fdfc" +dependencies = [ + "bindgen 0.71.1", + "log", ] [[package]] @@ -1571,7 +1608,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ba811ef8ca8fb33d776e128624cb4fe25c9804cab96f83b822d4322431e6dd5a" dependencies = [ "aarch64-cpu 10.0.0", - "bitflags 2.9.2", + "bitflags 2.9.4", "memory_addr", "x86_64", ] @@ -1626,7 +1663,7 @@ version = "0.2.21" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "85eae3c4ed2f50dcfe72643da4befc30deadb458a9b590d720cde2f2b1e97da9" dependencies = [ - "zerocopy 0.8.26", + "zerocopy 0.8.27", ] [[package]] @@ -1725,18 +1762,18 @@ dependencies = [ [[package]] name = "raw-cpuid" -version = "11.5.0" +version = "11.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c6df7ab838ed27997ba19a4664507e6f82b41fe6e20be42929332156e5e85146" +checksum = "498cd0dc59d73224351ee52a95fee0f1a617a2eae0e7d9d720cc622c73a54186" dependencies = [ - "bitflags 2.9.2", + "bitflags 2.9.4", ] [[package]] name = "regex" -version = "1.11.1" +version = "1.11.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b544ef1b4eac5dc2db33ea63606ae9ffcfac26c1416a2806ae0bf5f56b201191" +checksum = "23d7fd106d8c02486a8d64e778353d1cffe08ce79ac2e82f540c86d0facf6912" dependencies = [ "aho-corasick", "memchr", @@ -1746,9 +1783,9 @@ dependencies = [ [[package]] name = "regex-automata" -version = "0.4.9" +version = "0.4.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "809e8dc61f6de73b46c85f4c96486310fe304c434cfa43669d7b40f711150908" +checksum = "6b9458fa0bfeeac22b5ca447c63aaf45f28439a709ccd244698632f9aa6394d6" dependencies = [ "aho-corasick", "memchr", @@ -1757,9 +1794,9 @@ dependencies = [ [[package]] name = "regex-syntax" -version = "0.8.5" +version = "0.8.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2b15c43186be67a4fd63bee50d0303afffcef381492ebe2c5d87f324e1b8815c" +checksum = "caf4aa5b0f434c91fe5c7f1ecb6a5ece2130b02ad2a590589dda5146df959001" [[package]] name = "riscv" @@ -2038,7 +2075,7 @@ version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "94d293f51425981fdb1b766beae254dbb711a17e8c4b549dc69b9b7ee0d478d5" dependencies = [ - "bitflags 2.9.2", + "bitflags 2.9.4", "rustversion", "x86", ] @@ -2067,7 +2104,7 @@ version = "0.7.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "aa40e09453618c7a927c08c5a990497a2954da7c2aaa6c65e0d4f0fc975f6114" dependencies = [ - "bitflags 2.9.2", + "bitflags 2.9.4", "log", "zerocopy 0.7.35", ] @@ -2092,30 +2129,31 @@ checksum = "442887c63f2c839b346c192d047a7c87e73d0689c9157b00b53dcc27dd5ea793" [[package]] name = "wasi" -version = "0.14.2+wasi-0.2.4" +version = "0.14.4+wasi-0.2.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9683f9a5a998d873c0d21fcbe3c083009670149a8fab228644b8bd36b2c48cb3" +checksum = "88a5f4a424faf49c3c2c344f166f0662341d470ea185e939657aaff130f0ec4a" dependencies = [ - "wit-bindgen-rt", + "wit-bindgen", ] [[package]] name = "wasm-bindgen" -version = "0.2.100" +version = "0.2.101" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1edc8929d7499fc4e8f0be2262a241556cfc54a0bea223790e71446f2aab1ef5" +checksum = "7e14915cadd45b529bb8d1f343c4ed0ac1de926144b746e2710f9cd05df6603b" dependencies = [ "cfg-if", "once_cell", "rustversion", "wasm-bindgen-macro", + "wasm-bindgen-shared", ] [[package]] name = "wasm-bindgen-backend" -version = "0.2.100" +version = "0.2.101" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2f0a0651a5c2bc21487bde11ee802ccaf4c51935d0d3d42a6101f98161700bc6" +checksum = "e28d1ba982ca7923fd01448d5c30c6864d0a14109560296a162f80f305fb93bb" dependencies = [ "bumpalo", "log", @@ -2127,9 +2165,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro" -version = "0.2.100" +version = "0.2.101" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7fe63fc6d09ed3792bd0897b314f53de8e16568c2b3f7982f468c0bf9bd0b407" +checksum = "7c3d463ae3eff775b0c45df9da45d68837702ac35af998361e2c84e7c5ec1b0d" dependencies = [ "quote", "wasm-bindgen-macro-support", @@ -2137,9 +2175,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro-support" -version = "0.2.100" +version = "0.2.101" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8ae87ea40c9f689fc23f209965b6fb8a99ad69aeeb0231408be24920604395de" +checksum = "7bb4ce89b08211f923caf51d527662b75bdc9c9c7aab40f86dcb9fb85ac552aa" dependencies = [ "proc-macro2", "quote", @@ -2150,9 +2188,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-shared" -version = "0.2.100" +version = "0.2.101" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1a05d73b933a847d6cccdda8f838a22ff101ad9bf93e33684f39c1f5f0eece3d" +checksum = "f143854a3b13752c6950862c906306adb27c7e839f7414cec8fea35beab624c1" dependencies = [ "unicode-ident", ] @@ -2292,21 +2330,18 @@ checksum = "271414315aff87387382ec3d271b52d7ae78726f5d44ac98b4f4030c91880486" [[package]] name = "winnow" -version = "0.7.12" +version = "0.7.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f3edebf492c8125044983378ecb5766203ad3b4c2f7a922bd7dd207f6d443e95" +checksum = "21a0236b59786fed61e2a80582dd500fe61f18b5dca67a4a067d0bc9039339cf" dependencies = [ "memchr", ] [[package]] -name = "wit-bindgen-rt" -version = "0.39.0" +name = "wit-bindgen" +version = "0.45.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6f42320e61fe2cfd34354ecb597f86f413484a798ba44a8ca1165c58d42da6c1" -dependencies = [ - "bitflags 2.9.2", -] +checksum = "5c573471f125075647d03df72e026074b7203790d41351cd6edc96f46bcccd36" [[package]] name = "x2apic" @@ -2339,7 +2374,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0f042214de98141e9c8706e8192b73f56494087cc55ebec28ce10f26c5c364ae" dependencies = [ "bit_field", - "bitflags 2.9.2", + "bitflags 2.9.4", "rustversion", "volatile 0.4.6", ] @@ -2366,11 +2401,11 @@ dependencies = [ [[package]] name = "zerocopy" -version = "0.8.26" +version = "0.8.27" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1039dd0d3c310cf05de012d8a39ff557cb0d23087fd44cad61df08fc31907a2f" +checksum = "0894878a5fa3edfd6da3f88c4805f4c8558e2b996227a3d864f47fe11e38282c" dependencies = [ - "zerocopy-derive 0.8.26", + "zerocopy-derive 0.8.27", ] [[package]] @@ -2386,9 +2421,9 @@ dependencies = [ [[package]] name = "zerocopy-derive" -version = "0.8.26" +version = "0.8.27" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9ecf5b4cc5364572d7f4c329661bcc82724222973f2cab6f050a4e5c22f75181" +checksum = "88d2b8d9c68ad2b9e4340d7832716a4d21a22a1154777ad56ea55c51a9cf3831" dependencies = [ "proc-macro2", "quote", diff --git a/api/axfeat/Cargo.toml b/api/axfeat/Cargo.toml index 2837535231..9c140b6e57 100644 --- a/api/axfeat/Cargo.toml +++ b/api/axfeat/Cargo.toml @@ -46,6 +46,8 @@ sched-cfs = ["axtask/sched-cfs", "irq"] # File system fs = ["alloc", "paging", "axdriver/virtio-blk", "dep:axfs", "axruntime/fs"] # TODO: try to remove "paging" myfs = ["axfs?/myfs"] +ext4fs = ["axfs?/ext4fs"] +fatfs = ["axfs?/fatfs"] # Networking net = ["alloc", "paging", "axdriver/virtio-net", "dep:axnet", "axruntime/net"] diff --git a/modules/axfs/Cargo.toml b/modules/axfs/Cargo.toml index e8768f2b2a..36ff41fcb5 100644 --- a/modules/axfs/Cargo.toml +++ b/modules/axfs/Cargo.toml @@ -14,6 +14,7 @@ devfs = ["dep:axfs_devfs"] ramfs = ["dep:axfs_ramfs"] procfs = ["dep:axfs_ramfs"] sysfs = ["dep:axfs_ramfs"] +ext4fs = ["dep:lwext4_rust"] fatfs = ["dep:fatfs"] myfs = ["dep:crate_interface"] use-ramdisk = [] @@ -33,6 +34,7 @@ axfs_ramfs = { version = "0.1", optional = true } crate_interface = { version = "0.1", optional = true } axsync = { workspace = true } axdriver = { workspace = true, features = ["block"] } +lwext4_rust = { git = "https://github.com/Josen-B/lwext4_rust.git", optional = true } axdriver_block = { git = "https://github.com/arceos-org/axdriver_crates.git", tag = "v0.1.2" } axns = { workspace = true } diff --git a/modules/axfs/src/fs/ext4fs.rs b/modules/axfs/src/fs/ext4fs.rs new file mode 100644 index 0000000000..abebf28cee --- /dev/null +++ b/modules/axfs/src/fs/ext4fs.rs @@ -0,0 +1,377 @@ +use crate::alloc::string::{String, ToString}; +use alloc::sync::Arc; +pub use axdriver_block::DevError; +use axerrno::AxError; +use axfs_vfs::{ + VfsDirEntry, VfsError, VfsNodeAttr, VfsNodeOps, VfsNodePerm, VfsNodeRef, VfsNodeType, VfsOps, + VfsResult, +}; +use axsync::Mutex; +use lwext4_rust::bindings::{ + O_CREAT, O_RDONLY, O_RDWR, O_TRUNC, O_WRONLY, SEEK_CUR, SEEK_END, SEEK_SET, +}; +use lwext4_rust::{Ext4BlockWrapper, Ext4File, InodeTypes, KernelDevOp}; + +use crate::dev::Disk; +pub const BLOCK_SIZE: usize = 512; + +#[allow(dead_code)] +pub struct Ext4FileSystem { + inner: Ext4BlockWrapper, + root: VfsNodeRef, +} + +unsafe impl Sync for Ext4FileSystem {} +unsafe impl Send for Ext4FileSystem {} + +impl Ext4FileSystem { + #[cfg(feature = "use-ramdisk")] + pub fn new(mut disk: Disk) -> Self { + unimplemented!() + } + + #[cfg(not(feature = "use-ramdisk"))] + pub fn new(disk: Disk) -> Self { + info!( + "Got Disk size:{}, position:{}", + disk.size(), + disk.position() + ); + let inner = + Ext4BlockWrapper::::new(disk).expect("failed to initialize EXT4 filesystem"); + let root = Arc::new(FileWrapper::new("/", InodeTypes::EXT4_DE_DIR)); + Self { inner, root } + } +} + +/// The [`VfsOps`] trait provides operations on a filesystem. +impl VfsOps for Ext4FileSystem { + fn root_dir(&self) -> VfsNodeRef { + debug!("Get root_dir"); + Arc::clone(&self.root) + } +} + +pub struct FileWrapper(Mutex); + +unsafe impl Send for FileWrapper {} +unsafe impl Sync for FileWrapper {} + +impl FileWrapper { + fn new(path: &str, types: InodeTypes) -> Self { + info!("FileWrapper new {:?} {}", types, path); + Self(Mutex::new(Ext4File::new(path, types))) + } + + fn path_deal_with(&self, path: &str) -> String { + if path.starts_with('/') { + debug!("path_deal_with: {}", path); + } + let trim_path = path.trim_matches('/'); + if trim_path.is_empty() || trim_path == "." { + return String::new(); + } + + if let Some(rest) = trim_path.strip_prefix("./") { + //if starts with "./" + return self.path_deal_with(rest); + } + let rest_p = trim_path.replace("//", "/"); + if trim_path != rest_p { + return self.path_deal_with(&rest_p); + } + let file = self.0.lock(); + let path = file.get_path(); + let fpath = String::from(path.to_str().unwrap().trim_end_matches('/')) + "/" + trim_path; + debug!("dealt with full path: {}", fpath.as_str()); + fpath + } +} + +/// The [`VfsNodeOps`] trait provides operations on a file or a directory. +impl VfsNodeOps for FileWrapper { + fn get_attr(&self) -> VfsResult { + let mut file = self.0.lock(); + let perm = file.file_mode_get().unwrap_or(0o755); + let perm = VfsNodePerm::from_bits_truncate((perm as u16) & 0o777); + let vtype = file.file_type_get(); + let vtype = match vtype { + InodeTypes::EXT4_INODE_MODE_FIFO => VfsNodeType::Fifo, + InodeTypes::EXT4_INODE_MODE_CHARDEV => VfsNodeType::CharDevice, + InodeTypes::EXT4_INODE_MODE_DIRECTORY => VfsNodeType::Dir, + InodeTypes::EXT4_INODE_MODE_BLOCKDEV => VfsNodeType::BlockDevice, + InodeTypes::EXT4_INODE_MODE_FILE => VfsNodeType::File, + InodeTypes::EXT4_INODE_MODE_SOFTLINK => VfsNodeType::SymLink, + InodeTypes::EXT4_INODE_MODE_SOCKET => VfsNodeType::Socket, + _ => { + warn!("unknown file type: {:?}", vtype); + VfsNodeType::File + } + }; + let size = if vtype == VfsNodeType::File { + let path = file.get_path().to_str().unwrap().to_string(); + file.file_open(&path, O_RDONLY) + .map_err(|e| >::try_into(e).unwrap())?; + let fsize = file.file_size(); + file.file_close().expect("failed to close fd"); + fsize + } else { + 0 + }; + let blocks = (size + (BLOCK_SIZE as u64 - 1)) / BLOCK_SIZE as u64; + trace!( + "get_attr of {:?} {:?}, size: {}, blocks: {}", + vtype, + file.get_path(), + size, + blocks + ); + + Ok(VfsNodeAttr::new(perm, vtype, size, blocks)) + } + + fn create(&self, path: &str, ty: VfsNodeType) -> VfsResult { + debug!("create {:?} on Ext4fs: {}", ty, path); + let fpath = self.path_deal_with(path); + let fpath = fpath.as_str(); + if fpath.is_empty() { + return Ok(()); + } + let types = match ty { + VfsNodeType::Fifo => InodeTypes::EXT4_DE_FIFO, + VfsNodeType::CharDevice => InodeTypes::EXT4_DE_CHRDEV, + VfsNodeType::Dir => InodeTypes::EXT4_DE_DIR, + VfsNodeType::BlockDevice => InodeTypes::EXT4_DE_BLKDEV, + VfsNodeType::File => InodeTypes::EXT4_DE_REG_FILE, + VfsNodeType::SymLink => InodeTypes::EXT4_DE_SYMLINK, + VfsNodeType::Socket => InodeTypes::EXT4_DE_SOCK, + }; + + let mut file = self.0.lock(); + if file.check_inode_exist(fpath, types.clone()) { + Ok(()) + } else { + if types == InodeTypes::EXT4_DE_DIR { + file.dir_mk(fpath) + .map(|_v| ()) + .map_err(|e| e.try_into().unwrap()) + } else { + file.file_open(fpath, O_WRONLY | O_CREAT | O_TRUNC) + .expect("create file failed"); + file.file_close() + .map(|_v| ()) + .map_err(|e| e.try_into().unwrap()) + } + } + } + + fn remove(&self, path: &str) -> VfsResult { + debug!("remove ext4fs: {}", path); + let fpath = self.path_deal_with(path); + let fpath = fpath.as_str(); + assert!(!fpath.is_empty()); // already check at `root.rs` + let mut file = self.0.lock(); + if file.check_inode_exist(fpath, InodeTypes::EXT4_DE_DIR) { + // Recursive directory remove + file.dir_rm(fpath) + .map(|_v| ()) + .map_err(|e| e.try_into().unwrap()) + } else { + file.file_remove(fpath) + .map(|_v| ()) + .map_err(|e| e.try_into().unwrap()) + } + } + + /// Get the parent directory of this directory. + /// Return `None` if the node is a file. + fn parent(&self) -> Option { + let file = self.0.lock(); + if file.get_type() == InodeTypes::EXT4_DE_DIR { + let path = file.get_path().to_str().unwrap().to_string(); + debug!("Get the parent dir of {}", path); + let path = path.trim_end_matches('/').trim_end_matches(|c| c != '/'); + if !path.is_empty() { + return Some(Arc::new(Self::new(path, InodeTypes::EXT4_DE_DIR))); + } + } + None + } + + /// Read directory entries into `dirents`, starting from `start_idx`. + fn read_dir(&self, start_idx: usize, dirents: &mut [VfsDirEntry]) -> VfsResult { + let file = self.0.lock(); + let (names, inode_types) = file.lwext4_dir_entries().unwrap(); + for (i, out_entry) in dirents.iter_mut().enumerate() { + let iname = names.get(start_idx + i); + let itype = inode_types.get(start_idx + i); + match (iname, itype) { + (Some(name), Some(t)) => { + let ty = match t { + InodeTypes::EXT4_DE_DIR => VfsNodeType::Dir, + InodeTypes::EXT4_DE_REG_FILE => VfsNodeType::File, + InodeTypes::EXT4_DE_SYMLINK => VfsNodeType::SymLink, + _ => { + error!("unknown file type: {:?}", t); + unreachable!() + } + }; + *out_entry = VfsDirEntry::new(core::str::from_utf8(name).unwrap(), ty); + } + _ => return Ok(i), + } + } + Ok(dirents.len()) + } + + /// Lookup the node with given `path` in the directory. + /// Return the node if found. + fn lookup(self: Arc, path: &str) -> VfsResult { + trace!("lookup ext4fs: {:?}, {}", self.0.lock().get_path(), path); + let fpath = self.path_deal_with(path); + let fpath = fpath.as_str(); + if fpath.is_empty() { + return Ok(self.clone()); + } + let mut file = self.0.lock(); + if file.check_inode_exist(fpath, InodeTypes::EXT4_DE_DIR) { + trace!("lookup new DIR FileWrapper"); + Ok(Arc::new(Self::new(fpath, InodeTypes::EXT4_DE_DIR))) + } else if file.check_inode_exist(fpath, InodeTypes::EXT4_DE_REG_FILE) { + trace!("lookup new FILE FileWrapper"); + Ok(Arc::new(Self::new(fpath, InodeTypes::EXT4_DE_REG_FILE))) + } else { + Err(VfsError::NotFound) + } + } + + fn read_at(&self, offset: u64, buf: &mut [u8]) -> VfsResult { + trace!("To read_at {}, buf len={}", offset, buf.len()); + let mut file = self.0.lock(); + let path = file.get_path().to_str().unwrap().to_string(); + file.file_open(&path, O_RDONLY) + .map_err(|e| >::try_into(e).unwrap())?; + + file.file_seek(offset as i64, SEEK_SET) + .map_err(|e| >::try_into(e).unwrap())?; + let result = file.file_read(buf); + file.file_close().expect("failed to close fd"); + result.map_err(|e| e.try_into().unwrap()) + } + + fn write_at(&self, offset: u64, buf: &[u8]) -> VfsResult { + trace!("To write_at {}, buf len={}", offset, buf.len()); + let mut file = self.0.lock(); + let path = file.get_path().to_str().unwrap().to_string(); + file.file_open(&path, O_RDWR) + .map_err(|e| >::try_into(e).unwrap())?; + + file.file_seek(offset as i64, SEEK_SET) + .map_err(|e| >::try_into(e).unwrap())?; + let result = file.file_write(buf); + file.file_close().expect("failed to close fd"); + result.map_err(|e| e.try_into().unwrap()) + } + + fn truncate(&self, size: u64) -> VfsResult { + debug!("truncate file to size={}", size); + let mut file = self.0.lock(); + let path = file.get_path().to_str().unwrap().to_string(); + file.file_open(&path, O_RDWR | O_CREAT | O_TRUNC) + .map_err(|e| >::try_into(e).unwrap())?; + + let result = file.file_truncate(size); + file.file_close().expect("failed to close fd"); + result.map(|_| ()).map_err(|e| e.try_into().unwrap()) + } + + fn rename(&self, src_path: &str, dst_path: &str) -> VfsResult { + debug!("rename from {} to {}", src_path, dst_path); + let mut file = self.0.lock(); + file.file_rename(src_path, dst_path) + .map(|_| ()) + .map_err(|e| e.try_into().unwrap()) + } + + fn as_any(&self) -> &dyn core::any::Any { + self as &dyn core::any::Any + } +} + +impl Drop for FileWrapper { + fn drop(&mut self) { + let mut file = self.0.lock(); + debug!("Drop struct FileWrapper {:?}", file.get_path()); + file.file_close().expect("failed to close fd"); + drop(file); // todo + } +} + +impl KernelDevOp for Disk { + type DevType = Disk; + + fn read(dev: &mut Disk, mut buf: &mut [u8]) -> Result { + trace!("READ block device buf={}", buf.len()); + let mut read_len = 0; + while !buf.is_empty() { + match dev.read_one(buf) { + Ok(0) => break, + Ok(n) => { + buf = &mut buf[n..]; + read_len += n; + } + Err(_) => return Err(DevError::Io as i32), + } + } + trace!("READ rt len={}", read_len); + Ok(read_len) + } + + fn write(dev: &mut Self::DevType, mut buf: &[u8]) -> Result { + trace!("WRITE block device buf={}", buf.len()); + let mut write_len = 0; + while !buf.is_empty() { + match dev.write_one(buf) { + Ok(0) => break, + Ok(n) => { + buf = &buf[n..]; + write_len += n; + } + Err(_e) => return Err(DevError::Io as i32), + } + } + trace!("WRITE rt len={}", write_len); + Ok(write_len) + } + + fn flush(_dev: &mut Self::DevType) -> Result { + debug!("uncomplicated"); + Ok(0) + } + + fn seek(dev: &mut Disk, off: i64, whence: i32) -> Result { + let size = dev.size(); + trace!( + "SEEK block device size:{}, pos:{}, offset={}, whence={}", + size, + &dev.position(), + off, + whence + ); + let new_pos = match whence as u32 { + SEEK_SET => Some(off), + SEEK_CUR => dev.position().checked_add_signed(off).map(|v| v as i64), + SEEK_END => size.checked_add_signed(off).map(|v| v as i64), + _ => { + error!("invalid seek() whence: {}", whence); + Some(off) + } + } + .ok_or(DevError::Io as i32)?; + if new_pos as u64 > size { + warn!("Seek beyond the end of the block device"); + } + dev.set_position(new_pos as u64); + Ok(new_pos) + } +} diff --git a/modules/axfs/src/fs/mod.rs b/modules/axfs/src/fs/mod.rs index 77aad60f2c..8636249d56 100644 --- a/modules/axfs/src/fs/mod.rs +++ b/modules/axfs/src/fs/mod.rs @@ -1,6 +1,8 @@ cfg_if::cfg_if! { if #[cfg(feature = "myfs")] { pub mod myfs; + } else if #[cfg(feature = "ext4fs")] { + pub mod ext4fs; } else if #[cfg(feature = "fatfs")] { pub mod fatfs; } diff --git a/modules/axfs/src/root.rs b/modules/axfs/src/root.rs index afa3f937a2..dabda1ee8b 100644 --- a/modules/axfs/src/root.rs +++ b/modules/axfs/src/root.rs @@ -150,6 +150,10 @@ pub(crate) fn init_rootfs(disk: crate::dev::Disk) { cfg_if::cfg_if! { if #[cfg(feature = "myfs")] { // override the default filesystem let main_fs = fs::myfs::new_myfs(disk); + } else if #[cfg(feature = "ext4fs")] { + static EXT4_FS: LazyInit> = LazyInit::new(); + EXT4_FS.init_once(Arc::new(fs::ext4fs::Ext4FileSystem::new(disk))); + let main_fs = EXT4_FS.clone(); } else if #[cfg(feature = "fatfs")] { static FAT_FS: LazyInit> = LazyInit::new(); FAT_FS.init_once(Arc::new(fs::fatfs::FatFileSystem::new(disk))); diff --git a/ulib/axstd/Cargo.toml b/ulib/axstd/Cargo.toml index 8fd987355b..0c1b81a6e7 100644 --- a/ulib/axstd/Cargo.toml +++ b/ulib/axstd/Cargo.toml @@ -53,6 +53,8 @@ sched-cfs = ["axfeat/sched-cfs"] # File system fs = ["arceos_api/fs", "axfeat/fs"] myfs = ["arceos_api/myfs", "axfeat/myfs"] +ext4fs = ["axfeat/ext4fs"] +fatfs = ["axfeat/fatfs"] # Networking net = ["arceos_api/net", "axfeat/net"]