use super::{DescriptorTag, EntityIdentifier, TagIdentifier};
use crate::error::Result;
#[repr(C)]
#[derive(Debug, Clone, Copy)]
pub struct PartitionDescriptor {
pub tag: DescriptorTag,
pub vds_number: u32,
pub partition_flags: u16,
pub partition_number: u16,
pub partition_contents: EntityIdentifier,
pub partition_contents_use: [u8; 128],
pub access_type: u32,
pub partition_starting_location: u32,
pub partition_length: u32,
pub implementation_identifier: EntityIdentifier,
pub implementation_use: [u8; 128],
reserved: [u8; 156],
}
unsafe impl bytemuck::Zeroable for PartitionDescriptor {}
unsafe impl bytemuck::Pod for PartitionDescriptor {}
impl PartitionDescriptor {
#[cfg(feature = "alloc")]
pub(crate) fn into_native(mut self) -> Self {
self.tag = DescriptorTag::from_disk_bytes(bytemuck::bytes_of(&self.tag))
.expect("DescriptorTag has its fixed on-disk size");
self.vds_number = self.vds_number.to_le();
self.partition_flags = self.partition_flags.to_le();
self.partition_number = self.partition_number.to_le();
self.access_type = self.access_type.to_le();
self.partition_starting_location = self.partition_starting_location.to_le();
self.partition_length = self.partition_length.to_le();
self
}
pub fn validate(&self, location: u32) -> Result<()> {
self.tag
.validate(TagIdentifier::PartitionDescriptor, location)
}
pub fn contents_type(&self) -> PartitionContents {
if self.partition_contents.is(b"+NSR02") {
PartitionContents::Nsr02
} else if self.partition_contents.is(b"+NSR03") {
PartitionContents::Nsr03
} else if self.partition_contents.is(b"+FDC01") {
PartitionContents::Fdc01
} else if self.partition_contents.is(b"+CD001") {
PartitionContents::Cd001
} else {
PartitionContents::Unknown
}
}
pub fn is_allocated(&self) -> bool {
self.partition_flags & 0x0001 != 0
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum PartitionContents {
Nsr02,
Nsr03,
Fdc01,
Cd001,
Unknown,
}
#[cfg(test)]
mod tests {
use super::*;
static_assertions::const_assert_eq!(size_of::<PartitionDescriptor>(), 512);
fn tag_with_checksum(identifier: TagIdentifier, location: u32) -> DescriptorTag {
let mut tag = DescriptorTag {
tag_identifier: identifier.to_u16(),
descriptor_version: 2,
tag_checksum: 0,
reserved: 0,
tag_serial_number: 0,
descriptor_crc: 0,
descriptor_crc_length: 0,
tag_location: location,
};
let bytes = bytemuck::bytes_of(&tag);
let mut sum: u8 = 0;
for (i, &byte) in bytes.iter().enumerate() {
if i != 4 {
sum = sum.wrapping_add(byte);
}
}
tag.tag_checksum = sum;
tag
}
fn entity_id(id: &[u8]) -> EntityIdentifier {
assert!(
id.len() <= 23,
"EntityIdentifier::identifier is 23 bytes; got {}",
id.len()
);
let mut entity = EntityIdentifier::EMPTY;
entity.identifier[..id.len()].copy_from_slice(id);
entity
}
#[test]
fn partition_descriptor_layout_and_validate() {
let location = 20u32;
let mut desc = PartitionDescriptor {
tag: tag_with_checksum(TagIdentifier::PartitionDescriptor, location),
vds_number: 1,
partition_flags: 0x0001,
partition_number: 0,
partition_contents: entity_id(b"+NSR03"),
partition_contents_use: [0; 128],
access_type: 1,
partition_starting_location: 0,
partition_length: 1000,
implementation_identifier: EntityIdentifier::EMPTY,
implementation_use: [0; 128],
reserved: [0; 156],
};
assert_eq!(core::mem::size_of_val(&desc), 512);
assert!(desc.validate(location).is_ok());
assert!(desc.is_allocated());
assert_eq!(desc.contents_type(), PartitionContents::Nsr03);
desc.tag = tag_with_checksum(TagIdentifier::PrimaryVolumeDescriptor, location);
assert!(desc.validate(location).is_err());
}
}