xtask\tasks\guest_test\uefi/
gpt_efi_disk.rs1use anyhow::Context;
5use anyhow::Result;
6use fatfs::FileSystem;
7use fatfs::FormatVolumeOptions;
8use fatfs::FsOptions;
9use guid::Guid;
10use std::io::Cursor;
11use std::io::Seek;
12use std::path::Path;
13
14const SECTOR_SIZE: usize = 512;
15const EFI_GUID: Guid = guid::guid!("{c12a7328-f81f-11d2-ba4b-00a0c93ec93b}");
16
17pub fn create_gpt_efi_disk(out_img: &Path, with_files: &[(&Path, &Path)]) -> Result<()> {
18 if out_img.extension().unwrap_or_default() != "img" {
19 return Err(anyhow::anyhow!(
20 "only .img disk images are supported at this time"
21 ));
22 }
23
24 let disk_size = 1024 * 1024 * 32; let num_sectors = disk_size / SECTOR_SIZE;
26
27 let mut disk = vec![0; num_sectors * SECTOR_SIZE];
28
29 let efi_partition_range = {
30 let mut cur = Cursor::new(&mut disk);
31 let mut gpt =
32 gptman::GPT::new_from(&mut cur, SECTOR_SIZE as u64, Guid::new_random().into())?;
33
34 gptman::GPT::write_protective_mbr_into(&mut cur, SECTOR_SIZE as u64)?;
36
37 gpt[1] = gptman::GPTPartitionEntry {
39 partition_type_guid: EFI_GUID.into(),
40 unique_partition_guid: Guid::new_random().into(),
41 starting_lba: gpt.header.first_usable_lba,
42 ending_lba: gpt.header.last_usable_lba,
43 attribute_bits: 0,
44 partition_name: "EFI".into(),
45 };
46 gpt.write_into(&mut cur)?;
47
48 let partition_start_byte = gpt[1].starting_lba as usize * SECTOR_SIZE;
50 let partition_num_bytes = (gpt[1].ending_lba - gpt[1].starting_lba) as usize * SECTOR_SIZE;
51 partition_start_byte..partition_start_byte + partition_num_bytes
52 };
53
54 init_fat(&mut disk[efi_partition_range], with_files).context("initializing FAT partition")?;
55
56 fs_err::write(out_img, &disk)?;
57 log::info!("Wrote test image to: {}", out_img.display());
58
59 Ok(())
60}
61
62fn init_fat(partition: &mut [u8], with_files: &[(&Path, &Path)]) -> Result<()> {
63 let efi_fs = {
64 let mut cursor = Cursor::new(partition);
65 fatfs::format_volume(
66 &mut cursor,
67 FormatVolumeOptions::new()
68 .fat_type(fatfs::FatType::Fat32)
69 .volume_label(*b"hvlite_test"),
70 )?;
71
72 cursor.rewind()?;
73 FileSystem::new(cursor, FsOptions::new().update_accessed_date(false))?
74 };
75
76 let root_dir = efi_fs.root_dir();
77 for (dst_file, src_file) in with_files {
78 let ancestors = dst_file.ancestors().collect::<Vec<_>>();
79 let num_ancestors = ancestors.len();
80
81 for (i, chunk) in ancestors.into_iter().rev().enumerate() {
82 if i == 0 {
84 continue;
85 }
86
87 if i != num_ancestors - 1 {
88 log::info!("creating dir {}", chunk.display());
89 root_dir
90 .create_dir(chunk.to_str().unwrap())
91 .context("creating dir")?;
92 } else {
93 log::info!("creating file {}", chunk.display());
94 let mut file = root_dir
95 .create_file(chunk.to_str().unwrap())
96 .context(format!("creating file {}", chunk.display()))?;
97 std::io::copy(&mut fs_err::File::open(src_file)?, &mut file)?;
98 }
99 }
100 }
101
102 log::info!("{:?}", efi_fs.stats()?);
103
104 Ok(())
105}