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..8e5e3fad44 --- /dev/null +++ b/storage/partitionlib/Cargo.toml @@ -0,0 +1,11 @@ +[package] +name = "partitionlib" +version = "0.1.0" +authors = ["Deepak Sirone "] +edition = "2021" +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..be369ce64e --- /dev/null +++ b/storage/partitionlib/src/lib.rs @@ -0,0 +1,3 @@ +mod mbr; +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..67ae5a6dad --- /dev/null +++ b/storage/partitionlib/src/mbr.rs @@ -0,0 +1,57 @@ +use scroll::{Pread, Pwrite}; +use std::io::{self, Read, Seek}; + +#[derive(Clone, Copy, Debug, Pread, Pwrite)] +pub(crate) struct Entry { + pub(crate) drive_attrs: u8, + pub(crate) start_head: u8, + pub(crate) start_cs: u16, + pub(crate) sys_id: u8, + pub(crate) end_head: u8, + pub(crate) end_cs: u16, + pub(crate) rel_sector: u32, + pub(crate) len: u32, +} + +#[derive(Pread, Pwrite)] +pub(crate) struct Header { + pub(crate) bootstrap: [u8; 446], + pub(crate) first_entry: Entry, + pub(crate) second_entry: Entry, + pub(crate) third_entry: Entry, + pub(crate) fourth_entry: Entry, + pub(crate) last_signature: u16, // 0xAA55 +} + +pub(crate) fn read_header(device: &mut D) -> io::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).unwrap(); + + if header.last_signature != 0xAA55 { + return Ok(None); + } + + Ok(Some(header)) +} + +impl Header { + pub(crate) fn partitions(&self) -> impl Iterator { + [ + self.first_entry, + self.second_entry, + self.third_entry, + self.fourth_entry, + ] + .into_iter() + .filter(Entry::is_valid) + } +} +impl Entry { + 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..949171511b --- /dev/null +++ b/storage/partitionlib/src/partition.rs @@ -0,0 +1,84 @@ +pub use gpt::disk::LogicalBlockSize; +use std::io::{self, Read, Seek}; +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)] +pub enum PartitionTableKind { + Mbr, + Gpt, +} + +#[derive(Clone, Debug, Eq, PartialEq)] +pub struct PartitionTable { + pub partitions: Vec, + pub kind: PartitionTableKind, +} + +fn get_gpt_partitions( + device: &mut D, + sector_size: LogicalBlockSize, +) -> io::Result { + let header = gpt::header::read_header_from_arbitrary_device(device, sector_size)?; + 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) -> io::Result> { + let Some(header) = crate::mbr::read_header(device)? else { + return Ok(None); + }; + Ok(Some(PartitionTable { + kind: PartitionTableKind::Mbr, + partitions: header + .partitions() + .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, +) -> io::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..c4ef93220e --- /dev/null +++ b/storage/partitionlib/tests/test.rs @@ -0,0 +1,45 @@ +use std::fs::File; + +use partitionlib::{ + get_partitions, LogicalBlockSize, Partition, PartitionTable, PartitionTableKind, +}; + +fn get_partitions_from_file(path: &str) -> PartitionTable { + let mut file = File::open(path).unwrap(); + get_partitions(&mut file, LogicalBlockSize::Lb512) + .unwrap() + .unwrap() +} + +// NOTE: The following tests rely on outside resource files being correct. +#[test] +fn gpt() { + let table = get_partitions_from_file("./resources/disk.img"); + assert_eq!(table.kind, PartitionTableKind::Gpt); + 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"); + assert_eq!(table.kind, PartitionTableKind::Mbr); + 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();