#![no_std]
#![deny(missing_docs)]
#![allow(async_fn_in_trait)]
#![allow(clippy::duplicate_mod)]
#![cfg_attr(docsrs, feature(doc_cfg))]
#[cfg(feature = "alloc")]
extern crate alloc;
#[cfg(feature = "std")]
extern crate std;
pub mod error;
pub mod geometry;
pub mod gpt;
pub mod hybrid;
pub mod mbr;
pub mod scheme;
#[cfg(feature = "sync")]
#[path = ""]
pub mod sync {
pub use hadris_io::Result as IoResult;
pub use hadris_io::sync::{Parsable, Read, ReadExt, Seek, Writable, Write};
pub use hadris_io::{Error, ErrorKind, SeekFrom};
macro_rules! io_transform {
($($item:tt)*) => { hadris_macros::strip_async!{ $($item)* } };
}
#[allow(unused_macros)]
macro_rules! sync_only {
($($item:tt)*) => { $($item)* };
}
#[allow(unused_macros)]
macro_rules! async_only {
($($item:tt)*) => {};
}
#[path = "."]
mod __inner {
pub mod gpt_io;
pub mod mbr_io;
#[cfg(all(feature = "alloc", feature = "read"))]
#[path = "partition_table_io.rs"]
pub mod partition_table;
pub mod scheme_io;
}
pub use __inner::*;
}
#[cfg(feature = "async")]
#[path = ""]
pub mod r#async {
pub use hadris_io::Result as IoResult;
pub use hadris_io::r#async::{Parsable, Read, ReadExt, Seek, Writable, Write};
pub use hadris_io::{Error, ErrorKind, SeekFrom};
macro_rules! io_transform {
($($item:tt)*) => { $($item)* };
}
#[allow(unused_macros)]
macro_rules! sync_only {
($($item:tt)*) => {};
}
#[allow(unused_macros)]
macro_rules! async_only {
($($item:tt)*) => { $($item)* };
}
#[path = "."]
mod __inner {
pub mod gpt_io;
pub mod mbr_io;
#[cfg(all(feature = "alloc", feature = "read"))]
#[path = "partition_table_io.rs"]
pub mod partition_table;
pub mod scheme_io;
}
pub use __inner::*;
}
#[cfg(feature = "sync")]
pub use sync::*;
pub use endian_num::Le;
pub use error::{Error, Result};
pub use geometry::{DiskGeometry, validate_partition_alignment};
pub use gpt::{GptHeader, GptPartitionEntry, Guid};
pub use mbr::{Chs, MasterBootRecord, MbrPartition, MbrPartitionTable, MbrPartitionType};
pub use scheme::{PartitionInfo, PartitionSchemeType, PartitionType};
#[cfg(feature = "alloc")]
#[cfg_attr(docsrs, doc(cfg(feature = "alloc")))]
pub use scheme::{GptDisk, PartitionTable};
#[cfg(all(feature = "sync", feature = "read"))]
#[cfg_attr(docsrs, doc(cfg(feature = "read")))]
pub use sync::gpt_io::GptHeaderReadExt;
#[cfg(all(feature = "sync", feature = "write"))]
#[cfg_attr(docsrs, doc(cfg(feature = "write")))]
pub use sync::gpt_io::GptHeaderWriteExt;
#[cfg(all(feature = "sync", feature = "read"))]
#[cfg_attr(docsrs, doc(cfg(feature = "read")))]
pub use sync::mbr_io::MasterBootRecordReadExt;
#[cfg(all(feature = "sync", feature = "write"))]
#[cfg_attr(docsrs, doc(cfg(feature = "write")))]
pub use sync::mbr_io::MasterBootRecordWriteExt;
#[cfg(all(feature = "sync", feature = "alloc", feature = "read"))]
#[cfg_attr(docsrs, doc(cfg(all(feature = "alloc", feature = "read"))))]
pub use sync::scheme_io::{GptDiskReadExt, PartitionTableReadExt};
#[cfg(all(feature = "sync", feature = "alloc", feature = "write"))]
#[cfg_attr(docsrs, doc(cfg(all(feature = "alloc", feature = "write"))))]
pub use sync::scheme_io::{GptDiskWriteExt, PartitionTableWriteExt};
pub trait PartitionInfoTrait {
fn start_lba(&self) -> u64;
fn size_sectors(&self) -> u64;
fn end_lba(&self) -> u64 {
let size = self.size_sectors();
if size == 0 {
self.start_lba()
} else {
self.start_lba().saturating_add(size - 1)
}
}
fn checked_end_lba(&self) -> Option<u64> {
let size = self.size_sectors();
if size == 0 {
Some(self.start_lba())
} else {
self.start_lba().checked_add(size - 1)
}
}
fn byte_len(&self, logical_block_size: u32) -> Option<u64> {
self.size_sectors().checked_mul(logical_block_size as u64)
}
}
impl PartitionInfoTrait for MbrPartition {
fn start_lba(&self) -> u64 {
self.start_lba.to_ne() as u64
}
fn size_sectors(&self) -> u64 {
self.sector_count.to_ne() as u64
}
}
impl PartitionInfoTrait for GptPartitionEntry {
fn start_lba(&self) -> u64 {
self.first_lba.to_ne()
}
fn size_sectors(&self) -> u64 {
let first = self.first_lba.to_ne();
let last = self.last_lba.to_ne();
if self.is_unused() || last < first {
0
} else {
(last - first).saturating_add(1)
}
}
fn end_lba(&self) -> u64 {
self.last_lba.to_ne()
}
}
impl PartitionInfoTrait for PartitionInfo {
fn start_lba(&self) -> u64 {
self.start_lba
}
fn size_sectors(&self) -> u64 {
self.size_sectors
}
fn end_lba(&self) -> u64 {
self.end_lba
}
}
pub trait PartitionTableRead {
type Partition: PartitionInfoTrait;
fn partition_count(&self) -> usize;
fn partition(&self, index: usize) -> Option<&Self::Partition>;
}
impl PartitionTableRead for MbrPartitionTable {
type Partition = MbrPartition;
fn partition_count(&self) -> usize {
self.count()
}
fn partition(&self, index: usize) -> Option<&Self::Partition> {
if index < 4 && !self.partitions[index].is_empty() {
Some(&self.partitions[index])
} else {
None
}
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_mbr_partition_trait() {
let partition = MbrPartition::new(MbrPartitionType::Fat32, 2048, 204800);
assert_eq!(partition.start_lba(), 2048);
assert_eq!(partition.size_sectors(), 204800);
assert_eq!(partition.end_lba(), 2048 + 204800 - 1);
assert_eq!(partition.byte_len(512), Some(204800 * 512));
}
#[test]
fn test_gpt_partition_trait() {
let partition = GptPartitionEntry::new(Guid::EFI_SYSTEM, Guid::UNUSED, 2048, 206847);
assert_eq!(partition.start_lba(), 2048);
assert_eq!(partition.size_sectors(), 204800);
assert_eq!(partition.end_lba(), 206847);
}
#[test]
fn test_mbr_table_read_trait() {
let mut table = MbrPartitionTable::new();
table[0] = MbrPartition::new(MbrPartitionType::Fat32, 2048, 204800);
table[1] = MbrPartition::new(MbrPartitionType::LinuxNative, 206848, 1000000);
assert_eq!(table.partition_count(), 2);
assert!(table.partition(0).is_some());
assert!(table.partition(1).is_some());
assert!(table.partition(2).is_none());
assert!(table.partition(3).is_none());
}
#[test]
fn test_struct_sizes() {
assert_eq!(core::mem::size_of::<MbrPartition>(), 16);
assert_eq!(core::mem::size_of::<MbrPartitionTable>(), 64);
assert_eq!(core::mem::size_of::<MasterBootRecord>(), 512);
assert!(core::mem::size_of::<GptHeader>() >= 92);
assert_eq!(core::mem::size_of::<GptPartitionEntry>(), 128);
}
}