use crate::Result;
use crate::block::BlockDevice;
use super::SECTOR_SIZE;
#[derive(Debug, Clone)]
pub struct BootEntry {
pub bootable: bool,
pub media_type: u8,
pub load_segment: u16,
pub system_type: u8,
pub sector_count: u16,
pub load_rba: u32,
pub platform: u8,
}
#[derive(Debug, Clone)]
pub struct BootCatalog {
pub default_entry: BootEntry,
pub additional: Vec<BootEntry>,
pub id_string: String,
}
impl BootCatalog {
pub fn load(dev: &mut dyn BlockDevice, catalog_lba: u32) -> Result<Self> {
let mut buf = vec![0u8; SECTOR_SIZE as usize];
dev.read_at(u64::from(catalog_lba) * u64::from(SECTOR_SIZE), &mut buf)?;
if buf[0] != 0x01 {
return Err(crate::Error::InvalidImage(
"el-torito: validation entry missing header_id 0x01".into(),
));
}
let platform = buf[1];
let id_string = String::from_utf8_lossy(&buf[4..28])
.trim_end_matches(['\0', ' '])
.to_string();
if buf[30] != 0x55 || buf[31] != 0xAA {
return Err(crate::Error::InvalidImage(
"el-torito: validation entry missing 0x55AA terminator".into(),
));
}
let default_entry = decode_entry(&buf[32..64], platform)?;
let mut additional = Vec::new();
let mut cursor = 64usize;
let mut current_platform;
while cursor + 32 <= buf.len() {
let hdr = &buf[cursor..cursor + 32];
match hdr[0] {
0x90 | 0x91 => {
current_platform = hdr[1];
let n_entries = u16::from_le_bytes([hdr[2], hdr[3]]) as usize;
let final_section = hdr[0] == 0x91;
cursor += 32;
for _ in 0..n_entries {
if cursor + 32 > buf.len() {
break;
}
let ent = decode_entry(&buf[cursor..cursor + 32], current_platform).ok();
if let Some(e) = ent {
additional.push(e);
}
cursor += 32;
}
if final_section {
break;
}
}
_ => break, }
}
Ok(Self {
default_entry,
additional,
id_string,
})
}
}
fn decode_entry(buf: &[u8], platform: u8) -> Result<BootEntry> {
if buf.len() < 32 {
return Err(crate::Error::InvalidImage(
"el-torito: short section entry".into(),
));
}
Ok(BootEntry {
bootable: buf[0] == 0x88,
media_type: buf[1],
load_segment: u16::from_le_bytes([buf[2], buf[3]]),
system_type: buf[4],
sector_count: u16::from_le_bytes([buf[6], buf[7]]),
load_rba: u32::from_le_bytes([buf[8], buf[9], buf[10], buf[11]]),
platform,
})
}