@@ -305,14 +305,16 @@ impl GPTHeader {
305305 }
306306
307307 /// Generate the CRC32 checksum of the partition entry array.
308- pub fn generate_partition_entry_array_crc32 ( & self , partitions : & [ GPTPartitionEntry ] ) -> u32 {
308+ pub fn generate_partition_entry_array_crc32 (
309+ & self ,
310+ partitions_raw : & [ RawPartitionEntry ] ,
311+ ) -> u32 {
309312 let mut clone = self . clone ( ) ;
310313 clone. partition_entry_array_crc32 = 0 ;
311314 let crc = Crc :: < u32 > :: new ( & CRC_32_ISO_HDLC ) ;
312315 let mut digest = crc. digest ( ) ;
313316 let mut wrote = 0 ;
314- for x in partitions {
315- let data = encode_to_vec ( x, legacy ( ) ) . expect ( "could not serialize" ) ;
317+ for data in partitions_raw {
316318 digest. update ( & data) ;
317319 wrote += data. len ( ) ;
318320 }
@@ -326,7 +328,21 @@ impl GPTHeader {
326328
327329 /// Update the CRC32 checksum of the partition entry array.
328330 pub fn update_partition_entry_array_crc32 ( & mut self , partitions : & [ GPTPartitionEntry ] ) {
329- self . partition_entry_array_crc32 = self . generate_partition_entry_array_crc32 ( partitions) ;
331+ // Dump the partitions into raw bytes.
332+ let mut partitions_raw = Vec :: new ( ) ;
333+ for i in 0usize ..self . number_of_partition_entries as usize {
334+ let mut cur_raw = vec ! [ 0 ; self . size_of_partition_entry as usize ] ;
335+ if let Some ( entry) = partitions. get ( i) {
336+ let data = encode_to_vec ( entry, legacy ( ) ) . expect ( "could not serialize" ) ;
337+ cur_raw. copy_from_slice ( & data) ;
338+ } else {
339+ cur_raw. copy_from_slice ( & vec ! [ 0 ; self . size_of_partition_entry as usize ] ) ;
340+ } ;
341+ partitions_raw. push ( cur_raw) ;
342+ }
343+ // Use raw bytes for checksuming.
344+ self . partition_entry_array_crc32 =
345+ self . generate_partition_entry_array_crc32 ( & partitions_raw) ;
330346 }
331347
332348 /// Updates the header to match the specifications of the seeker given in argument.
@@ -450,6 +466,12 @@ impl Serialize for PartitionName {
450466 }
451467}
452468
469+ /// Raw bytes containing all partition entries for checksuming, to
470+ /// accommodate extreme (but common) situations like improperly zeroed
471+ /// partition names. Tools based on libparted usually exhibit this behavior.
472+ /// Note: using Vec instead of static array; entry size is variable.
473+ type RawPartitionEntry = Vec < u8 > ;
474+
453475/// A GPT partition's entry in the partition array.
454476///
455477/// # Examples
@@ -660,6 +682,7 @@ pub struct GPT {
660682 /// GPT partition header (disk GUID, first/last usable LBA, etc...)
661683 pub header : GPTHeader ,
662684 partitions : Vec < GPTPartitionEntry > ,
685+ partitions_raw : Vec < RawPartitionEntry > ,
663686 /// Partitions alignment (in sectors)
664687 ///
665688 /// This field change the behavior of the methods `get_maximum_partition_size()`,
@@ -699,6 +722,7 @@ impl GPT {
699722 sector_size,
700723 header,
701724 partitions,
725+ partitions_raw : vec ! [ ] ,
702726 align : DEFAULT_ALIGN ,
703727 } )
704728 }
@@ -744,15 +768,22 @@ impl GPT {
744768 } ) ?;
745769
746770 let mut partitions = Vec :: with_capacity ( header. number_of_partition_entries as usize ) ;
771+ let mut partitions_raw = Vec :: new ( ) ;
747772 for i in 0 ..header. number_of_partition_entries {
748773 reader. seek ( SeekFrom :: Start (
749774 header. partition_entry_lba * sector_size
750775 + u64:: from ( i) * u64:: from ( header. size_of_partition_entry ) ,
751776 ) ) ?;
752- partitions. push ( GPTPartitionEntry :: read_from ( & mut reader) ?) ;
777+
778+ let mut raw_entry = vec ! [ 0 ; header. size_of_partition_entry as usize ] ;
779+ // Read to raw buffer
780+ reader. read_exact ( & mut raw_entry. as_mut_slice ( ) ) ?;
781+
782+ partitions. push ( GPTPartitionEntry :: read_from ( & mut raw_entry. as_slice ( ) ) ?) ;
783+ partitions_raw. push ( raw_entry) ;
753784 }
754785
755- let sum = header. generate_partition_entry_array_crc32 ( & partitions ) ;
786+ let sum = header. generate_partition_entry_array_crc32 ( & partitions_raw ) ;
756787 if header. partition_entry_array_crc32 != sum {
757788 return Err ( Error :: InvalidPartitionEntryArrayChecksum (
758789 header. partition_entry_array_crc32 ,
@@ -766,6 +797,7 @@ impl GPT {
766797 sector_size,
767798 header,
768799 partitions,
800+ partitions_raw,
769801 align,
770802 } )
771803 }
@@ -1374,6 +1406,7 @@ mod test {
13741406 let mut unused = 0 ;
13751407 let mut used = 0 ;
13761408 let mut partitions = Vec :: new ( ) ;
1409+ let mut partitions_raw = Vec :: new ( ) ;
13771410 for i in 0 ..gpt. number_of_partition_entries {
13781411 f. seek ( SeekFrom :: Start (
13791412 gpt. partition_entry_lba * ss
@@ -1400,6 +1433,7 @@ mod test {
14001433 assert_eq ! ( data1, data2) ;
14011434
14021435 partitions. push ( partition) ;
1436+ partitions_raw. push ( data2) ;
14031437 }
14041438 assert_eq ! ( unused, 126 ) ;
14051439 assert_eq ! ( used, 2 ) ;
@@ -1413,7 +1447,10 @@ mod test {
14131447 let sum = gpt. partition_entry_array_crc32 ;
14141448 gpt. update_partition_entry_array_crc32 ( & partitions) ;
14151449 assert_eq ! ( gpt. partition_entry_array_crc32, sum) ;
1416- assert_eq ! ( gpt. generate_partition_entry_array_crc32( & partitions) , sum) ;
1450+ assert_eq ! (
1451+ gpt. generate_partition_entry_array_crc32( & partitions_raw) ,
1452+ sum
1453+ ) ;
14171454 assert_ne ! ( gpt. partition_entry_array_crc32, 0 ) ;
14181455 }
14191456
0 commit comments