43
43
//! currently implemented:
44
44
//! * [`AcpiDevicePath`]
45
45
//! * [`FilePathMediaDevicePath`]
46
+ //! * [`HardDriveMediaDevicePath`]
46
47
//!
47
48
//! * [`DevicePathHeader`] is a header present at the start of every
48
49
//! node. It describes the type of node as well as the node's size.
@@ -69,7 +70,7 @@ pub mod text;
69
70
70
71
use crate :: data_types:: UnalignedCStr16 ;
71
72
use crate :: proto:: { Protocol , ProtocolPointer } ;
72
- use crate :: unsafe_guid;
73
+ use crate :: { unsafe_guid, Guid } ;
73
74
use core:: ffi:: c_void;
74
75
use core:: marker:: { PhantomData , PhantomPinned } ;
75
76
use core:: { mem, ptr} ;
@@ -177,6 +178,20 @@ impl DevicePathNode {
177
178
None
178
179
}
179
180
}
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
+ }
180
195
}
181
196
182
197
/// A single device path instance that ends with either an [`END_INSTANCE`]
@@ -579,6 +594,93 @@ impl FilePathMediaDevicePath {
579
594
}
580
595
}
581
596
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
+
582
684
#[ cfg( test) ]
583
685
mod tests {
584
686
use super :: * ;
@@ -716,4 +818,52 @@ mod tests {
716
818
CString16 :: try_from( "test" ) . unwrap( )
717
819
) ;
718
820
}
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
+ }
719
869
}
0 commit comments