#![warn(
clippy::cast_lossless,
clippy::cast_possible_truncation,
clippy::cast_possible_wrap
)]
use std::io;
mod gpt;
mod le;
mod mbr;
pub use positioned_io2 as pio;
#[derive(Debug, Clone, Eq, PartialEq)]
pub enum Attributes {
MBR {
bootable: bool,
type_code: u8,
},
GPT {
type_uuid: [u8; 16],
partition_uuid: [u8; 16],
attributes: [u8; 8],
name: String,
},
}
#[derive(Debug, Clone, Eq, PartialEq)]
pub struct Partition {
pub id: usize,
pub first_byte: u64,
pub len: u64,
pub attributes: Attributes,
}
pub enum ReadMBR {
Modern,
Never,
}
pub enum ReadGPT {
RevisionOne,
Never,
}
pub enum SectorSize {
GuessOrAssume,
Known(u16),
}
pub struct Options {
pub mbr: ReadMBR,
pub gpt: ReadGPT,
pub sector_size: SectorSize,
}
impl Default for Options {
fn default() -> Self {
Options {
mbr: ReadMBR::Modern,
gpt: ReadGPT::RevisionOne,
sector_size: SectorSize::GuessOrAssume,
}
}
}
pub fn list_partitions<R>(reader: R, options: &Options) -> io::Result<Vec<Partition>>
where
R: pio::ReadAt,
{
let header_table = {
let mut disc_header = [0u8; 512];
reader.read_exact_at(0, &mut disc_header)?;
if 0x55 != disc_header[510] || 0xAA != disc_header[511] {
return Err(io::ErrorKind::NotFound.into());
}
mbr::parse_partition_table(&disc_header)?
};
match header_table.len() {
1 if gpt::is_protective(&header_table[0]) => {}
_ => {
return match options.mbr {
ReadMBR::Modern => Ok(header_table),
ReadMBR::Never => Err(io::ErrorKind::NotFound.into()),
}
}
}
match options.gpt {
ReadGPT::Never => Ok(header_table),
ReadGPT::RevisionOne => {
let sector_size = match options.sector_size {
SectorSize::Known(size) => u64::from(size),
SectorSize::GuessOrAssume => header_table[0].first_byte,
};
gpt::read(pio::Cursor::new(reader), sector_size)
}
}
}
pub fn open_partition<R>(inner: R, part: &Partition) -> io::Result<pio::Slice<R>>
where
R: pio::ReadAt,
{
Ok(pio::Slice::new(inner, part.first_byte, Some(part.len)))
}