#[derive(Debug, Clone, Copy, PartialEq, Eq)]
#[cfg_attr(feature = "serde", derive(serde::Serialize))]
pub struct GptType {
pub guid: &'static str,
pub name: &'static str,
}
pub const UNUSED_GUID: &str = "00000000-0000-0000-0000-000000000000";
pub const PARTITION_TYPE_GUIDS: &[GptType] = &[
GptType { guid: UNUSED_GUID, name: "Unused entry" },
GptType { guid: "C12A7328-F81F-11D2-BA4B-00A0C93EC93B", name: "EFI System Partition" },
GptType { guid: "21686148-6449-6E6F-744E-656564454649", name: "BIOS Boot Partition" },
GptType { guid: "024DEE41-33E7-11D3-9D69-0008C781F39F", name: "MBR Partition Scheme" },
GptType { guid: "BC13C2FF-59E6-4262-A352-B275FD6F7172", name: "Extended Boot Loader (XBOOTLDR)" },
GptType { guid: "E3C9E316-0B5C-4DB8-817D-F92DF00215AE", name: "Microsoft Reserved (MSR)" },
GptType { guid: "EBD0A0A2-B9E5-4433-87C0-68B6B72699C7", name: "Microsoft Basic Data" },
GptType { guid: "5808C8AA-7E8F-42E0-85D2-E1E90434CFB3", name: "Windows LDM metadata" },
GptType { guid: "AF9B60A0-1431-4F62-BC68-3311714A69AD", name: "Windows LDM data" },
GptType { guid: "DE94BBA4-06D1-4D40-A16A-BFD50179D6AC", name: "Windows Recovery Environment" },
GptType { guid: "E75CAF8F-F680-4CEE-AFA3-B001E56EFC2D", name: "Storage Spaces" },
GptType { guid: "0FC63DAF-8483-4772-8E79-3D69D8477DE4", name: "Linux filesystem data" },
GptType { guid: "0657FD6D-A4AB-43C4-84E5-0933C84B4F4F", name: "Linux swap" },
GptType { guid: "E6D6D379-F507-44C2-A23C-238F2A3DF928", name: "Linux LVM" },
GptType { guid: "A19D880F-05FC-4D3B-A006-743F0F84911E", name: "Linux RAID" },
GptType { guid: "CA7D7CCB-63ED-4C53-861C-1742536059CC", name: "Linux LUKS" },
GptType { guid: "933AC7E1-2EB4-4F13-B844-0E14E2AEF915", name: "Linux /home" },
GptType { guid: "4F68BCE3-E8CD-4DB1-96E7-FBCAF984B709", name: "Linux root (x86-64)" },
GptType { guid: "8DA63339-0007-60C0-C436-083AC8230908", name: "Linux reserved" },
GptType { guid: "48465300-0000-11AA-AA11-00306543ECAC", name: "Apple HFS+" },
GptType { guid: "7C3457EF-0000-11AA-AA11-00306543ECAC", name: "Apple APFS" },
GptType { guid: "55465300-0000-11AA-AA11-00306543ECAC", name: "Apple UFS" },
GptType { guid: "426F6F74-0000-11AA-AA11-00306543ECAC", name: "Apple Boot (Recovery HD)" },
GptType { guid: "52414944-0000-11AA-AA11-00306543ECAC", name: "Apple RAID" },
GptType { guid: "516E7CB4-6ECF-11D6-8FF8-00022D09712B", name: "FreeBSD data" },
GptType { guid: "83BD6B9D-7F41-11DC-BE0B-001560B84F0F", name: "FreeBSD boot" },
GptType { guid: "516E7CB5-6ECF-11D6-8FF8-00022D09712B", name: "FreeBSD swap" },
GptType { guid: "FE3A2A5D-4F32-41A7-B725-ACCC3285A309", name: "ChromeOS kernel" },
GptType { guid: "3CB8E202-3B7E-47DD-8A3C-7FF2A13CFCEC", name: "ChromeOS root" },
];
pub mod attributes {
pub const REQUIRED: u64 = 1 << 0;
pub const NO_BLOCK_IO: u64 = 1 << 1;
pub const LEGACY_BIOS_BOOTABLE: u64 = 1 << 2;
pub const MS_READ_ONLY: u64 = 1 << 60;
pub const MS_SHADOW_COPY: u64 = 1 << 61;
pub const MS_HIDDEN: u64 = 1 << 62;
pub const MS_NO_DRIVE_LETTER: u64 = 1 << 63;
}
#[must_use]
pub fn attribute_names(attrs: u64) -> Vec<&'static str> {
use attributes as a;
let table: &[(u64, &str)] = &[
(a::REQUIRED, "required"),
(a::NO_BLOCK_IO, "no-block-io"),
(a::LEGACY_BIOS_BOOTABLE, "legacy-bios-bootable"),
(a::MS_READ_ONLY, "read-only"),
(a::MS_SHADOW_COPY, "shadow-copy"),
(a::MS_HIDDEN, "hidden"),
(a::MS_NO_DRIVE_LETTER, "no-automount"),
];
table
.iter()
.filter(|(bit, _)| attrs & bit != 0)
.map(|(_, name)| *name)
.collect()
}
#[must_use]
pub fn type_name(guid: &str) -> Option<&'static str> {
PARTITION_TYPE_GUIDS
.iter()
.find(|t| t.guid.eq_ignore_ascii_case(guid))
.map(|t| t.name)
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn known_guids_resolve() {
assert_eq!(
type_name("C12A7328-F81F-11D2-BA4B-00A0C93EC93B"),
Some("EFI System Partition")
);
assert_eq!(
type_name("0FC63DAF-8483-4772-8E79-3D69D8477DE4"),
Some("Linux filesystem data")
);
assert_eq!(type_name(UNUSED_GUID), Some("Unused entry"));
}
#[test]
fn lookup_is_case_insensitive() {
assert_eq!(
type_name("c12a7328-f81f-11d2-ba4b-00a0c93ec93b"),
Some("EFI System Partition")
);
}
#[test]
fn unknown_guid_is_none() {
assert_eq!(type_name("DEADBEEF-0000-0000-0000-000000000000"), None);
}
#[test]
fn attribute_names_decode_in_bit_order() {
assert!(attribute_names(0).is_empty());
assert_eq!(attribute_names(attributes::REQUIRED), vec!["required"]);
let attrs = attributes::MS_HIDDEN | attributes::MS_NO_DRIVE_LETTER;
assert_eq!(attribute_names(attrs), vec!["hidden", "no-automount"]);
}
#[test]
fn table_guids_are_well_formed() {
for t in PARTITION_TYPE_GUIDS {
assert_eq!(t.guid.len(), 36, "GUID must be 36 chars: {}", t.guid);
assert_eq!(t.guid.matches('-').count(), 4, "GUID needs 4 dashes: {}", t.guid);
assert!(!t.name.is_empty());
}
}
}