refactor(file): replace fdisk with gptman+mbrman#154
Open
HarryWaschkeit wants to merge 1 commit intoomnect:mainfrom
Open
refactor(file): replace fdisk with gptman+mbrman#154HarryWaschkeit wants to merge 1 commit intoomnect:mainfrom
HarryWaschkeit wants to merge 1 commit intoomnect:mainfrom
Conversation
Replace fragile fdisk-based partition detection with Rust-native crates: - add gptman (GPT with CRC32 validation) and mbrman (MBR including logical partitions) as dependencies - add src/file/partition.rs: get_partition_data() and is_gpt() - remove locale-sensitive fdisk shell invocation and regex parsing - mbrman iter() correctly reaches logical partitions 5 and 6 - fix pre-existing bug: PartitionInfo.end (last sector) was used as dd count= instead of sector count; rename field to count with correct semantics (ending_lba - starting_lba + 1 for GPT, p.sectors for MBR) - remove fdisk from package.metadata.deb depends - change PartitionInfo fields from String to typed u32/u64 Signed-off-by: Harry Waschkeit <44188360+HarryWaschkeit@users.noreply.github.com>
Author
There was a problem hiding this comment.
Pull request overview
Refactors image partition detection away from shelling out to fdisk and instead uses Rust-native parsing via gptman (GPT) and mbrman (MBR), while also correcting partition sector-count semantics for the dd operations.
Changes:
- Introduces
src/file/partition.rsto read GPT/MBR partition start/count directly from the image. - Updates
get_partition_info()andddinvocation to use typedu32/u64fields and correctcountsemantics. - Adds
gptman/mbrmandependencies and removesfdiskfrom Debian runtime dependencies.
Reviewed changes
Copilot reviewed 4 out of 5 changed files in this pull request and generated 5 comments.
Show a summary per file
| File | Description |
|---|---|
src/file/partition.rs |
New partition table parsing utilities using gptman/mbrman. |
src/file/mod.rs |
Wires in the new partition module. |
src/file/functions.rs |
Replaces fdisk+regex partition discovery with Rust-native parsing; fixes dd count= usage. |
Cargo.toml |
Adds gptman/mbrman; removes fdisk from cargo-deb depends. |
Cargo.lock |
Lockfile updates for the newly introduced crates and their transitive deps. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
Comment on lines
+22
to
+25
| return Ok(PartitionData { | ||
| num: partition_num, | ||
| start: entry.starting_lba, | ||
| count: entry.ending_lba - entry.starting_lba + 1, |
| pub fn is_gpt<P: AsRef<Path>>(path: P) -> Result<bool> { | ||
| let mut file = File::open(path.as_ref()) | ||
| .context("is_gpt: failed to open image")?; | ||
| Ok(gptman::GPT::find_from(&mut file).is_ok()) |
Comment on lines
382
to
403
| fn get_partition_info(image_file: &str, partition: &Partition) -> Result<PartitionInfo> { | ||
| let mut fdisk = Command::new("fdisk"); | ||
| fdisk | ||
| .arg("-l") | ||
| .arg("-o") | ||
| .arg("Device,Start,End") | ||
| .arg(image_file); | ||
| let fdisk_out = exec_cmd_with_output!(fdisk); | ||
| use crate::file::partition::{get_partition_data, is_gpt}; | ||
|
|
||
| let gpt = is_gpt(image_file) | ||
| .context("get_partition_info: failed to detect partition table type")?; | ||
|
|
||
| let partition_num = match partition { | ||
| let partition_num: u32 = match partition { | ||
| Partition::boot => 1, | ||
| Partition::rootA => 2, | ||
| p @ (Partition::factory | Partition::cert) => { | ||
| let re = Regex::new(r"Disklabel type: (\D{3})").unwrap(); | ||
|
|
||
| let matches = re | ||
| .captures(&fdisk_out) | ||
| .context("get_partition_info: regex no matches found")?; | ||
| anyhow::ensure!( | ||
| matches.len() == 2, | ||
| "'get_partition_info: regex contains unexpected number of matches" | ||
| ); | ||
|
|
||
| let partition_type = &matches[1]; | ||
|
|
||
| debug!("partition type: {partition_type}"); | ||
|
|
||
| match (p, partition_type) { | ||
| (Partition::factory, "gpt") => 4, | ||
| (Partition::factory, "dos") => 5, | ||
| (Partition::cert, "gpt") => 5, | ||
| (Partition::cert, "dos") => 6, | ||
| _ => anyhow::bail!("get_partition_info: unhandled partition type"), | ||
| } | ||
| Partition::factory => { | ||
| if gpt { 4 } else { 5 } | ||
| } | ||
| Partition::cert => { | ||
| if gpt { 5 } else { 6 } | ||
| } | ||
| }; | ||
|
|
||
| let re = Regex::new(format!(r"{image_file}{partition_num}\s+(\d+)\s+(\d+)").as_str()) | ||
| .context("get_partition_info: failed to create regex")?; | ||
|
|
||
| let matches = re | ||
| .captures(&fdisk_out) | ||
| .context("get_partition_info: regex no matches found")?; | ||
| anyhow::ensure!( | ||
| matches.len() == 3, | ||
| "'get_partition_info: regex contains unexpected number of matches" | ||
| ); | ||
| debug!("get_partition_info: partition={partition}, num={partition_num}, gpt={gpt}"); | ||
|
|
||
| let partition_offset = (matches[1].to_string(), matches[2].to_string()); | ||
| let data = get_partition_data(image_file, partition_num) | ||
| .with_context(|| format!("get_partition_info: failed to read partition {partition_num}"))?; | ||
|
|
Comment on lines
+18
to
+20
| // Try GPT first (validates CRC32 — more robust than signature check) | ||
| if let Ok(gpt) = gptman::GPT::find_from(&mut file) { | ||
| let entry = &gpt[partition_num]; |
|
|
||
| // Try GPT first (validates CRC32 — more robust than signature check) | ||
| if let Ok(gpt) = gptman::GPT::find_from(&mut file) { | ||
| let entry = &gpt[partition_num]; |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Replace the fragile
fdisk-based partition detection inget_partition_info()with Rust-nativegptmanandmbrmancrates.Changes:
gptman(GPT with CRC32 validation) andmbrman(MBR including logical partitions) as dependenciessrc/file/partition.rswithget_partition_data()andis_gpt()fdiskshell invocation and regex parsingfdiskfrompackage.metadata.debdependsPartitionInfofields fromStringto typedu32/u64Reason
The previous implementation spawned
fdisk -land parsed its text output with regex — making it locale-sensitive, version-dependent, and requiringfdiskas a runtime system dependency.Additionally, a pre-existing bug was fixed:
PartitionInfo.endheld the last sector (inclusive) fromfdiskoutput and was passed directly asdd count=, butcountexpects the number of sectors. For a partition starting at sector 2048 and ending at 206847, this causedddto copy 206847 sectors instead of the correct 204800.Fixed semantics:
count = ending_lba - starting_lba + 1count = p.sectors(already the sector count)Verification
cargo checkpassescargo fmt -- --checkpassescargo clippy -- -D warningspasses