Skip to content

Commit da40452

Browse files
Add GPTPartitionEntry::range and GPT::get_partition_byte_range (#76)
The `range` method returns an inclusive range of sectors covered by the partition, and `get_partition_byte_range` returns an inclusive range of bytes covered by a partition. This is useful when directly accessing the partition data.
1 parent 2ef2fac commit da40452

File tree

1 file changed

+94
-1
lines changed

1 file changed

+94
-1
lines changed

src/lib.rs

Lines changed: 94 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -80,7 +80,7 @@ use std::collections::HashSet;
8080
use std::fmt;
8181
use std::io;
8282
use std::io::{Read, Seek, SeekFrom, Write};
83-
use std::ops::{Index, IndexMut};
83+
use std::ops::{Index, IndexMut, RangeInclusive};
8484
use thiserror::Error;
8585

8686
/// Linux specific helpers
@@ -146,9 +146,15 @@ pub enum Error {
146146
/// included.
147147
#[error("invalid partition number: {0}")]
148148
InvalidPartitionNumber(u32),
149+
/// An error that occurs when the user attempts to access information for an unused partition.
150+
#[error("unused partition")]
151+
UnusedPartition,
149152
/// An operation that required to find a partition, was unable to find that partition.
150153
#[error("partition not found")]
151154
PartitionNotFound,
155+
/// An arithmetic operation overflowed.
156+
#[error("an arithmetic operation overflowed")]
157+
Overflow,
152158
}
153159

154160
/// The result of reading, writing or managing a GPT.
@@ -575,6 +581,43 @@ impl GPTPartitionEntry {
575581

576582
Ok(self.ending_lba - self.starting_lba + 1)
577583
}
584+
585+
/// Get the range of sectors covered by a partition.
586+
///
587+
/// # Errors
588+
///
589+
/// This function will return an error if the partition is unused or if
590+
/// `ending_lba` is lesser than the `starting_lba`.
591+
///
592+
/// # Examples
593+
///
594+
/// ```
595+
/// let ss = 512;
596+
/// let data = vec![0; 100 * ss as usize];
597+
/// let mut cur = std::io::Cursor::new(data);
598+
/// let mut gpt = gptman::GPT::new_from(&mut cur, ss as u64, [0xff; 16])
599+
/// .expect("could not create partition table");
600+
/// gpt[1] = gptman::GPTPartitionEntry {
601+
/// partition_type_guid: [0xff; 16],
602+
/// unique_partition_guid: [0xff; 16],
603+
/// starting_lba: 2048,
604+
/// ending_lba: 4096,
605+
/// attribute_bits: 0,
606+
/// partition_name: "A Robot Named Fight!".into(),
607+
/// };
608+
///
609+
/// assert_eq!(gpt[1].range().unwrap(), 2048..=4096);
610+
/// ```
611+
pub fn range(&self) -> Result<RangeInclusive<u64>> {
612+
if self.is_unused() {
613+
return Err(Error::UnusedPartition);
614+
}
615+
if self.ending_lba < self.starting_lba {
616+
return Err(Error::InvalidPartitionBoundaries);
617+
}
618+
619+
Ok(self.starting_lba..=self.ending_lba)
620+
}
578621
}
579622

580623
/// A type representing a GUID partition table including its partitions, the sector size of the
@@ -1076,6 +1119,56 @@ impl GPT {
10761119
.ok_or(Error::NoSpaceLeft)
10771120
}
10781121

1122+
/// Get the range of bytes covered by a partition.
1123+
///
1124+
/// # Errors
1125+
///
1126+
/// This function will return an error if the partition number is invalid, or if
1127+
/// the partition is unused, or if the partition's `ending_lba` is less than its
1128+
/// `starting_lba`.
1129+
///
1130+
/// # Examples
1131+
///
1132+
/// ```
1133+
/// let ss = 512;
1134+
/// let data = vec![0; 100 * ss as usize];
1135+
/// let mut cur = std::io::Cursor::new(data);
1136+
/// let mut gpt = gptman::GPT::new_from(&mut cur, ss as u64, [0xff; 16])
1137+
/// .expect("could not create partition table");
1138+
/// gpt[1] = gptman::GPTPartitionEntry {
1139+
/// partition_type_guid: [0xff; 16],
1140+
/// unique_partition_guid: [0xff; 16],
1141+
/// starting_lba: 2048,
1142+
/// ending_lba: 2048,
1143+
/// attribute_bits: 0,
1144+
/// partition_name: "A Robot Named Fight!".into(),
1145+
/// };
1146+
///
1147+
/// assert_eq!(gpt.get_partition_byte_range(1).unwrap(), 1048576..=1049087);
1148+
/// ```
1149+
pub fn get_partition_byte_range(&self, partition_number: u32) -> Result<RangeInclusive<u64>> {
1150+
if partition_number == 0 || partition_number > self.header.number_of_partition_entries {
1151+
return Err(Error::InvalidPartitionNumber(partition_number));
1152+
}
1153+
let partition = &self[partition_number];
1154+
1155+
let sector_range = partition.range()?;
1156+
1157+
let start_byte = sector_range
1158+
.start()
1159+
.checked_mul(self.sector_size)
1160+
.ok_or(Error::Overflow)?;
1161+
// Sector ranges are inclusive, so to get the position of the end byte we need
1162+
// to add the size of another sector, less one byte because the byte range
1163+
// returned from this function is also inclusive.
1164+
let end_byte = sector_range
1165+
.end()
1166+
.checked_mul(self.sector_size)
1167+
.and_then(|v| v.checked_add(self.sector_size - 1))
1168+
.ok_or(Error::Overflow)?;
1169+
Ok(start_byte..=end_byte)
1170+
}
1171+
10791172
/// Sort the partition entries in the array by the starting LBA.
10801173
pub fn sort(&mut self) {
10811174
self.partitions

0 commit comments

Comments
 (0)