From 6f0094c0399a4e3795e1dac404b6a0dab5f8d25e Mon Sep 17 00:00:00 2001 From: pjht Date: Thu, 6 Jun 2024 22:01:41 -0500 Subject: [PATCH] Work --- .cargo/config.toml | 5 +- Cargo.lock | 395 +------------------------------- Cargo.toml | 12 +- rust-toolchain.toml | 2 +- src/ata.rs | 412 ---------------------------------- src/ext2.rs | 164 -------------- src/ext2/block_group_table.rs | 83 ------- src/ext2/block_reader.rs | 54 ----- src/ext2/dir.rs | 180 --------------- src/ext2/file.rs | 133 ----------- src/ext2/metadata.rs | 252 --------------------- src/ext2/structs.rs | 159 ------------- src/main.rs | 59 +---- 13 files changed, 23 insertions(+), 1887 deletions(-) delete mode 100644 src/ata.rs delete mode 100644 src/ext2.rs delete mode 100644 src/ext2/block_group_table.rs delete mode 100644 src/ext2/block_reader.rs delete mode 100644 src/ext2/dir.rs delete mode 100644 src/ext2/file.rs delete mode 100644 src/ext2/metadata.rs delete mode 100644 src/ext2/structs.rs diff --git a/.cargo/config.toml b/.cargo/config.toml index bac022e..bec4b7a 100644 --- a/.cargo/config.toml +++ b/.cargo/config.toml @@ -1,6 +1,5 @@ [build] -target = "x86_64-unknown-none" -rustflags = ["-C", "relocation-model=static"] +target = "x86_64-unknown-mikros" [install] -root = "../kernel/sysroot" +root = "../os_build/sysroot" diff --git a/Cargo.lock b/Cargo.lock index 6823e20..76c7331 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2,204 +2,23 @@ # It is not intended for manual editing. version = 3 -[[package]] -name = "ahash" -version = "0.8.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e89da841a80418a9b391ebaea17f5c112ffaaa96f621d2c285b5174da76b9011" -dependencies = [ - "cfg-if", - "once_cell", - "version_check", - "zerocopy", -] - -[[package]] -name = "arrayvec" -version = "0.7.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "96d30a06541fbafbc7f82ed10c06164cfbd2c401138f6addd8404629c4b16711" - [[package]] name = "autocfg" version = "1.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0c4b4d0bd25bd0b74681c0ad21497610ce1b7c91b1022cd21c80c6fbdd9476b0" -[[package]] -name = "binread" -version = "2.2.0" -dependencies = [ - "binread_derive", - "rustversion", - "std", -] - -[[package]] -name = "binread_derive" -version = "2.1.0" -dependencies = [ - "either", - "proc-macro2", - "quote", - "syn 1.0.109", -] - -[[package]] -name = "bit_field" -version = "0.10.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dc827186963e592360843fb5ba4b973e145841266c1357f7180c43526f2e5b61" - -[[package]] -name = "bitflags" -version = "1.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" - [[package]] name = "bitflags" version = "2.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cf4b9d6a944f767f8e5e0db018570623c85f3d925ac718db4e06d0187adb21c1" -[[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 = "core2" -version = "0.4.0" -dependencies = [ - "memchr", - "serde", -] - -[[package]] -name = "crossbeam-queue" -version = "0.3.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "df0346b5d5e76ac2fe4e327c5fd1118d6be7c51dfb18f9b7922923f287471e35" -dependencies = [ - "crossbeam-utils", -] - -[[package]] -name = "crossbeam-utils" -version = "0.8.20" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "22ec99545bb0ed0ea7bb9b8e1e9122ea386ff8a48c0922e43f36d45ab09e0e80" - -[[package]] -name = "derive-try-from-primitive" -version = "1.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "302ccf094df1151173bb6f5a2282fcd2f45accd5eae1bdf82dcbfefbc501ad5c" -dependencies = [ - "proc-macro2", - "quote", - "syn 1.0.109", -] - -[[package]] -name = "dev_driver_rpc" -version = "0.1.0" -dependencies = [ - "postcard", - "serde", - "spin", - "std", -] - -[[package]] -name = "either" -version = "1.12.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3dca9240753cf90908d7e4aac30f630662b02aebaa1b58a3cadabdb23385b58b" - -[[package]] -name = "elf" -version = "0.7.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4445909572dbd556c457c849c4ca58623d84b27c8fff1e74b0b4227d8b90d17b" - -[[package]] -name = "elfloader" -version = "0.16.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6a7b18d35bf8ec3bac59c3ec29cf1f1b46e764e00b42a9c0c754d06e38e78f3b" -dependencies = [ - "bitflags 1.3.2", - "log", - "xmas-elf", -] - -[[package]] -name = "embedded-io" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ef1a6892d9eef45c8fa6b9e0086428a2cca8491aca8f787c534a3d6d0bcb3ced" - -[[package]] -name = "hashbrown" -version = "0.13.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "43a3c133739dddd0d2990f9a4bdf8eb4b21ef50e4851ca85ab661199821d510e" -dependencies = [ - "ahash", -] - [[package]] name = "init" version = "0.1.0" dependencies = [ - "binread", - "bitflags 1.3.2", - "dev_driver_rpc", - "itertools", - "postcard", - "serde", - "spin", - "std", - "tap", "tar-no-std", - "x86_64 0.15.1", -] - -[[package]] -name = "itertools" -version = "0.10.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b0fd2260e829bddf4cb6ea802289de2f86d6a7a690192fbe91b3f46e0f2c8473" -dependencies = [ - "either", -] - -[[package]] -name = "linked_list_allocator" -version = "0.10.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9afa463f5405ee81cdb9cc2baf37e08ec7e4c8209442b5d72c04cfb2cd6e6286" -dependencies = [ - "spinning_top", -] - -[[package]] -name = "lock_api" -version = "0.4.12" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "07af8b9cdd281b7915f413fa73f29ebd5d55d0d3f0155584dade1ff18cea1b17" -dependencies = [ - "autocfg", - "scopeguard", ] [[package]] @@ -215,216 +34,22 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6c8640c5d730cb13ebd907d8d04b52f55ac9a2eec55b440c8892f40d56c76c1d" [[package]] -name = "once_cell" -version = "1.19.0" +name = "num-traits" +version = "0.2.19" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92" - -[[package]] -name = "postcard" -version = "1.0.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a55c51ee6c0db07e68448e336cf8ea4131a620edefebf9893e759b2d793420f8" +checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841" dependencies = [ - "cobs", - "embedded-io", - "serde", + "autocfg", ] -[[package]] -name = "proc-macro2" -version = "1.0.84" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ec96c6a92621310b51366f1e28d05ef11489516e93be030060e5fc12024a49d6" -dependencies = [ - "unicode-ident", -] - -[[package]] -name = "quote" -version = "1.0.36" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0fa76aaf39101c457836aec0ce2316dbdc3ab723cdda1c6bd4e6ad4208acaca7" -dependencies = [ - "proc-macro2", -] - -[[package]] -name = "rustversion" -version = "1.0.17" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "955d28af4278de8121b7ebeb796b6a45735dc01436d898801014aced2773a3d6" - -[[package]] -name = "scopeguard" -version = "1.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" - -[[package]] -name = "serde" -version = "1.0.203" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7253ab4de971e72fb7be983802300c30b5a7f0c2e56fab8abfc6a214307c0094" -dependencies = [ - "serde_derive", -] - -[[package]] -name = "serde_derive" -version = "1.0.203" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "500cbc0ebeb6f46627f50f3f5811ccf6bf00643be300b4c3eabc0ef55dc5b5ba" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.66", -] - -[[package]] -name = "spin" -version = "0.9.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6980e8d7511241f8acf4aebddbb1ff938df5eebe98691418c4468d0b72a96a67" -dependencies = [ - "lock_api", -] - -[[package]] -name = "spinning_top" -version = "0.2.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5b9eb1a2f4c41445a3a0ff9abc5221c5fcd28e1f13cd7c0397706f9ac938ddb0" -dependencies = [ - "lock_api", -] - -[[package]] -name = "std" -version = "0.1.0" -dependencies = [ - "core2", - "crossbeam-queue", - "derive-try-from-primitive", - "elf", - "elfloader", - "hashbrown", - "linked_list_allocator", - "postcard", - "serde", - "spin", - "x86_64 0.14.12", -] - -[[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.66" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c42f3f41a2de00b01c0aaad383c5a45241efc8b2d1eda5661812fda5f3cdcff5" -dependencies = [ - "proc-macro2", - "quote", - "unicode-ident", -] - -[[package]] -name = "tap" -version = "1.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "55937e1799185b12863d447f42597ed69d9928686b8d88a1df17376a097d8369" - [[package]] name = "tar-no-std" -version = "0.1.7" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4d897790ee033615752cc7bf882343881ad748438c01bc7e1b9d6242bf14a2c6" dependencies = [ - "arrayvec", - "bitflags 1.3.2", + "bitflags", "log", -] - -[[package]] -name = "unicode-ident" -version = "1.0.12" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b" - -[[package]] -name = "version_check" -version = "0.9.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" - -[[package]] -name = "volatile" -version = "0.4.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "442887c63f2c839b346c192d047a7c87e73d0689c9157b00b53dcc27dd5ea793" - -[[package]] -name = "x86_64" -version = "0.14.12" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "96cb6fd45bfeab6a5055c5bffdb08768bd0c069f1d946debe585bbb380a7c062" -dependencies = [ - "bit_field", - "bitflags 2.5.0", - "rustversion", - "volatile", -] - -[[package]] -name = "x86_64" -version = "0.15.1" -source = "git+https://gitea.pterpstra.com/mikros/x86_64#8debcc3504d7e5c39c10b28f2a0661b19ee3a6f0" -dependencies = [ - "bit_field", - "bitflags 2.5.0", - "rustversion", - "volatile", -] - -[[package]] -name = "xmas-elf" -version = "0.8.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8d29b4d8e7beaceb4e77447ba941a7600d23d0319ab52da0461abea214832d5a" -dependencies = [ - "zero", -] - -[[package]] -name = "zero" -version = "0.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2fe21bcc34ca7fe6dd56cc2cb1261ea59d6b93620215aefb5ea6032265527784" - -[[package]] -name = "zerocopy" -version = "0.7.34" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ae87e3fcd617500e5d106f0380cf7b77f3c6092aae37191433159dda23cfb087" -dependencies = [ - "zerocopy-derive", -] - -[[package]] -name = "zerocopy-derive" -version = "0.7.34" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "15e934569e47891f7d9411f1a451d947a60e000ab3bd24fbb970f000387d1b3b" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.66", + "memchr", + "num-traits", ] diff --git a/Cargo.toml b/Cargo.toml index 09c9fb6..87778c4 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -6,17 +6,7 @@ edition = "2021" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] -tar-no-std = { path = "../tar-no-std" } -std = { path = "../std" } -bitflags = "1.3.2" -spin = "0.9.4" -tap = "1.0.1" -x86_64 = { git = "https://gitea.pterpstra.com/mikros/x86_64" } -binread = { version = "2.2.0", path = "../binread/binread", default-features = false } -itertools = { version = "0.10.3", default-features = false, features = ["use_alloc"] } -serde = { version = "1.0.144", default-features = false, features = ["alloc", "derive"] } -postcard = { version = "1.0.2", default-features = false, features = ["alloc"] } -dev_driver_rpc = { version = "0.1.0", path = "../dev_driver_rpc" } +tar-no-std = "0.3.1" [profile.dev] panic = "abort" diff --git a/rust-toolchain.toml b/rust-toolchain.toml index 5d56faf..a5535e3 100644 --- a/rust-toolchain.toml +++ b/rust-toolchain.toml @@ -1,2 +1,2 @@ [toolchain] -channel = "nightly" +channel = "dev-x86_64-unknown-mikros" diff --git a/src/ata.rs b/src/ata.rs deleted file mode 100644 index c44abc9..0000000 --- a/src/ata.rs +++ /dev/null @@ -1,412 +0,0 @@ -use std::cmp::Ordering; - -use bitflags::bitflags; -use spin::{Lazy, Mutex}; -use std::io::{self, Read, Seek}; -use tap::Tap; -use x86_64::instructions::port::{ - PortRead, PortSafe, PortSafeReadOnly, PortSafeWriteOnly, PortWrite, -}; - -bitflags! { - pub struct RawError: u8 { - const AMNF = 0b0000_0001; - const TKZNF = 0b0000_0010; - const ABRT = 0b0000_0100; - const MCR = 0b0000_1000; - const IDNF = 0b0001_0000; - const MC = 0b0010_0000; - const UNC = 0b0100_0000; - const BBK = 0b1000_0000; - } -} - -impl From for Error { - fn from(err: RawError) -> Self { - if err.contains(RawError::AMNF) { - Self::AddressMarkNotFound - } else if err.contains(RawError::TKZNF) { - Self::TrackZeroNotFound - } else if err.contains(RawError::ABRT) { - Self::AbortedCommand - } else if err.contains(RawError::MCR) { - Self::MediaChangeRequest - } else if err.contains(RawError::IDNF) { - Self::IDMarkNotFound - } else if err.contains(RawError::MC) { - Self::MediaChanged - } else if err.contains(RawError::UNC) { - Self::UncorrectableData - } else if err.contains(RawError::BBK) { - Self::BadBlock - } else { - Self::Generic - } - } -} - -impl PortRead for RawError { - unsafe fn read_from_port(port: u16) -> Self { - unsafe { Self::from_bits_unchecked(u8::read_from_port(port)) } - } -} - -impl PortWrite for RawError { - unsafe fn write_to_port(port: u16, value: Self) { - unsafe { u8::write_to_port(port, value.bits) }; - } -} - -bitflags! { - pub struct Status: u8 { - const ERR = 0b0000_0001; - const DRQ = 0b0000_1000; - const SRV = 0b0001_0000; - const DF = 0b0010_0000; - const RDY = 0b0100_0000; - const BSY = 0b1000_0000; - } -} - -impl PortRead for Status { - unsafe fn read_from_port(port: u16) -> Self { - unsafe { Self::from_bits_unchecked(u8::read_from_port(port)) } - } -} - -impl PortWrite for Status { - unsafe fn write_to_port(port: u16, value: Self) { - unsafe { u8::write_to_port(port, value.bits) }; - } -} - -bitflags! { - pub struct DeviceControl: u8 { - const N_IEN = 0b0000_0010; - const SRST = 0b0000_0100; - const HOB = 0b1000_0000; - } -} - -impl PortRead for DeviceControl { - unsafe fn read_from_port(port: u16) -> Self { - unsafe { Self::from_bits_unchecked(u8::read_from_port(port)) } - } -} - -impl PortWrite for DeviceControl { - unsafe fn write_to_port(port: u16, value: Self) { - unsafe { u8::write_to_port(port, value.bits) }; - } -} - -bitflags! { - #[repr(transparent)] - pub struct DriveHead: u8 { - const DT0 = 0b0000_0001; - const DT1 = 0b0000_0010; - const DT2 = 0b0000_0100; - const DT3 = 0b0000_1000; - const DRV = 0b0001_0000; - const LBA = 0b0100_0000; - } -} - -impl DriveHead { - fn set_head_block(&mut self, data: u8) { - assert!(data < 16); - self.bits = (self.bits & 0xF0) | data; - } -} - -impl PortRead for DriveHead { - unsafe fn read_from_port(port: u16) -> Self { - unsafe { Self::from_bits_unchecked(u8::read_from_port(port)) } - } -} - -impl PortWrite for DriveHead { - unsafe fn write_to_port(port: u16, value: Self) { - unsafe { u8::write_to_port(port, value.bits) }; - } -} - -#[repr(u8)] -#[derive(Copy, Clone, Debug, PartialEq, Eq)] -pub enum DriveNumber { - Master = 0, - Slave = 1, -} - -#[repr(u8)] -#[derive(Copy, Clone, Debug, PartialEq)] -#[allow(unused)] -enum Command { - Identify = 0xEC, - IdentifyPacket = 0xA1, - ReadSectors = 0x20, - WriteSectors = 0x30, -} - -#[derive(Copy, Clone, Debug, PartialEq, Eq)] -pub enum Error { - NonexistentDrive, - Generic, - AbortedCommand, - TrackZeroNotFound, - AddressMarkNotFound, - MediaChangeRequest, - IDMarkNotFound, - MediaChanged, - UncorrectableData, - BadBlock, -} - -impl From for io::Error { - fn from(_: Error) -> Self { - Self::new(io::ErrorKind::Other, "ATA read error") - } -} - -#[derive(Copy, Clone, Debug, PartialEq, Eq)] -#[allow(clippy::upper_case_acronyms)] -pub enum DriveKind { - ATA, - ATAPI, -} - -#[derive(Copy, Clone, Debug, PartialEq, Eq)] -pub enum IdentifyError { - SATADrive, - Error(Error), -} - -impl From for IdentifyError { - fn from(err: Error) -> Self { - Self::Error(err) - } -} - -#[derive(Clone, Debug, PartialEq, Eq)] -pub struct Bus { - data: PortSafe, - error: PortSafeReadOnly, - sector_count: PortSafe, - sector_num_lba_lo: PortSafe, - cyl_low_lba_mid: PortSafe, - cyl_high_lba_hi: PortSafe, - drive_head: PortSafe, - status: PortSafeReadOnly, - command: PortSafeWriteOnly, - selected_drive: Option, // None represents the initial state with an unknown drive selected -} - -impl Bus { - /// SAFETY - /// io_base must be a valid base for the ATA bus's IO registers - const unsafe fn new(io_base: u16) -> Self { - unsafe { - Self { - data: PortSafe::new(io_base), - error: PortSafeReadOnly::new(io_base + 1), - sector_count: PortSafe::new(io_base + 2), - sector_num_lba_lo: PortSafe::new(io_base + 3), - cyl_low_lba_mid: PortSafe::new(io_base + 4), - cyl_high_lba_hi: PortSafe::new(io_base + 5), - drive_head: PortSafe::new(io_base + 6), - status: PortSafeReadOnly::new(io_base + 7), - command: PortSafeWriteOnly::new(io_base + 7), - selected_drive: None, - } - } - } - - pub fn select(&mut self, drive: DriveNumber, lba: bool, data: u8) { - if self.selected_drive != Some(drive) { - self.drive_head.write(DriveHead::empty().tap_mut(|v| { - v.set(DriveHead::DRV, drive == DriveNumber::Slave); - v.set(DriveHead::LBA, lba); - v.set_head_block(data); - })); - for _ in 0..14 { - self.status.read(); - } - self.selected_drive = Some(drive); - } - } - - pub fn read_data(&mut self) -> [u16; 256] { - let mut arr = [0; 256]; - arr.fill_with(|| self.data.read()); - arr - } - - fn send_command(&mut self, command: Command) -> Result<(), Error> { - self.command.write(command as u8); - while self.status.read().contains(Status::BSY) {} - while !(self.status.read().intersects(Status::DRQ | Status::ERR)) {} - self.error()?; - Ok(()) - } - - pub fn identify(&mut self) -> Result<(DriveKind, [u16; 256]), IdentifyError> { - self.command.write(Command::Identify as u8); - if self.status.read().bits() == 0 { - return Err(IdentifyError::Error(Error::NonexistentDrive)); - }; - while self.status.read().contains(Status::BSY) {} - while !(self.status.read().intersects(Status::DRQ | Status::ERR)) {} - if self.status.read().contains(Status::ERR) { - if self.cyl_low_lba_mid.read() == 0x14 && self.cyl_high_lba_hi.read() == 0xEB { - self.command.write(Command::IdentifyPacket as u8); - if self.status.read().bits() == 0 { - return Err(IdentifyError::Error(Error::NonexistentDrive)); - }; - while self.status.read().contains(Status::BSY) {} - while !(self.status.read().intersects(Status::DRQ | Status::ERR)) {} - self.error()?; - Ok((DriveKind::ATAPI, self.read_data())) - } else { - Err(IdentifyError::SATADrive) - } - } else { - Ok((DriveKind::ATA, self.read_data())) - } - } - - fn error(&mut self) -> Result<(), Error> { - if self.status.read().contains(Status::ERR) { - Err(self.error.read().into()) - } else { - Ok(()) - } - } -} - -#[allow(unused)] -// SAFETY -// This is safe because 0x1F0 is the standard primary bus base address -static PRIMARY_BUS: Mutex = Mutex::new(unsafe { Bus::new(0x1F0) }); -#[allow(unused)] -// SAFETY -// This is safe because 0x170 is the standard secondary bus base address -static SECONDARY_BUS: Mutex = Mutex::new(unsafe { Bus::new(0x170) }); - -#[allow(unused)] -pub static PRIMARY_MASTER: Lazy> = - Lazy::new(|| Device::new(&PRIMARY_BUS, DriveNumber::Master)); -#[allow(unused)] -pub static PRIMARY_SLAVE: Lazy> = - Lazy::new(|| Device::new(&PRIMARY_BUS, DriveNumber::Slave)); -#[allow(unused)] -pub static SECONDARY_MASTER: Lazy> = - Lazy::new(|| Device::new(&SECONDARY_BUS, DriveNumber::Master)); -#[allow(unused)] -pub static SECONDARY_SLAVE: Lazy> = - Lazy::new(|| Device::new(&SECONDARY_BUS, DriveNumber::Slave)); - -#[derive(Copy, Clone, Debug)] -pub struct Device { - bus: &'static Mutex, - drive_number: DriveNumber, - lba: bool, - pos: u64, - len: u64, -} - -#[derive(Copy, Clone, Debug, PartialEq, Eq)] -pub enum NewDeviceError { - IdentifyError(IdentifyError), - ATAPIDevice, -} - -impl Device { - fn new(bus: &'static Mutex, drive_number: DriveNumber) -> Result { - bus.lock().select(drive_number, true, 0); - let id_result = bus - .lock() - .identify() - .map_err(NewDeviceError::IdentifyError)?; - if let (DriveKind::ATA, ident_data) = id_result { - Ok(Self { - bus, - drive_number, - lba: true, - pos: 0, - len: (u64::from(ident_data[60]) * 512), - }) - } else { - Err(NewDeviceError::ATAPIDevice) - } - } - - fn select(&self, data: u8) { - self.bus.lock().select(self.drive_number, self.lba, data); - } -} - -impl Read for Device { - #[allow(clippy::similar_names)] - fn read(&mut self, buf: &mut [u8]) -> io::Result { - let avail_len = u64::min(u64::min(self.len - self.pos, buf.len() as u64), 512 * 250); - if avail_len == 0 { - return Ok(0); - } - let sector = self.pos / 512; - assert!(sector < 0x1_0000_0000_0000); - let offset = (self.pos % 512) as usize; - let length = avail_len as usize + offset; - let num_sectors = length.div_ceil(512); - assert!(num_sectors < 256); - if sector < 0x1000_0000 { - self.select(((sector & 0xF00_0000) >> 24) as u8); - let mut bus = self.bus.lock(); - bus.sector_count.write(num_sectors as u8); - bus.sector_num_lba_lo.write(sector as u8); - bus.cyl_low_lba_mid.write((sector >> 8) as u8); - bus.cyl_high_lba_hi.write((sector >> 16) as u8); - bus.send_command(Command::ReadSectors)?; - } else { - unimplemented!(); - } - let mut byte_num = 0; - let mut i = 0; - for _ in 0..num_sectors { - for byte in self - .bus - .lock() - .read_data() - .into_iter() - .flat_map(u16::to_le_bytes) - { - if byte_num >= offset && byte_num < (offset + buf.len()) { - buf[i] = byte; - i += 1; - } - byte_num += 1; - } - } - self.pos += avail_len as u64; - Ok(avail_len as usize) - } -} - -impl Seek for Device { - fn seek(&mut self, pos: io::SeekFrom) -> io::Result { - match pos { - io::SeekFrom::Start(x) => self.pos = x, - io::SeekFrom::End(_) => { - return Err(io::Error::new( - io::ErrorKind::Other, - "End seek not implemented yet", - )) - } - io::SeekFrom::Current(x) => match x.cmp(&0) { - Ordering::Equal => (), - Ordering::Greater => self.pos += x.unsigned_abs(), - Ordering::Less => self.pos -= x.unsigned_abs(), - }, - }; - Ok(self.pos) - } -} diff --git a/src/ext2.rs b/src/ext2.rs deleted file mode 100644 index 143efd7..0000000 --- a/src/ext2.rs +++ /dev/null @@ -1,164 +0,0 @@ -mod block_group_table; -mod block_reader; -mod dir; -mod file; -mod metadata; -mod structs; - -use block_group_table::BlockGroupDescriptorTable; -use block_reader::BlockReader; -use std::dbg; -use std::io::{self, Read}; -use std::path::{Component, Path}; -use std::string::{String, ToString}; -use std::vec::Vec; -use structs::{Inode, Superblock}; - -pub use dir::{DirEntry, ReadDir}; -pub use file::File; -pub use metadata::{FileType, Metadata, Permissions}; -use std::fs::File as StdFile; - -#[derive(Debug)] -pub struct Ext2 { - reader: BlockReader, - descriptor_table: BlockGroupDescriptorTable, -} - -impl Ext2 { - pub fn new(mut disk: StdFile) -> io::Result { - let superblock = Superblock::read_from_disk(&mut disk)?; - let reader = BlockReader::new(disk, &superblock); - Ok(Self { - descriptor_table: dbg!(BlockGroupDescriptorTable::new(&superblock, &reader)?), - reader, - }) - } - - fn path_inode>(&self, path: P) -> io::Result { - let path = path.as_ref(); - path.parent().map_or(Ok(2), |parent| { - self.read_dir_no_path(parent)? - .get_entry(path.file_name().ok_or_else(|| { - io::Error::new( - io::ErrorKind::Other, - "A path ending in .. or . was passed to path_inode", - ) - })?) - .map(|x| x.inode) - }) - } - - /// Returns an iterator over the entries within a directory. - /// - /// The iterator will yield instances of [`io::Result`]<[`DirEntry`]>. - /// New errors may be encountered after an iterator is initially constructed. - /// Entries for the current and parent directories (`.` and `..`) are - /// skipped. - /// - /// - /// # Errors - /// - /// This function will return an error in the following situations, but is not - /// limited to just these cases: - /// - /// * The provided `path` doesn't exist. - /// * The process lacks permissions to view the contents. - /// * The `path` points at a non-directory file. - #[allow(unused)] - pub fn read_dir>(&self, path: P) -> io::Result { - path.as_ref().components().try_fold( - ReadDir::read_inode(self, 2, Some("/".to_string().into()))?, - |dir, component| match component { - Component::Normal(os_str) => dir.get_entry(os_str)?.read_dir(), - _ => Ok(dir), - }, - ) - } - - /// Returns an iterator over the entries within a directory, without allocating the full path - /// for the directory on the heap. This saves unnecessary allocations when you will not use - /// `DirEntry::path`. - /// - /// The iterator will yield instances of [`io::Result`]<[`DirEntry`]>. - /// New errors may be encountered after an iterator is initially constructed. - /// Entries for the current and parent directories (`.` and `..`) are - /// skipped. - /// - /// - /// # Errors - /// - /// This function will return an error in the following situations, but is not - /// limited to just these cases: - /// - /// * The provided `path` doesn't exist. - /// * The process lacks permissions to view the contents. - /// * The `path` points at a non-directory file. - pub fn read_dir_no_path>(&self, path: P) -> io::Result { - path.as_ref().components().try_fold( - ReadDir::read_inode(self, 2, None)?, - |dir, component| match component { - Component::Normal(os_str) => dir.get_entry(os_str)?.read_dir(), - _ => Ok(dir), - }, - ) - } - - /// Attempts to open a file in read-only mode. - /// - /// # Errors - /// - /// This function will return an error if `path` does not already exist. - #[allow(unused)] - pub fn open>(&self, path: P) -> io::Result { - File::from_inode(Inode::read(self, self.path_inode(path)?)?, self) - } - - /// Read the entire contents of a file into a string. - /// - /// This is a convenience function for using [`File::open`] and [`read_to_string`] - /// with fewer imports and without an intermediate variable. - /// - /// [`read_to_string`]: core2::io::Read::read_to_string - /// - /// # Errors - /// - /// This function will return an error if `path` does not already exist. - /// Other errors may also be returned according to [`OpenOptions::open`]. - /// - /// It will also return an error if it encounters while reading an error - /// of a kind other than [`io::ErrorKind::Interrupted`], - /// or if the contents of the file are not valid UTF-8. - #[allow(unused)] - pub fn read_to_string>(&self, path: P) -> io::Result { - let mut string = String::new(); - self.open(path)?.read_to_string(&mut string)?; - Ok(string) - } - - /// Read the entire contents of a file into a bytes vector. - /// - /// This is a convenience function for using [`File::open`] and [`read_to_end`] - /// with fewer imports and without an intermediate variable. - /// - /// [`read_to_end`]: core2::io::Read::read_to_end - /// - /// # Errors - /// - /// This function will return an error if `path` does not already exist. - /// Other errors may also be returned according to [`OpenOptions::open`]. - /// - /// It will also return an error if it encounters while reading an error - /// of a kind other than [`io::ErrorKind::Interrupted`]. - #[allow(unused)] - pub fn read>(&self, path: P) -> io::Result> { - let mut bytes = Vec::new(); - self.open(path)?.read_to_end(&mut bytes)?; - Ok(bytes) - } - - #[allow(unused)] - pub fn metadata>(&self, path: P) -> io::Result { - Inode::read(self, self.path_inode(path)?).map(|x| Metadata::from_inode(&x)) - } -} diff --git a/src/ext2/block_group_table.rs b/src/ext2/block_group_table.rs deleted file mode 100644 index 6482f95..0000000 --- a/src/ext2/block_group_table.rs +++ /dev/null @@ -1,83 +0,0 @@ -use super::{ - block_reader::BlockReader, - structs::{BlockGroupDescriptor, Inode, Superblock}, -}; -use binread::prelude::*; -use std::vec::Vec; -use std::{dbg, io}; - -const INODE_SIZE: usize = 256; - -#[derive(Debug, BinRead)] -#[br(import(len: usize, block_group_inode_count: u32, block_size: usize))] -pub struct BlockGroupDescriptorTable { - #[br(count = len)] - table: Vec, - #[br(calc = block_group_inode_count)] - block_group_inode_count: u32, - #[br(calc = block_size)] - block_size: usize, -} - -impl BlockGroupDescriptorTable { - pub fn new(superblock: &Superblock, reader: &BlockReader) -> io::Result { - let num_block_groups = superblock - .total_blocks - .div_ceil(superblock.block_group_block_count) as usize; - let table_blocks = num_block_groups.div_ceil(reader.block_size / 32); - Ok(reader - .read_blocks(superblock.superblock_block + 1, table_blocks)? - .read_le_args(( - num_block_groups, - superblock.block_group_inode_count, - 1024 << superblock.block_size_raw, - )) - .expect("Parsing the block group descriptor table should never fail")) - } - - fn inode_group(&self, inode: u32) -> &BlockGroupDescriptor { - &self.table[((inode - 1) / self.block_group_inode_count) as usize] - } - - fn inode_group_offset(&self, inode: u32) -> usize { - ((inode - 1) % self.block_group_inode_count) as usize - } - - fn inode_block(&self, inode: u32) -> u32 { - (((self.inode_group_offset(inode) * INODE_SIZE) / self.block_size) as u32) - + self.inode_group(inode).inode_table_start - } - - fn inode_block_byte_start(&self, inode: u32) -> usize { - (self.inode_group_offset(inode) * INODE_SIZE) % self.block_size - } - - pub fn inode_loc(&self, inode: u32) -> InodeLoc { - // dbg!(self); - InodeLoc { - block: self.inode_block(inode), - byte_offset: self.inode_block_byte_start(inode), - num: inode, - } - } -} - -#[derive(Debug)] -pub struct InodeLoc { - block: u32, - byte_offset: usize, - num: u32, -} - -impl InodeLoc { - pub fn read(&self, reader: &BlockReader) -> io::Result { - // dbg!(self.num); - reader - .read_block_offset(self.block, self.byte_offset as u32)? - .read_le_args((self.num,)) - .map_err(|err| match err { - binread::Error::Io(_) => io::Error::new(io::ErrorKind::Other, "Binread IO error"), - _ => io::Error::new(io::ErrorKind::InvalidData, "Inode data was invalid"), - }) - } -} diff --git a/src/ext2/block_reader.rs b/src/ext2/block_reader.rs deleted file mode 100644 index ddbd1b4..0000000 --- a/src/ext2/block_reader.rs +++ /dev/null @@ -1,54 +0,0 @@ -use std::dbg; -use std::vec::Vec; - -use super::structs::Superblock; -use std::fs::File as StdFile; -use std::io::{self, Cursor}; - -#[derive(Debug)] -pub struct BlockReader { - pub disk: StdFile, - pub block_size: usize, -} - -impl BlockReader { - pub fn new(disk: StdFile, superblock: &Superblock) -> Self { - Self { - disk, - block_size: 1024 << superblock.block_size_raw, - } - } - - pub fn read_block(&self, block: u32) -> io::Result>> { - self.read_blocks_offset(block, 0, 1) - } - - pub fn read_block_offset(&self, block: u32, offset: u32) -> io::Result>> { - self.read_blocks_offset(block, offset, 1) - } - - pub fn read_blocks(&self, block: u32, count: usize) -> io::Result>> { - self.read_blocks_offset(block, 0, count) - } - - pub fn read_blocks_offset( - &self, - block: u32, - offset: u32, - count: usize, - ) -> io::Result>> { - // dbg!(block, offset, count, self.block_size); - let start = self.block_to_byte_offset(block) + u64::from(offset); - let size = (self.block_size * count) - (offset as usize); - // dbg!(start, size); - let mut vec = Vec::new(); - vec.resize(size, 0); - self.disk.read_at(&mut vec, start)?; - // dbg!(&vec[0..16]); - Ok(Cursor::new(vec)) - } - - fn block_to_byte_offset(&self, block: u32) -> u64 { - u64::from(block) * (self.block_size as u64) - } -} diff --git a/src/ext2/dir.rs b/src/ext2/dir.rs deleted file mode 100644 index 403f6cd..0000000 --- a/src/ext2/dir.rs +++ /dev/null @@ -1,180 +0,0 @@ -use super::{ - file::File, - metadata::{FileType, Metadata}, - structs::{DirEntryDisk, Inode}, - Ext2, -}; -use binread::BinReaderExt; -use std::io; -use std::path::PathBuf; -use std::string::String; - -/// Entries returned by the [`ReadDir`] iterator. -/// -/// An instance of `DirEntry` represents an entry inside of a directory on the -/// filesystem. Each entry can be inspected via methods to learn about the full -/// path or possibly other metadata through per-platform extension traits. -#[allow(unused)] -#[allow(clippy::module_name_repetitions)] -pub struct DirEntry<'a> { - pub(super) inode: u32, - pub(super) name: String, - pub(super) metadata: Metadata, - pub(super) directory_path: Option, - fs: &'a Ext2, -} - -impl<'a> core::fmt::Debug for DirEntry<'a> { - fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { - f.debug_struct("DirEntry") - .field("inode", &self.inode) - .field("name", &self.name) - .field("metadata", &self.metadata) - .field("directory_path", &self.directory_path) - .finish() - } -} - -#[allow(unused)] -impl<'a> DirEntry<'a> { - /// Returns the bare file name of this directory entry without any other - /// leading path component. - pub fn file_name(&self) -> String { - self.name.clone() - } - - /// Returns the file type for the file that this entry points at. - /// - /// This function will not traverse symlinks if this entry points at a - /// symlink. - pub fn file_type(&self) -> FileType { - self.metadata.file_type() - } - - /// Returns the metadata for the file that this entry points at. - /// - /// This function will not traverse symlinks if this entry points at a - /// symlink. - pub fn metadata(&self) -> Metadata { - self.metadata - } - - /// Returns the full path to the file that this entry represents. - /// - /// The full path is created by joining the original path to `read_dir` - /// with the filename of this entry. - /// - /// # Panics - /// - /// This function will panic if this entry came either directly from a `ReadDir` made with - /// `Ext2::read_dir_no_path`, or indirectly from such a `ReadDir` by use of the - /// `DirEntry::read_dir` function. This is an explicit decision, so such a panic indicates a - /// definite bug in your code. - pub fn path(&self) -> PathBuf { - self.try_path().expect("Path was None") - } - - /// Returns the full path to the file that this entry represents. - /// - /// The full path is created by joining the original path to `read_dir` - /// with the filename of this entry. - pub fn try_path(&self) -> Option { - self.directory_path - .as_ref() - .map(|x| x.join(self.name.clone())) - } - - pub fn open(&self) -> io::Result { - File::from_inode(Inode::read(self.fs, self.inode)?, self.fs) - } - - pub fn read_dir(&self) -> io::Result> { - ReadDir::read_inode(self.fs, self.inode, self.try_path()) - } -} - -/// Iterator over the entries in a directory. -/// -/// This iterator is returned from the [`super::Ext2::read_dir`] function and -/// will yield instances of [`io::Result`]<[`DirEntry`]>. Through a [`DirEntry`] -/// information like the entry's path and possibly other metadata can be -/// learned. -/// -/// The order in which this iterator returns entries is platform and filesystem -/// dependent. -/// -/// # Errors -/// -/// This [`io::Result`] will be an `Err` if there's some sort of intermittent -/// IO error during iteration. -#[derive(Debug)] -#[allow(clippy::module_name_repetitions)] -pub struct ReadDir<'a> { - fs: &'a Ext2, - file: File<'a>, - directory_path: Option, -} - -impl<'a> ReadDir<'a> { - pub fn read_inode(fs: &'a Ext2, inode: u32, path: Option) -> io::Result> { - Ok(Self { - fs, - file: File::from_inode_dir(Inode::read(fs, inode)?, fs)?, - directory_path: path, - }) - } - - pub(super) fn get_entry(mut self, name: &str) -> io::Result> { - self.find(|entry| { - if let Ok(entry) = entry { - entry.name == name - } else { - true - } - }) - .unwrap_or_else(|| Err(io::Error::new(io::ErrorKind::NotFound, "File not found"))) - } - - fn next_impl(&mut self) -> io::Result>> { - let entry: DirEntryDisk = match self.file.read_le() { - Ok(entry) => entry, - Err(binread::Error::Io(io_error)) => { - return if io_error.kind() == io::ErrorKind::UnexpectedEof { - Ok(None) - } else { - Err(io_error) - } - } - Err(_) => { - return Err(io::Error::new( - io::ErrorKind::InvalidData, - "Directory entry data was invalid", - )) - } - }; - let name = String::from_utf8(entry.name).map_err(|_| { - io::Error::new( - io::ErrorKind::InvalidData, - "Non UTF-8 directory entry names are unspported", - ) - })?; - if name == "." || name == ".." || entry.inode == 0 { - return self.next_impl(); - } - let entry_inode = Inode::read(self.fs, entry.inode)?; - Ok(Some(DirEntry { - inode: entry.inode, - name, - metadata: Metadata::from_inode(&entry_inode), - directory_path: self.directory_path.clone(), - fs: self.fs, - })) - } -} - -impl<'a> Iterator for ReadDir<'a> { - type Item = io::Result>; - fn next(&mut self) -> Option { - self.next_impl().transpose() - } -} diff --git a/src/ext2/file.rs b/src/ext2/file.rs deleted file mode 100644 index e9a4269..0000000 --- a/src/ext2/file.rs +++ /dev/null @@ -1,133 +0,0 @@ -use super::Ext2; -use super::{structs::Inode, Metadata}; -use core::{cmp::Ordering, str}; -use std::io::{self, Read}; -use std::string::String; - -/// A reference to an open file on the filesystem. -/// -/// An instance of a `File` can be read and/or written depending on what options -/// it was opened with. Files also implement [`Seek`] to alter the logical cursor -/// that the file contains internally. -/// -/// Files are automatically closed when they go out of scope. Errors detected -/// on closing are ignored by the implementation of `Drop`. -#[derive(Debug)] -pub struct File<'a> { - pos: u64, - inode: Inode, - fs: &'a Ext2, - block_size: usize, -} - -impl<'a> File<'a> { - pub(super) fn from_inode(inode: Inode, fs: &'a Ext2) -> io::Result { - // if !Metadata::from_inode(&inode).file_type().is_file() { - // return Err(io::Error::new(io::ErrorKind::Other, "Not a file")); - // } - Ok(Self { - pos: 0, - block_size: fs.reader.block_size, - fs, - inode, - }) - } - - /// This version of `from_inode` skips checks that the provided inode is a directory, not a file. It - /// should, only be used by `ReadDir::read_inode` to read the raw directory data. - pub(super) fn from_inode_dir(inode: Inode, fs: &'a Ext2) -> io::Result { - if !Metadata::from_inode(&inode).file_type().is_dir() { - return Err(io::Error::new(io::ErrorKind::Other, "Not a directory")); - } - Ok(Self { - pos: 0, - block_size: fs.reader.block_size, - fs, - inode, - }) - } - - /// Queries metadata about the underlying file. - #[allow(unused)] - pub fn metadata(&self) -> Metadata { - Metadata::from_inode(&self.inode) - } - - pub fn read_at(&mut self, buf: &mut [u8], pos: u64) -> io::Result { - let bytes_to_end = u64::from(self.inode.size_lower32).saturating_sub(pos); - if bytes_to_end == 0 { - return Ok(0); - } - let start_block = (pos / self.block_size as u64) as u32; - let offset = (pos % self.block_size as u64) as usize; - let length = core::cmp::min(bytes_to_end, buf.len() as u64); - self.fs - .reader - .read_block_offset( - self.inode - .log_to_phys_block(start_block) - .ok_or_else(|| io::Error::new(io::ErrorKind::UnexpectedEof, "EOF reached"))?, - offset as u32, - )? - .read(buf)?; - let mut remaining_bytes = length.saturating_sub((self.block_size - offset) as u64); - for block in (start_block + 1)..=u32::MAX { - if remaining_bytes == 0 { - break; - }; - self.fs - .reader - .read_block( - self.inode.log_to_phys_block(block).ok_or_else(|| { - io::Error::new(io::ErrorKind::UnexpectedEof, "EOF reached") - })?, - )? - .read(buf)?; - remaining_bytes = remaining_bytes.saturating_sub(self.block_size as u64); - } - Ok((length - remaining_bytes) as usize) - } - - pub fn read_to_string(&mut self, buf: &mut String) -> io::Result { - unsafe { - let buf = buf.as_mut_vec(); - let ret = self.read_to_end(buf)?; - str::from_utf8(buf).map_err(|_| { - io::Error::new( - io::ErrorKind::InvalidData, - "stream did not contain valid UTF-8", - ) - })?; - Ok(ret) - } - } -} - -impl io::Seek for File<'_> { - fn seek(&mut self, pos: io::SeekFrom) -> io::Result { - match pos { - io::SeekFrom::Start(x) => self.pos = x, - io::SeekFrom::End(x) => match x.cmp(&0) { - Ordering::Equal => self.pos = u64::from(self.inode.size_lower32), - Ordering::Greater => unimplemented!(), - Ordering::Less => self.pos = u64::from(self.inode.size_lower32) - x.unsigned_abs(), - }, - io::SeekFrom::Current(x) => match x.cmp(&0) { - Ordering::Equal => (), - Ordering::Greater => self.pos += x.unsigned_abs(), - Ordering::Less => self.pos -= x.unsigned_abs(), - }, - }; - Ok(self.pos) - } -} - -impl io::Read for File<'_> { - fn read(&mut self, buf: &mut [u8]) -> io::Result { - let res = self.read_at(buf, self.pos); - if let Ok(bytes_read) = res { - self.pos += bytes_read as u64; - } - res - } -} diff --git a/src/ext2/metadata.rs b/src/ext2/metadata.rs deleted file mode 100644 index f52cc63..0000000 --- a/src/ext2/metadata.rs +++ /dev/null @@ -1,252 +0,0 @@ -#![allow(unused)] -use super::structs::Inode; - -#[derive(Copy, Clone, Debug)] -pub struct Permissions(u32); - -impl Permissions { - /// Returns `true` if these permissions describe a readonly (unwritable) file. - pub fn readonly(self) -> bool { - // check if any class (owner, group, others) has write permission - self.0 & 0o222 == 0 - } - - /// Modifies the readonly flag for this set of permissions. If the - /// `readonly` argument is `true`, using the resulting `Permission` will - /// update file permissions to forbid writing. Conversely, if it's `false`, - /// using the resulting `Permission` will update file permissions to allow - /// writing. - /// - /// This operation does **not** modify the filesystem. - pub fn set_readonly(mut self, readonly: bool) { - if readonly { - // remove write permission for all classes; equivalent to `chmod a-w ` - self.0 &= !0o222; - } else { - // add write permission for all classes; equivalent to `chmod a+w ` - self.0 |= 0o222; - } - } - - /// Returns the underlying raw `st_mode` bits that contain the standard - /// Unix permissions for this file. - pub fn mode(self) -> u32 { - self.0 as u32 - } - - /// Sets the underlying raw bits for this set of permissions. - pub fn set_mode(mut self, mode: u32) { - self.0 = mode; - } - - /// Creates a new instance of `Permissions` from the given set of Unix - /// permission bits. - pub fn from_mode(mode: u32) -> Self { - Self(mode) - } -} - -#[derive(Debug, PartialEq, Eq, Copy, Clone)] -pub enum FileType { - Fifo, - CharDev, - Directory, - BlockDev, - File, - SymLink, - Socket, -} - -impl FileType { - /// Tests whether this file type represents a directory. The - /// result is mutually exclusive to the results of - /// [`is_file`] and [`is_symlink`]; only zero or one of these - /// tests may pass. - pub fn is_dir(self) -> bool { - self == Self::Directory - } - - /// Tests whether this file type represents a regular file. - /// The result is mutually exclusive to the results of - /// [`is_dir`] and [`is_symlink`]; only zero or one of these - /// tests may pass. - pub fn is_file(self) -> bool { - self == Self::File - } - - /// Tests whether this file type represents a symbolic link. - /// The result is mutually exclusive to the results of - /// [`is_dir`] and [`is_file`]; only zero or one of these - /// tests may pass. - pub fn is_symlink(self) -> bool { - self == Self::SymLink - } - - /// Returns `true` if this file type is a fifo. - pub fn is_fifo(self) -> bool { - self == Self::Fifo - } - - /// Returns `true` if this file type is a block device. - pub fn is_block_device(self) -> bool { - self == Self::BlockDev - } - - /// Returns `true` if this file type is a char device. - pub fn is_char_device(self) -> bool { - self == Self::CharDev - } - - /// Returns `true` if this file type is a socket. - pub fn is_socket(self) -> bool { - self == Self::Socket - } -} - -#[derive(Copy, Clone, Debug)] -pub struct Metadata { - accessed: u32, - created: u32, - file_type: FileType, - length: u64, - modified: u32, - permissions: Permissions, - ino: u64, - nlink: u64, - uid: u32, - gid: u32, - // blksize: u64, - blocks: u64, -} - -impl Metadata { - pub(super) fn from_inode(inode: &Inode) -> Self { - let file_type = match (inode.type_perms & 0xF000) >> 12 { - 1 => FileType::Fifo, - 2 => FileType::CharDev, - 4 => FileType::Directory, - 6 => FileType::BlockDev, - 8 => FileType::File, - 0xA => FileType::SymLink, - 0xC => FileType::Socket, - x => panic!("Invalid inode file type {}", x), - }; - let permissions = Permissions(u32::from(inode.type_perms & 0xFFF)); - Self { - accessed: inode.last_access_time, - created: inode.creation_time, - file_type, - length: u64::from(inode.size_lower32), - modified: inode.last_modification_time, - permissions, - ino: u64::from(inode.number), - nlink: u64::from(inode.hard_links_count), - uid: u32::from(inode.uid), - gid: u32::from(inode.gid), - // blksize: inode.reader.block_size as u64, - blocks: u64::from(inode.sectors_used), - } - } - - /// Returns the last access time of this metadata. - /// - /// The returned value corresponds to the `atime` field of `stat` - pub fn accessed(&self) -> u32 { - self.accessed - } - - /// Returns the creation time listed in this metadata. - /// - /// The returned value corresponds to the `btime` field of `statx` on - /// Linux kernel starting from to 4.11, and the `birthtime` field of `stat` on - /// other Unix platforms. - pub fn created(&self) -> u32 { - self.created - } - - /// Returns the last modification time listed in this metadata. - /// - /// The returned value corresponds to the `mtime` field of `stat` - pub fn modified(&self) -> u32 { - self.modified - } - - /// Returns the file type for this metadata. - pub fn file_type(&self) -> FileType { - self.file_type - } - - /// Returns `true` if this metadata is for a directory. The - /// result is mutually exclusive to the result of - /// [`Metadata::is_file`], and will be false for symlink metadata - /// obtained from [`symlink_metadata`]. - pub fn is_dir(&self) -> bool { - self.file_type.is_dir() - } - - /// Returns `true` if this metadata is for a regular file. The - /// result is mutually exclusive to the result of - /// [`Metadata::is_dir`], and will be false for symlink metadata - /// obtained from [`symlink_metadata`]. - /// - /// When the goal is simply to read from (or write to) the source, the most0.227s - /// reliable way to test the source can be read (or written to) is to open - /// it. Only using `is_file` can break workflows like `diff <( prog_a )` on - /// a Unix-like system for example. See [`File::open`] or - /// [`OpenOptions::open`] for more information. - pub fn is_file(&self) -> bool { - self.file_type.is_file() - } - - /// Returns `true` if this metadata is for a symbolic link. - pub fn is_symlink(&self) -> bool { - self.file_type.is_symlink() - } - - /// Returns the size of the file, in bytes, this metadata is for. - pub fn len(&self) -> u64 { - self.length - } - - /// Returns the permissions of the file this metadata is for. - pub fn permissions(&self) -> Permissions { - self.permissions - } - - /// Returns the inode number. - pub fn ino(&self) -> u64 { - self.ino - } - - /// Returns the rights applied to this file. - pub fn mode(&self) -> u32 { - self.permissions.0 - } - - /// Returns the number of hard links pointing to this file. - pub fn nlink(&self) -> u64 { - self.nlink - } - - /// Returns the user ID of the owner of this file. - pub fn uid(&self) -> u32 { - self.uid - } - - /// Returns the group ID of the owner of this file. - pub fn gid(&self) -> u32 { - self.gid - } - - // /// Returns the block size for filesystem I/O. - // pub fn blksize(&self) -> u64 { - // self.blksize - // } - - /// Returns the number of blocks allocated to the file, in 512-byte units. - /// - /// Please note that this may be smaller than `st_size / 512` when the file has holes. - pub fn blocks(&self) -> u64 { - self.blocks - } -} diff --git a/src/ext2/structs.rs b/src/ext2/structs.rs deleted file mode 100644 index becc2f8..0000000 --- a/src/ext2/structs.rs +++ /dev/null @@ -1,159 +0,0 @@ -use super::{block_reader::BlockReader, Ext2}; -use binread::prelude::*; -use itertools::Itertools; -use std::dbg; -use std::io::{self, Read, Seek, SeekFrom}; -use std::vec::Vec; - -use std::fs::File as StdFile; - -#[repr(u16)] -#[derive(Debug, BinRead)] -#[br(repr=u16)] -pub enum FSState { - Clean = 1, - HasErrors = 2, -} - -#[repr(u16)] -#[derive(Debug, BinRead)] -#[br(repr=u16)] -pub enum ErrorHandlingMethod { - Ignore = 1, - RemountRO = 2, - Panic = 3, -} - -#[derive(Debug, BinRead)] -#[allow(unused)] -pub struct Superblock { - pub total_inodes: u32, - pub total_blocks: u32, - pub superuser_blocks: u32, - pub unallocated_blocks: u32, - pub unallocated_inodes: u32, - pub superblock_block: u32, - pub block_size_raw: u32, - pub fragment_size_raw: u32, - pub block_group_block_count: u32, - pub block_group_fragment_count: u32, - pub block_group_inode_count: u32, - pub last_mount_time: u32, - pub last_written_time: u32, - pub times_mounted_since_last_check: u16, - pub max_mounts_before_check: u16, - pub ext2_sig: u16, - pub fs_state: FSState, - pub error_handling_method: ErrorHandlingMethod, - pub version_minor: u16, - pub last_check_time: u32, - pub max_interval_between_check: u32, - pub creation_os_id: u32, - pub version_major: u32, - pub reserved_uid: u16, - pub reserved_gid: u16, -} - -impl Superblock { - pub fn read_from_disk(disk: &mut StdFile) -> io::Result { - disk.seek(SeekFrom::Start(1024))?; - Ok(disk.read_le().unwrap()) - } -} - -#[derive(Debug, Clone, BinRead)] -#[allow(unused)] -pub struct BlockGroupDescriptor { - pub block_usage_block: u32, - pub inode_usage_block: u32, - pub inode_table_start: u32, - pub unallocated_blocks: u16, - pub unallocated_inodes: u16, - pub num_directories: u16, - pub reserved: [u8; 14], -} - -#[derive(Debug, BinRead)] -#[allow(unused)] -pub struct DirEntryDisk { - pub inode: u32, - pub entry_size: u16, - pub name_len: u8, - pub high_len_or_type: u8, - #[br(count = name_len)] - #[br(pad_after(i64::from(entry_size - u16::from(name_len) - 8)))] - pub name: Vec, -} - -#[derive(Debug, Clone, BinRead)] -#[br(import(number: u32))] -#[allow(unused)] -pub struct Inode { - pub type_perms: u16, - pub uid: u16, - pub size_lower32: u32, - pub last_access_time: u32, - pub creation_time: u32, - pub last_modification_time: u32, - pub deletion_time: u32, - pub gid: u16, - pub hard_links_count: u16, - pub sectors_used: u32, - pub flags: u32, - pub os_specific_1: u32, - pub direct_block_pointers: [u32; 12], - pub singly_indirect_block_pointer: u32, - pub doubly_indirect_block_pointer: u32, - pub triply_indirect_block_pointer: u32, - pub generation_number: u32, - pub file_acl: u32, - pub file_size_upper32_dir_acl: u32, - pub fragment_block_address: u32, - pub os_specific_2: [u8; 12], - #[br(calc = number)] - pub number: u32, -} - -impl Inode { - pub(super) fn read(fs: &Ext2, inode_num: u32) -> io::Result { - // dbg!(); - let ino = fs.descriptor_table.inode_loc(inode_num).read(&fs.reader); - // dbg!(); - ino - } - - #[allow(unused)] - pub fn pointer_block_blocks( - &self, - block: u32, - reader: &mut BlockReader, - ) -> io::Result>> { - Ok(reader - .read_block(block)? - .bytes() - .tuples::<(_, _, _, _)>() - .map(|raw| { - if let (Ok(b1), Ok(b2), Ok(b3), Ok(b4)) = raw { - Ok(u32::from_le_bytes([b1, b2, b3, b4])) - } else { - Err([raw.0, raw.1, raw.2, raw.3] - .into_iter() - .find_map(Result::err) - .expect("Not all bytes were Ok, yet all are not Err")) - } - }) - .filter(|x| if let &Ok(x) = x { x != 0 } else { true })) - } - - pub fn log_to_phys_block(&self, block: u32) -> Option { - if block < 12 { - if self.direct_block_pointers[block as usize] == 0 { - None - } else { - Some(self.direct_block_pointers[block as usize]) - } - } else { - unimplemented!() - } - } -} diff --git a/src/main.rs b/src/main.rs index 0149425..afe3e1c 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,59 +1,18 @@ -#![no_std] -#![no_main] #![feature(int_roundings)] #![deny(unsafe_op_in_unsafe_fn)] -use ext2::Ext2; -use std::fmt::Debug; -use std::fs::File; -use std::loader::Loader; -use std::path::Path; -use std::prelude::*; -use std::syscalls::{get_initrd, new_process}; +use std::os::mikros::loader::Loader; +use std::os::mikros::syscalls::{get_initrd, new_process}; use tar_no_std::TarArchiveRef; -mod ata; -mod ext2; - -main!({ - dbg!(); - // let primary_slave = PRIMARY_SLAVE.unwrap(); - let initrd = TarArchiveRef::new(get_initrd()); - dbg!(); - let test_proc = +fn main() { + let initrd = TarArchiveRef::new(get_initrd()).unwrap(); + let vfs = initrd .entries() - .find(|entry| entry.filename() == *"bin/test_proc") - .expect("test_proc not found") + .find(|entry| entry.filename().as_str().unwrap() == "bin/vfs") + .expect("vfs not found") .data(); - dbg!(); - let (space, entry) = Loader::load(&test_proc); - dbg!(); - let pid = new_process(entry as _, space).expect("Failed to create process"); - dbg!(); - let client = dev_driver_rpc::Client::new(pid); - dbg!(); - let fd = client.open("sdb").unwrap(); - dbg!(); - let sdb = File::from_pid_fd(pid, fd); - dbg!(); - let fs = Ext2::new(sdb).unwrap(); - dbg!(); - print_all_files("/", &fs); - dbg!(); -}); - -fn print_all_files + Debug>(path: P, fs: &Ext2) { - for entry in fs.read_dir(path).unwrap() { - let entry = entry.unwrap(); - println!("{:?}", entry.path()); - // if entry.metadata().file_type().is_dir() { - // // print_all_files(entry.path(), fs); - // } else { - // // let mut file = fs.open(entry.path()).unwrap(); - // // let mut buf = String::new(); - // // file.read_to_string(&mut buf).unwrap(); - // // print!("{:?}:\n{}", entry.path(), buf); - // } - } + let (space, entry) = Loader::load(&vfs); + new_process(entry as _, space).unwrap(); }