diff --git a/Cargo.lock b/Cargo.lock index e101de9edb..0bc2322768 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -937,7 +937,6 @@ dependencies = [ [[package]] name = "partitionlib" version = "0.1.0" -source = "git+https://gitlab.redox-os.org/redox-os/partitionlib.git#9e48718a0553a4d0d4070994053e1c402bb33b91" dependencies = [ "gpt", "scroll", diff --git a/storage/driver-block/Cargo.toml b/storage/driver-block/Cargo.toml index f876f19832..278520adca 100644 --- a/storage/driver-block/Cargo.toml +++ b/storage/driver-block/Cargo.toml @@ -4,6 +4,6 @@ version = "0.1.0" edition = "2021" [dependencies] -partitionlib = { git = "https://gitlab.redox-os.org/redox-os/partitionlib.git" } +partitionlib = { path = "../partitionlib" } redox_syscall = "0.5" diff --git a/storage/nvmed/Cargo.toml b/storage/nvmed/Cargo.toml index 1a00ca727a..04cf4bb27c 100644 --- a/storage/nvmed/Cargo.toml +++ b/storage/nvmed/Cargo.toml @@ -13,7 +13,7 @@ redox-daemon = "0.1" redox_syscall = { version = "0.5", features = ["std"] } redox-scheme = { git = "https://gitlab.redox-os.org/redox-os/redox-scheme.git" } redox_event = "0.4" -partitionlib = { git = "https://gitlab.redox-os.org/redox-os/partitionlib.git" } +partitionlib = { path = "../partitionlib" } smallvec = "1" common = { path = "../../common" } diff --git a/storage/partitionlib/Cargo.toml b/storage/partitionlib/Cargo.toml new file mode 100644 index 0000000000..27df61ce16 --- /dev/null +++ b/storage/partitionlib/Cargo.toml @@ -0,0 +1,11 @@ +[package] +name = "partitionlib" +version = "0.1.0" +authors = ["Deepak Sirone "] +edition = "2018" +license = "MIT" + +[dependencies] +gpt = { version = "3.0.1" } +scroll = { version = "0.10", features = ["derive"] } +uuid = { version = "1.0", features = ["v4"] } diff --git a/storage/partitionlib/resources/disk.img b/storage/partitionlib/resources/disk.img new file mode 100644 index 0000000000..76913628c2 Binary files /dev/null and b/storage/partitionlib/resources/disk.img differ diff --git a/storage/partitionlib/resources/disk_mbr.img b/storage/partitionlib/resources/disk_mbr.img new file mode 100644 index 0000000000..429d41ca6b Binary files /dev/null and b/storage/partitionlib/resources/disk_mbr.img differ diff --git a/storage/partitionlib/src/lib.rs b/storage/partitionlib/src/lib.rs new file mode 100644 index 0000000000..1b0b71b4e5 --- /dev/null +++ b/storage/partitionlib/src/lib.rs @@ -0,0 +1,7 @@ +extern crate gpt; +extern crate uuid; + +pub type Result = std::io::Result; +mod mbr; +pub mod partition; +pub use self::partition::*; diff --git a/storage/partitionlib/src/mbr.rs b/storage/partitionlib/src/mbr.rs new file mode 100644 index 0000000000..cf129ce356 --- /dev/null +++ b/storage/partitionlib/src/mbr.rs @@ -0,0 +1,77 @@ +use scroll::{Pread, Pwrite}; +use std::io; +use std::io::prelude::*; + +#[derive(Clone, Copy, Debug, Pread, Pwrite)] +pub struct Entry { + pub drive_attrs: u8, + pub start_head: u8, + pub start_cs: u16, + pub sys_id: u8, + pub end_head: u8, + pub end_cs: u16, + pub rel_sector: u32, + pub len: u32, +} + +#[derive(Pread, Pwrite)] +pub struct Header { + pub bootstrap: [u8; 446], + pub first_entry: Entry, + pub second_entry: Entry, + pub third_entry: Entry, + pub fourth_entry: Entry, + pub last_signature: u16, // 0xAA55 +} + +#[derive(Debug)] +pub enum Error { + IoError(io::Error), + ParsingError(scroll::Error), +} + +impl From for Error { + fn from(err: io::Error) -> Self { + Self::IoError(err) + } +} +impl From for Error { + fn from(err: scroll::Error) -> Self { + Self::ParsingError(err) + } +} + +pub fn read_header(device: &mut D) -> Result { + device.seek(io::SeekFrom::Start(0))?; + + let mut bytes = [0u8; 512]; + device.read_exact(&mut bytes)?; + + let header: Header = bytes.pread_with(0, scroll::LE)?; + + if header.last_signature != 0xAA55 { + return Err(scroll::Error::BadInput { + size: 2, + msg: "no 0xAA55 signature", + } + .into()); + } + + Ok(header) +} + +impl Header { + pub fn partitions(&self) -> [Entry; 4] { + [ + self.first_entry, + self.second_entry, + self.third_entry, + self.fourth_entry, + ] + } +} +impl Entry { + pub fn is_valid(&self) -> bool { + (self.drive_attrs == 0 || self.drive_attrs == 0x80) && self.len != 0 + } +} diff --git a/storage/partitionlib/src/partition.rs b/storage/partitionlib/src/partition.rs new file mode 100644 index 0000000000..030f292852 --- /dev/null +++ b/storage/partitionlib/src/partition.rs @@ -0,0 +1,115 @@ +use super::Result; +pub use gpt::disk::LogicalBlockSize; +use std::fs::File; +use std::io::prelude::*; +use std::path::Path; +use uuid::Uuid; + +/// A union of the MBR and GPT partition entry +#[derive(Clone, Debug, Eq, Hash, PartialEq)] +pub struct Partition { + /// The starting logical block number + pub start_lba: u64, + /// The size of the partition in sectors + pub size: u64, + pub flags: Option, + pub name: Option, + pub uuid: Option, +} + +#[derive(Clone, Copy, Debug, Eq, PartialEq, Hash)] +pub enum PartitionTableKind { + Mbr, + Gpt, +} +impl Default for PartitionTableKind { + fn default() -> Self { + Self::Gpt + } +} +impl PartitionTableKind { + pub fn is_mbr(self) -> bool { + self == Self::Mbr + } + pub fn is_gpt(self) -> bool { + self == Self::Gpt + } +} + +#[derive(Clone, Debug, Eq, PartialEq, Hash)] +pub struct PartitionTable { + pub partitions: Vec, + pub kind: PartitionTableKind, +} + +pub fn get_partitions_from_file>( + path: P, + sector_size: LogicalBlockSize, +) -> Result> { + let mut file = File::open(path)?; + get_partitions(&mut file, sector_size) +} +fn get_gpt_partitions( + device: &mut D, + sector_size: LogicalBlockSize, +) -> Result { + let header = match gpt::header::read_header_from_arbitrary_device(device, sector_size) { + Ok(res) => res, + Err(err) => return Err(err), + }; + Ok(PartitionTable { + partitions: gpt::partition::file_read_partitions(device, &header, sector_size).map( + |btree| { + btree + .into_iter() + .map(|(_, part)| Partition { + flags: Some(part.flags), + size: part.last_lba - part.first_lba + 1, + name: Some(part.name.clone()), + uuid: Some(part.part_guid), + start_lba: part.first_lba, + }) + .collect() + }, + )?, + kind: PartitionTableKind::Gpt, + }) +} +fn get_mbr_partitions(device: &mut D) -> Result> { + let header = match crate::mbr::read_header(device) { + Ok(h) => h, + Err(crate::mbr::Error::ParsingError(_)) => return Ok(None), + Err(crate::mbr::Error::IoError(ioerr)) => return Err(ioerr), + }; + Ok(Some(PartitionTable { + kind: PartitionTableKind::Mbr, + partitions: header + .partitions() + .iter() + .copied() + .filter(crate::mbr::Entry::is_valid) + .map(|partition: crate::mbr::Entry| Partition { + name: None, + uuid: None, // TODO: Some kind of one-way conversion should be possible + flags: None, // TODO + size: partition.len.into(), + start_lba: partition.rel_sector.into(), + }) + .collect(), + })) +} +pub fn get_partitions( + device: &mut D, + sector_size: LogicalBlockSize, +) -> Result> { + get_gpt_partitions(device, sector_size) + .map(Some) + .or_else(|_| get_mbr_partitions(device)) +} + +impl Partition { + pub fn to_offset(&self, sector_size: LogicalBlockSize) -> u64 { + let blksize: u64 = sector_size.into(); + self.start_lba * blksize + } +} diff --git a/storage/partitionlib/tests/test.rs b/storage/partitionlib/tests/test.rs new file mode 100644 index 0000000000..a9254c859b --- /dev/null +++ b/storage/partitionlib/tests/test.rs @@ -0,0 +1,54 @@ +extern crate partitionlib; + +use partitionlib::{get_partitions_from_file, LogicalBlockSize, Partition}; + +#[test] +fn part_is_gpt() { + assert!(dbg!( + get_partitions_from_file("./resources/disk.img", LogicalBlockSize::Lb512) + .unwrap() + .unwrap() + ) + .kind + .is_gpt()); +} + +#[test] +fn part_is_mbr() { + assert!( + get_partitions_from_file("./resources/disk_mbr.img", LogicalBlockSize::Lb512) + .unwrap() + .unwrap() + .kind + .is_mbr() + ); +} + +// NOTE: The following tests rely on outside resource files being correct. +#[test] +fn gpt() { + let table = get_partitions_from_file("./resources/disk.img", LogicalBlockSize::Lb512).unwrap().unwrap(); + assert_eq!(&table.partitions, &[ + Partition { + flags: Some(0), + name: Some("bug".to_owned()), + uuid: Some(uuid::Uuid::parse_str("b665fba9-74d5-4069-a6b9-5ba3a164fdfe").unwrap()), // Microsoft basic data + size: 957, + start_lba: 34, + } + ]); +} + +#[test] +fn mbr() { + let table = get_partitions_from_file("./resources/disk_mbr.img", LogicalBlockSize::Lb512).unwrap().unwrap(); + assert_eq!(&table.partitions, &[ + Partition { + flags: None, + name: None, + uuid: None, + size: 3, + start_lba: 1, + } + ]); +} diff --git a/storage/virtio-blkd/Cargo.toml b/storage/virtio-blkd/Cargo.toml index c9d09ad78d..de7aba04a1 100644 --- a/storage/virtio-blkd/Cargo.toml +++ b/storage/virtio-blkd/Cargo.toml @@ -15,7 +15,7 @@ spin = "*" redox-daemon = "0.1" redox_syscall = { version = "0.5", features = ["std"] } redox-scheme = { git = "https://gitlab.redox-os.org/redox-os/redox-scheme.git" } -partitionlib = { git = "https://gitlab.redox-os.org/redox-os/partitionlib.git" } +partitionlib = { path = "../partitionlib" } common = { path = "../../common" } driver-block = { path = "../driver-block" } diff --git a/storage/virtio-blkd/src/scheme.rs b/storage/virtio-blkd/src/scheme.rs index 217bf68f94..609f5f5059 100644 --- a/storage/virtio-blkd/src/scheme.rs +++ b/storage/virtio-blkd/src/scheme.rs @@ -191,6 +191,9 @@ impl<'a> DiskScheme<'a> { block_bytes: &mut [0u8; 4096], }; + //driver_block::DiskWrapper::new(disk) + + // FIXME use DiskWrapper instead let part_table = partitionlib::get_partitions(&mut shim, LogicalBlockSize::Lb512) .ok() .flatten();