use crate::error::{Error, Result};
use crate::gpt;
use crate::mbr;
use crate::BlockRead;
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum TableKind {
Gpt,
Mbr,
}
#[derive(Debug, Clone)]
pub struct Partition {
pub start: u64,
pub length: u64,
pub kind: PartitionKind,
pub label: Option<String>,
pub uuid: Option<[u8; 16]>,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum PartitionKind {
Gpt {
type_guid: [u8; 16],
attributes: u64,
},
Mbr {
type_byte: u8,
active: bool,
},
Whole,
}
impl Partition {
pub fn is_bootable(&self) -> bool {
match self.kind {
PartitionKind::Mbr { active, .. } => active,
PartitionKind::Gpt {
type_guid,
attributes,
} => {
type_guid == crate::gpt::type_guids::EFI_SYSTEM
|| (attributes & crate::gpt::attr::LEGACY_BIOS_BOOTABLE) != 0
}
PartitionKind::Whole => false,
}
}
}
pub fn probe(dev: &dyn BlockRead) -> Result<(TableKind, Vec<Partition>)> {
let mut lba0 = [0u8; 512];
let mut lba1 = [0u8; 512];
dev.read_at(0, &mut lba0)?;
if dev.size_bytes() >= 1024 {
dev.read_at(512, &mut lba1)?;
}
let has_mbr_sig = lba0[510] == 0x55 && lba0[511] == 0xAA;
let gpt_sig = &lba1[0..8];
let has_gpt_sig = gpt_sig == gpt::SIGNATURE;
if has_gpt_sig {
let parts = gpt::parse(dev, &lba1)?;
return Ok((TableKind::Gpt, parts));
}
if has_mbr_sig {
if mbr::is_protective(&lba0) {
return Err(Error::GptCorrupt(
"protective MBR present but no GPT signature",
));
}
let parts = mbr::parse(&lba0)?;
return Ok((TableKind::Mbr, parts));
}
Err(Error::NoPartitionTable)
}