springboard/
gpt.rs

1/// Creates a GPT disk from the provided FAT image.
2pub fn create_gpt_disk(fat_image: &Path, out_gpt_path: &Path) -> anyhow::Result<()> {
3   // create new file
4   let mut disk = fs::OpenOptions::new()
5      .create(true)
6      .truncate(true)
7      .read(true)
8      .write(true)
9      .open(out_gpt_path)
10      .with_context(|| format!("failed to create GPT file at `{}`", out_gpt_path.display()))?;
11
12   // set file size
13   let partition_size: u64 = fs::metadata(fat_image)
14      .context("failed to read metadata of fat image")?
15      .len();
16   let disk_size = partition_size + 1024 * 64; // for GPT headers
17   disk.set_len(disk_size)
18      .context("failed to set GPT image file length")?;
19
20   // create a protective MBR at LBA0 so that disk is not considered
21   // unformatted on BIOS systems
22   let mbr = gpt::mbr::ProtectiveMBR::with_lb_size(
23      u32::try_from((disk_size / 512) - 1).unwrap_or(0xFF_FF_FF_FF),
24   );
25   mbr.overwrite_lba0(&mut disk)
26      .context("failed to write protective MBR")?;
27
28   // create new GPT structure
29   let block_size = gpt::disk::LogicalBlockSize::Lb512;
30   let mut gpt = gpt::GptConfig::new()
31      .writable(true)
32      .initialized(false)
33      .logical_block_size(block_size)
34      .create_from_device(Box::new(&mut disk), None)
35      .context("failed to create GPT structure in file")?;
36   gpt.update_partitions(Default::default())
37      .context("failed to update GPT partitions")?;
38
39   // add new EFI system partition and get its byte offset in the file
40   let partition_id = gpt
41      .add_partition("boot", partition_size, gpt::partition_types::EFI, 0, None)
42      .context("failed to add boot EFI partition")?;
43   let partition = gpt
44      .partitions()
45      .get(&partition_id)
46      .context("failed to open boot partition after creation")?;
47   let start_offset = partition
48      .bytes_start(block_size)
49      .context("failed to get start offset of boot partition")?;
50
51   // close the GPT structure and write out changes
52   gpt.write().context("failed to write out GPT changes")?;
53
54   // place the FAT filesystem in the newly created partition
55   disk.seek(io::SeekFrom::Start(start_offset))
56      .context("failed to seek to start offset")?;
57   io::copy(
58      &mut File::open(fat_image).context("failed to open FAT image")?,
59      &mut disk,
60   )
61      .context("failed to copy FAT image to GPT disk")?;
62
63   Ok(())
64}
65
66// IMPORTS //
67
68use {
69   anyhow::Context,
70   std::{
71      fs::{self, File},
72      io::{self, Seek},
73      path::Path,
74   }
75};