Skip to content

Commit 1c62af7

Browse files
ColinFincknicholasbishop
authored andcommitted
Implement HardDriveMediaDevicePath (along with MBR and GPT tests).
1 parent dbf9ad1 commit 1c62af7

File tree

1 file changed

+151
-1
lines changed

1 file changed

+151
-1
lines changed

src/proto/device_path/mod.rs

Lines changed: 151 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,7 @@
4343
//! currently implemented:
4444
//! * [`AcpiDevicePath`]
4545
//! * [`FilePathMediaDevicePath`]
46+
//! * [`HardDriveMediaDevicePath`]
4647
//!
4748
//! * [`DevicePathHeader`] is a header present at the start of every
4849
//! node. It describes the type of node as well as the node's size.
@@ -69,7 +70,7 @@ pub mod text;
6970

7071
use crate::data_types::UnalignedCStr16;
7172
use crate::proto::{Protocol, ProtocolPointer};
72-
use crate::unsafe_guid;
73+
use crate::{unsafe_guid, Guid};
7374
use core::ffi::c_void;
7475
use core::marker::{PhantomData, PhantomPinned};
7576
use core::{mem, ptr};
@@ -177,6 +178,20 @@ impl DevicePathNode {
177178
None
178179
}
179180
}
181+
182+
/// Convert to a [`HardDriveMediaDevicePath`]. Returns `None` if the
183+
/// node is not of the appropriate type.
184+
pub fn as_hard_drive_media_device_path(&self) -> Option<&HardDriveMediaDevicePath> {
185+
if self.full_type() == (DeviceType::MEDIA, DeviceSubType::MEDIA_HARD_DRIVE) {
186+
assert!({ self.header.length } == HARD_DRIVE_MEDIA_DEVICE_PATH_LENGTH);
187+
188+
let p = self as *const Self;
189+
let p = p.cast::<HardDriveMediaDevicePath>();
190+
Some(unsafe { &*p })
191+
} else {
192+
None
193+
}
194+
}
180195
}
181196

182197
/// A single device path instance that ends with either an [`END_INSTANCE`]
@@ -579,6 +594,93 @@ impl FilePathMediaDevicePath {
579594
}
580595
}
581596

597+
/// Hard Drive Media Device Path.
598+
#[repr(C, packed)]
599+
pub struct HardDriveMediaDevicePath {
600+
header: DevicePathHeader,
601+
partition_number: u32,
602+
partition_start: u64,
603+
partition_size: u64,
604+
partition_signature: PartitionSignatureUnion,
605+
partition_format: PartitionFormat,
606+
signature_type: SignatureType,
607+
}
608+
609+
/// [`HardDriveMediaDevicePath`] is a fixed-length structure of 42 bytes.
610+
const HARD_DRIVE_MEDIA_DEVICE_PATH_LENGTH: u16 = 42;
611+
612+
impl HardDriveMediaDevicePath {
613+
/// Returns the format of the partition (MBR, GPT, or unknown).
614+
pub fn partition_format(&self) -> PartitionFormat {
615+
self.partition_format
616+
}
617+
618+
/// Returns the 1-based index of the partition.
619+
pub fn partition_number(&self) -> u32 {
620+
self.partition_number
621+
}
622+
623+
/// Returns the partition size in logical blocks.
624+
pub fn partition_size(&self) -> u64 {
625+
self.partition_size
626+
}
627+
628+
/// Returns the starting LBA of the partition.
629+
pub fn partition_start(&self) -> u64 {
630+
self.partition_start
631+
}
632+
633+
/// Returns the MBR or GPT partition signature
634+
pub fn partition_signature(&self) -> Option<PartitionSignature> {
635+
match self.signature_type {
636+
SignatureType::MBR => {
637+
let mbr_signature = unsafe { self.partition_signature.mbr_signature };
638+
Some(PartitionSignature::MBR(mbr_signature))
639+
}
640+
SignatureType::GUID => {
641+
let guid = unsafe { self.partition_signature.guid };
642+
Some(PartitionSignature::GUID(guid))
643+
}
644+
_ => None,
645+
}
646+
}
647+
}
648+
649+
newtype_enum! {
650+
/// Partition format.
651+
pub enum PartitionFormat: u8 => {
652+
/// MBR (PC-AT compatible Master Boot Record) format.
653+
MBR = 0x01,
654+
/// GPT (GUID Partition Table) format.
655+
GPT = 0x02,
656+
}
657+
}
658+
659+
/// Partition signature.
660+
#[derive(Clone, Debug, Eq, PartialEq)]
661+
pub enum PartitionSignature {
662+
/// 32-bit MBR partition signature.
663+
MBR(u32),
664+
/// 128-bit GUID partition signature.
665+
GUID(Guid),
666+
}
667+
668+
#[repr(C)]
669+
union PartitionSignatureUnion {
670+
mbr_signature: u32,
671+
guid: Guid,
672+
}
673+
674+
newtype_enum! {
675+
/// Signature type.
676+
enum SignatureType: u8 => {
677+
/// 32-bit MBR partition signature.
678+
MBR = 0x01,
679+
/// 128-bit GUID partition signature.
680+
GUID = 0x02,
681+
}
682+
}
683+
582684
#[cfg(test)]
583685
mod tests {
584686
use super::*;
@@ -716,4 +818,52 @@ mod tests {
716818
CString16::try_from("test").unwrap()
717819
);
718820
}
821+
822+
#[test]
823+
fn test_hard_drive_media_mbr() {
824+
let mbr_partition_bytes: [u8; 42] = [
825+
0x04, 0x01, 0x2a, 0x00, 0x01, 0x00, 0x00, 0x00, 0x3f, 0x00, 0x00, 0x00, 0x00, 0x00,
826+
0x00, 0x00, 0xc1, 0xbf, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfa, 0xfd, 0x1a, 0xbe,
827+
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01,
828+
];
829+
let dp = unsafe { DevicePathNode::from_ffi_ptr(mbr_partition_bytes.as_ptr().cast()) };
830+
assert_eq!(dp.length(), HARD_DRIVE_MEDIA_DEVICE_PATH_LENGTH);
831+
832+
let hdm = dp.as_hard_drive_media_device_path().unwrap();
833+
assert_eq!(hdm.partition_format(), PartitionFormat::MBR);
834+
assert_eq!(hdm.partition_number(), 1);
835+
assert_eq!(hdm.partition_size(), 1032129);
836+
assert_eq!(hdm.partition_start(), 63);
837+
assert_eq!(
838+
hdm.partition_signature(),
839+
Some(PartitionSignature::MBR(0xBE1AFDFA))
840+
);
841+
}
842+
843+
#[test]
844+
fn test_hard_drive_media_gpt() {
845+
let guid_partition_bytes: [u8; 42] = [
846+
0x04, 0x01, 0x2a, 0x00, 0x01, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00,
847+
0x00, 0x00, 0x00, 0x10, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0xa0, 0x39, 0xaa, 0x41,
848+
0x35, 0x3d, 0x84, 0x4f, 0xb1, 0x95, 0xae, 0x3a, 0x95, 0x0b, 0xfb, 0xad, 0x02, 0x02,
849+
];
850+
let dp = unsafe { DevicePathNode::from_ffi_ptr(guid_partition_bytes.as_ptr().cast()) };
851+
assert_eq!(dp.length(), HARD_DRIVE_MEDIA_DEVICE_PATH_LENGTH);
852+
853+
let hdm = dp.as_hard_drive_media_device_path().unwrap();
854+
assert_eq!(hdm.partition_format(), PartitionFormat::GPT);
855+
assert_eq!(hdm.partition_number(), 1);
856+
assert_eq!(hdm.partition_size(), 200704);
857+
assert_eq!(hdm.partition_start(), 128);
858+
assert_eq!(
859+
hdm.partition_signature(),
860+
Some(PartitionSignature::GUID(Guid::from_values(
861+
0x41aa39a0,
862+
0x3d35,
863+
0x4f84,
864+
0xb195,
865+
0xae3a950bfbad
866+
)))
867+
);
868+
}
719869
}

0 commit comments

Comments
 (0)