use std::io::{Read, Seek, SeekFrom};
use disk_core::filesystem::FilesystemError;
pub const HFS_BOOT_SIGNATURE: u16 = 0x4C4B;
pub const HFS_BOOT_REGION_LEN: usize = 1024;
pub fn has_boot_blocks<R: Read + Seek>(
reader: &mut R,
offset: u64,
) -> Result<bool, FilesystemError> {
reader.seek(SeekFrom::Start(offset))?;
let mut sig = [0u8; 2];
reader.read_exact(&mut sig)?;
Ok(u16::from_be_bytes(sig) == HFS_BOOT_SIGNATURE)
}
#[derive(Debug, Clone)]
pub struct DonorBootBlocks {
pub blocks: Box<[u8; HFS_BOOT_REGION_LEN]>,
pub offset: u64,
}
pub fn read_donor_boot_blocks<R: Read + Seek>(
reader: &mut R,
offset: u64,
) -> Result<Box<[u8; HFS_BOOT_REGION_LEN]>, FilesystemError> {
reader.seek(SeekFrom::Start(offset))?;
let mut buf = Box::new([0u8; HFS_BOOT_REGION_LEN]);
reader.read_exact(buf.as_mut_slice())?;
if u16::from_be_bytes([buf[0], buf[1]]) != HFS_BOOT_SIGNATURE {
return Err(FilesystemError::InvalidData(
"donor volume has no HFS boot blocks ('LK' signature absent at sector 0); \
pick a bootable classic-HFS disk to copy them from"
.to_string(),
));
}
Ok(buf)
}
#[cfg(test)]
mod tests {
use super::*;
use crate::hfs::create_blank_hfs;
use std::io::Cursor;
const MIB: u64 = 1024 * 1024;
#[test]
fn blank_volume_has_no_boot_blocks() {
let img = create_blank_hfs(8 * MIB, 4096, "Blank").unwrap();
let mut cur = Cursor::new(img);
assert!(!has_boot_blocks(&mut cur, 0).unwrap());
let err = read_donor_boot_blocks(&mut cur, 0).unwrap_err();
assert!(err.to_string().contains("no HFS boot blocks"));
}
#[test]
fn lk_signature_makes_a_valid_donor() {
let mut img = create_blank_hfs(8 * MIB, 4096, "Booty").unwrap();
img[0] = 0x4C;
img[1] = 0x4B;
img[2] = 0x60; let mut cur = Cursor::new(&mut img);
assert!(has_boot_blocks(&mut cur, 0).unwrap());
let donor = read_donor_boot_blocks(&mut cur, 0).unwrap();
assert_eq!(&donor[0..3], &[0x4C, 0x4B, 0x60]);
assert_eq!(donor.len(), HFS_BOOT_REGION_LEN);
}
}