use crate::utils;
use fatfs::{FatType, FileSystem, FormatVolumeOptions, FsOptions};
use std::{
fs::OpenOptions,
io::{self, Seek, Write},
path::Path,
};
pub fn create_fat_image(
fat_img_path: &Path,
loader_path: &Path,
kernel_path: &Path,
) -> io::Result<u32> {
println!("create_fat_image: Starting creation of FAT image.");
if !loader_path.exists() {
return Err(io::Error::new(
io::ErrorKind::NotFound,
format!("Loader file not found at {:?}", loader_path),
));
}
if !kernel_path.exists() {
return Err(io::Error::new(
io::ErrorKind::NotFound,
format!("Kernel file not found at {:?}", kernel_path),
));
}
let loader_size = loader_path.metadata()?.len();
let kernel_size = kernel_path.metadata()?.len();
let content_size = loader_size + kernel_size;
const MIN_FAT_SIZE: u64 = 16 * 1024 * 1024; const FAT_OVERHEAD: u64 = 2 * 1024 * 1024;
let mut total_size = (content_size + FAT_OVERHEAD).max(MIN_FAT_SIZE);
const SECTOR_SIZE: u64 = 512;
total_size = total_size.div_ceil(SECTOR_SIZE) * SECTOR_SIZE;
let fat_type = if total_size < 32 * 1024 * 1024 {
println!("create_fat_image: Formatting volume as FAT16 due to size.");
FatType::Fat16
} else {
println!("create_fat_image: Formatting volume as FAT32 due to size.");
FatType::Fat32
};
let mut file = OpenOptions::new()
.read(true)
.write(true)
.create(true)
.truncate(true)
.open(fat_img_path)?;
file.set_len(total_size)?;
println!(
"create_fat_image: FAT image size set to {} bytes.",
total_size
);
fatfs::format_volume(&mut file, FormatVolumeOptions::new().fat_type(fat_type))?;
file.flush()?; file.seek(io::SeekFrom::Start(0))?;
let fs = FileSystem::new(&mut file, FsOptions::new())?;
let root_dir = fs.root_dir();
let efi_dir = root_dir.create_dir("EFI")?;
let boot_dir = efi_dir.create_dir("BOOT")?;
println!("create_fat_image: Copying bootloader and kernel.");
utils::copy_to_fat(&boot_dir, loader_path, "BOOTX64.EFI")?;
utils::copy_to_fat(&boot_dir, kernel_path, "KERNEL.EFI")?;
println!("create_fat_image: FAT image creation complete.");
u32::try_from(total_size)
.map_err(|_| io::Error::new(io::ErrorKind::InvalidInput, "Image size exceeds 4GB limit"))
}