Skip to content

Commit d8b50dc

Browse files
committed
Refactor FAT creation function to take arbitrary file list
1 parent 01fdcbc commit d8b50dc

File tree

2 files changed

+92
-66
lines changed

2 files changed

+92
-66
lines changed

src/fat.rs

Lines changed: 82 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,82 @@
1+
use anyhow::Context;
2+
use std::{collections::BTreeMap, fs, io, path::Path};
3+
4+
use crate::KERNEL_FILE_NAME;
5+
6+
pub fn create_fat_filesystem(
7+
files: BTreeMap<&str, &Path>,
8+
out_fat_path: &Path,
9+
) -> anyhow::Result<()> {
10+
const MB: u64 = 1024 * 1024;
11+
12+
// calculate needed size
13+
let mut needed_size = 0;
14+
for path in files.values() {
15+
let file_size = fs::metadata(path)
16+
.with_context(|| format!("failed to read metadata of file `{}`", path.display()))?
17+
.len();
18+
needed_size += file_size;
19+
}
20+
21+
// create new filesystem image file at the given path and set its length
22+
let fat_file = fs::OpenOptions::new()
23+
.read(true)
24+
.write(true)
25+
.create(true)
26+
.truncate(true)
27+
.open(&out_fat_path)
28+
.unwrap();
29+
let fat_size_padded_and_rounded = ((needed_size + 1024 * 64 - 1) / MB + 1) * MB;
30+
fat_file.set_len(fat_size_padded_and_rounded).unwrap();
31+
32+
// choose a file system label
33+
let mut label = *b"MY_RUST_OS!";
34+
if let Some(path) = files.get(KERNEL_FILE_NAME) {
35+
if let Some(name) = path.file_stem() {
36+
let converted = name.to_string_lossy();
37+
let name = converted.as_bytes();
38+
let mut new_label = [0u8; 11];
39+
let name = &name[..new_label.len()];
40+
let slice = &mut new_label[..name.len()];
41+
slice.copy_from_slice(name);
42+
label = new_label;
43+
}
44+
}
45+
46+
// format the file system and open it
47+
let format_options = fatfs::FormatVolumeOptions::new().volume_label(label);
48+
fatfs::format_volume(&fat_file, format_options).context("Failed to format UEFI FAT file")?;
49+
let filesystem = fatfs::FileSystem::new(&fat_file, fatfs::FsOptions::new())
50+
.context("Failed to open FAT file system of UEFI FAT file")?;
51+
52+
// copy files to file system
53+
let root_dir = filesystem.root_dir();
54+
for (target_path_raw, file_path) in files {
55+
let target_path = Path::new(target_path_raw);
56+
// create parent directories
57+
let ancestors: Vec<_> = target_path.ancestors().skip(1).collect();
58+
for ancestor in ancestors.into_iter().rev().skip(1) {
59+
root_dir
60+
.create_dir(&ancestor.display().to_string())
61+
.with_context(|| {
62+
format!(
63+
"failed to create directory `{}` on FAT filesystem",
64+
ancestor.display()
65+
)
66+
})?;
67+
}
68+
69+
let mut new_file = root_dir
70+
.create_file(target_path_raw)
71+
.with_context(|| format!("failed to create file at `{}`", target_path.display()))?;
72+
new_file.truncate().unwrap();
73+
io::copy(
74+
&mut fs::File::open(file_path)
75+
.with_context(|| format!("failed to open `{}` for copying", file_path.display()))?,
76+
&mut new_file,
77+
)
78+
.with_context(|| format!("failed to copy `{}` to FAT filesystem", file_path.display()))?;
79+
}
80+
81+
Ok(())
82+
}

src/lib.rs

Lines changed: 10 additions & 66 deletions
Original file line numberDiff line numberDiff line change
@@ -69,90 +69,34 @@ for all possible configuration options.
6969

7070
use anyhow::Context;
7171
use std::{
72+
collections::BTreeMap,
7273
fs::{self, File},
7374
io::{self, Seek},
7475
path::Path,
7576
};
7677

78+
mod fat;
79+
80+
const KERNEL_FILE_NAME: &str = "kernel-x86_64";
81+
7782
pub fn create_uefi_disk_image(
7883
kernel_binary: &Path,
7984
out_fat_path: &Path,
8085
out_gpt_path: &Path,
8186
) -> anyhow::Result<()> {
8287
let bootloader_path = Path::new(env!("UEFI_BOOTLOADER_PATH"));
8388

84-
create_fat_filesystem(bootloader_path, kernel_binary, &out_fat_path)
89+
let mut files = BTreeMap::new();
90+
files.insert("efi/boot/bootx64.efi", bootloader_path);
91+
files.insert(KERNEL_FILE_NAME, kernel_binary);
92+
93+
fat::create_fat_filesystem(files, &out_fat_path)
8594
.context("failed to create UEFI FAT filesystem")?;
8695
create_gpt_disk(out_fat_path, out_gpt_path);
8796

8897
Ok(())
8998
}
9099

91-
fn create_fat_filesystem(
92-
bootloader_efi_file: &Path,
93-
kernel_binary: &Path,
94-
out_fat_path: &Path,
95-
) -> anyhow::Result<()> {
96-
const MB: u64 = 1024 * 1024;
97-
98-
// retrieve size of `.efi` file and round it up
99-
let efi_size = fs::metadata(&bootloader_efi_file).unwrap().len();
100-
let kernel_size = fs::metadata(&kernel_binary)
101-
.context("failed to read metadata of kernel binary")?
102-
.len();
103-
104-
// create new filesystem image file at the given path and set its length
105-
let fat_file = fs::OpenOptions::new()
106-
.read(true)
107-
.write(true)
108-
.create(true)
109-
.truncate(true)
110-
.open(&out_fat_path)
111-
.unwrap();
112-
let fat_size = efi_size + kernel_size;
113-
let fat_size_padded_and_rounded = ((fat_size + 1024 * 64 - 1) / MB + 1) * MB;
114-
fat_file.set_len(fat_size_padded_and_rounded).unwrap();
115-
116-
// create new FAT file system and open it
117-
let label = {
118-
if let Some(name) = bootloader_efi_file.file_stem() {
119-
let converted = name.to_string_lossy();
120-
let name = converted.as_bytes();
121-
let mut label = [0u8; 11];
122-
let name = &name[..label.len()];
123-
let slice = &mut label[..name.len()];
124-
slice.copy_from_slice(name);
125-
label
126-
} else {
127-
*b"MY_RUST_OS!"
128-
}
129-
};
130-
let format_options = fatfs::FormatVolumeOptions::new().volume_label(label);
131-
fatfs::format_volume(&fat_file, format_options).context("Failed to format UEFI FAT file")?;
132-
let filesystem = fatfs::FileSystem::new(&fat_file, fatfs::FsOptions::new())
133-
.context("Failed to open FAT file system of UEFI FAT file")?;
134-
135-
// copy EFI file to FAT filesystem
136-
let root_dir = filesystem.root_dir();
137-
root_dir.create_dir("efi").unwrap();
138-
root_dir.create_dir("efi/boot").unwrap();
139-
let mut bootx64 = root_dir.create_file("efi/boot/bootx64.efi").unwrap();
140-
bootx64.truncate().unwrap();
141-
io::copy(
142-
&mut fs::File::open(&bootloader_efi_file).unwrap(),
143-
&mut bootx64,
144-
)
145-
.unwrap();
146-
147-
// copy kernel to FAT filesystem
148-
let mut kernel_file = root_dir.create_file("kernel-x86_64")?;
149-
kernel_file.truncate()?;
150-
io::copy(&mut fs::File::open(&kernel_binary)?, &mut kernel_file)
151-
.context("failed to copy kernel to UEFI FAT filesystem")?;
152-
153-
Ok(())
154-
}
155-
156100
fn create_gpt_disk(fat_image: &Path, out_gpt_path: &Path) {
157101
// create new file
158102
let mut disk = fs::OpenOptions::new()

0 commit comments

Comments
 (0)