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
7071use crate :: data_types:: UnalignedCStr16 ;
7172use crate :: proto:: { Protocol , ProtocolPointer } ;
72- use crate :: unsafe_guid;
73+ use crate :: { unsafe_guid, Guid } ;
7374use core:: ffi:: c_void;
7475use core:: marker:: { PhantomData , PhantomPinned } ;
7576use 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) ]
583685mod 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