Skip to content

Commit 7946754

Browse files
lumagndechesne
authored andcommitted
degpt: add tool to parse gpt tables back to partition.xml
Import a tool to reparse gpt_bothN.bin tables into the partition.xml format. This is useful to restore the partition schema basing on binary files from the fastboot flashing package. Signed-off-by: Dmitry Baryshkov <[email protected]> Signed-off-by: Dmitry Baryshkov <[email protected]>
1 parent c1d6021 commit 7946754

File tree

10 files changed

+393
-0
lines changed

10 files changed

+393
-0
lines changed

.github/workflows/build.yml

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,3 +18,7 @@ jobs:
1818
run: |
1919
make
2020
21+
- name: Run cargo
22+
run: |
23+
cd degpt
24+
cargo build

degpt/.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
/target

degpt/Cargo.lock

Lines changed: 88 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

degpt/Cargo.toml

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
[package]
2+
name = "degpt"
3+
version = "0.1.0"
4+
edition = "2021"
5+
6+
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
7+
8+
[dependencies]
9+
gpt = "3.1"
10+
uuid = "1.8"

degpt/LICENCE

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
MIT License
2+
3+
Copyright (c) 2024 Linaro Ltd.
4+
5+
Permission is hereby granted, free of charge, to any person obtaining a copy
6+
of this software and associated documentation files (the "Software"), to deal
7+
in the Software without restriction, including without limitation the rights
8+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9+
copies of the Software, and to permit persons to whom the Software is
10+
furnished to do so, subject to the following conditions:
11+
12+
The above copyright notice and this permission notice shall be included in all
13+
copies or substantial portions of the Software.
14+
15+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21+
SOFTWARE.
22+
23+
------------------------------------------------------------------------
24+
25+
The GPT implementation is based on the gpt crate:
26+
27+
MIT License
28+
29+
Copyright (c) 2017 Quyzi
30+
31+
Permission is hereby granted, free of charge, to any person obtaining a copy
32+
of this software and associated documentation files (the "Software"), to deal
33+
in the Software without restriction, including without limitation the rights
34+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
35+
copies of the Software, and to permit persons to whom the Software is
36+
furnished to do so, subject to the following conditions:
37+
38+
The above copyright notice and this permission notice shall be included in all
39+
copies or substantial portions of the Software.
40+
41+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
42+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
43+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
44+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
45+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
46+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
47+
SOFTWARE.

degpt/src/lib.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
// SPDX-License-Identifier: MIT
2+
// Copyright (c) 2024 Linaro Ltd.
3+
4+
pub mod mygpt;

degpt/src/main.rs

Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,75 @@
1+
// SPDX-License-Identifier: MIT
2+
// Copyright (c) 2024 Linaro Ltd.
3+
4+
use std::env;
5+
use std::error::Error;
6+
use std::fs;
7+
use std::fs::File;
8+
use std::io::Write;
9+
10+
use degpt::mygpt::*;
11+
12+
fn main() -> Result<(), Box<dyn Error>> {
13+
let mut args = env::args().skip(1);
14+
15+
let mut xml;
16+
if let Some(name) = args.next() {
17+
xml = File::create(name)?;
18+
} else {
19+
return Err(format!(
20+
"usage: {} partition.xml gpt_both*.bin",
21+
env::args().next().unwrap()
22+
)
23+
.into());
24+
}
25+
26+
xml.write_all(
27+
concat!(
28+
"<?xml version=\"1.0\"?>\n",
29+
"<configuration>\n",
30+
" <parser_instructions>\n",
31+
" WRITE_PROTECT_BOUNDARY_IN_KB=0\n",
32+
" SECTOR_SIZE_IN_BYTES = 4096\n",
33+
" GROW_LAST_PARTITION_TO_FILL_DISK=true\n",
34+
" </parser_instructions>\n",
35+
"\n",
36+
)
37+
.as_bytes(),
38+
)?;
39+
40+
for gpt in args {
41+
let bytes = fs::read(&gpt)?;
42+
let hdr = Header::try_from(&bytes[0x1000..0x2000])?;
43+
44+
println!("{gpt}");
45+
println!("{hdr:#}");
46+
47+
xml.write_all(" <physical_partition>\n".as_bytes())?;
48+
for i in 0..hdr.num_parts {
49+
let offset = 0x2000 + i as usize * 0x80;
50+
let part = Partition::try_from(&bytes[offset..offset + 0x80])?;
51+
if part.part_guid.is_nil() {
52+
continue;
53+
}
54+
println!("{part:#}");
55+
let size = (part.last_lba + 1 - part.first_lba) * 4096 / 1024;
56+
let readonly: bool = part.flags & (1 << 60) != 0;
57+
xml.write_all(
58+
format!(
59+
" <partition label=\"{}\" size_in_kb=\"{}\" type=\"{}\" bootable=\"false\" readonly=\"{}\" filename=\"\" />\n",
60+
part.name,
61+
size,
62+
part.part_type_guid.guid.to_string().to_uppercase(),
63+
readonly,
64+
)
65+
.as_bytes(),
66+
)?;
67+
}
68+
69+
xml.write_all(" </physical_partition>\n\n".as_bytes())?;
70+
}
71+
72+
xml.write_all("</configuration>\n".as_bytes())?;
73+
74+
Ok(())
75+
}

degpt/src/mygpt.rs

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
// SPDX-License-Identifier: MIT
2+
// Copyright (c) 2024 Linaro Ltd.
3+
4+
pub mod header;
5+
pub mod partition;
6+
7+
pub use header::Header;
8+
pub use partition::Partition;
9+
pub use partition::Type;

degpt/src/mygpt/header.rs

Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,75 @@
1+
// SPDX-License-Identifier: MIT
2+
// Copyright (c) 2017 Quyzi
3+
// Copyright (c) 2024 Linaro Ltd.
4+
5+
use std::error::Error;
6+
use std::fmt;
7+
use std::io::Cursor;
8+
9+
use gpt::header::parse_uuid;
10+
11+
/// Header describing a GPT disk.
12+
#[derive(Clone, Debug, Eq, PartialEq)]
13+
pub struct Header {
14+
/// GPT header magic signature, hardcoded to "EFI PART".
15+
pub signature: String, // Offset 0. "EFI PART", 45h 46h 49h 20h 50h 41h 52h 54h
16+
/// 00 00 01 00
17+
pub revision: u32, // Offset 8
18+
/// little endian
19+
pub header_size_le: u32, // Offset 12
20+
/// CRC32 of the header with crc32 section zeroed
21+
pub crc32: u32, // Offset 16
22+
/// must be 0
23+
pub reserved: u32, // Offset 20
24+
/// For main header, 1
25+
pub current_lba: u64, // Offset 24
26+
/// LBA for backup header
27+
pub backup_lba: u64, // Offset 32
28+
/// First usable LBA for partitions (primary table last LBA + 1)
29+
pub first_usable: u64, // Offset 40
30+
/// Last usable LBA (secondary partition table first LBA - 1)
31+
pub last_usable: u64, // Offset 48
32+
/// UUID of the disk
33+
pub disk_guid: uuid::Uuid, // Offset 56
34+
/// Starting LBA of partition entries
35+
pub part_start: u64, // Offset 72
36+
/// Number of partition entries
37+
pub num_parts: u32, // Offset 80
38+
/// Size of a partition entry, usually 128
39+
pub part_size: u32, // Offset 84
40+
/// CRC32 of the partition table
41+
pub crc32_parts: u32, // Offset 88
42+
}
43+
44+
impl fmt::Display for Header {
45+
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
46+
write!(
47+
f,
48+
"Disk:\t\t{}\nCRC32:\t\t{}\nTable CRC:\t{}",
49+
self.disk_guid, self.crc32, self.crc32_parts
50+
)
51+
}
52+
}
53+
54+
impl TryFrom<&[u8]> for Header {
55+
type Error = Box<dyn Error>;
56+
57+
fn try_from(buf: &[u8]) -> Result<Self, Self::Error> {
58+
Ok(Header {
59+
signature: String::from_utf8(buf[0..8].into())?,
60+
revision: u32::from_le_bytes(buf[8..12].try_into()?),
61+
header_size_le: u32::from_le_bytes(buf[12..16].try_into()?),
62+
crc32: u32::from_le_bytes(buf[16..20].try_into()?),
63+
reserved: u32::from_le_bytes(buf[20..24].try_into()?),
64+
current_lba: u64::from_le_bytes(buf[24..32].try_into()?),
65+
backup_lba: u64::from_le_bytes(buf[32..40].try_into()?),
66+
first_usable: u64::from_le_bytes(buf[40..48].try_into()?),
67+
last_usable: u64::from_le_bytes(buf[48..56].try_into()?),
68+
disk_guid: parse_uuid(&mut Cursor::new(&buf[56..72]))?,
69+
part_start: u64::from_le_bytes(buf[72..80].try_into()?),
70+
num_parts: u32::from_le_bytes(buf[80..84].try_into()?),
71+
part_size: u32::from_le_bytes(buf[84..88].try_into()?),
72+
crc32_parts: u32::from_le_bytes(buf[88..92].try_into()?),
73+
})
74+
}
75+
}

0 commit comments

Comments
 (0)