Skip to content

Commit 81e9d80

Browse files
committed
Update code to use FileDataSource
1 parent 2af185f commit 81e9d80

File tree

2 files changed

+51
-54
lines changed

2 files changed

+51
-54
lines changed

src/fat.rs

Lines changed: 21 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,21 +1,21 @@
11
use anyhow::Context;
22
use std::{collections::BTreeMap, fs, io, path::Path};
3+
use std::fs::File;
4+
use fatfs::{Dir, FileSystem};
5+
use crate::file_data_source::FileDataSource;
36

47
use crate::KERNEL_FILE_NAME;
58

69
pub fn create_fat_filesystem(
7-
files: BTreeMap<&str, &Path>,
10+
files: BTreeMap<&str, FileDataSource>,
811
out_fat_path: &Path,
912
) -> anyhow::Result<()> {
1013
const MB: u64 = 1024 * 1024;
1114

1215
// calculate needed size
1316
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;
17+
for source in files.values() {
18+
needed_size += source.len()?;
1919
}
2020

2121
// create new filesystem image file at the given path and set its length
@@ -31,7 +31,9 @@ pub fn create_fat_filesystem(
3131

3232
// choose a file system label
3333
let mut label = *b"MY_RUST_OS!";
34-
if let Some(path) = files.get(KERNEL_FILE_NAME) {
34+
35+
// This __should__ always be a file, but maybe not. Should we allow the caller to set the volume label instead?
36+
if let Some(FileDataSource::File(path)) = files.get(KERNEL_FILE_NAME) {
3537
if let Some(name) = path.file_stem() {
3638
let converted = name.to_string_lossy();
3739
let name = converted.as_bytes();
@@ -48,10 +50,14 @@ pub fn create_fat_filesystem(
4850
fatfs::format_volume(&fat_file, format_options).context("Failed to format FAT file")?;
4951
let filesystem = fatfs::FileSystem::new(&fat_file, fatfs::FsOptions::new())
5052
.context("Failed to open FAT file system of UEFI FAT file")?;
51-
53+
let mut root_dir = filesystem.root_dir();
54+
5255
// copy files to file system
53-
let root_dir = filesystem.root_dir();
54-
for (target_path_raw, file_path) in files {
56+
add_files_to_image(&root_dir, files)
57+
}
58+
59+
pub fn add_files_to_image(root_dir: &Dir<&File>, files: BTreeMap<&str, FileDataSource>) -> anyhow::Result<()> {
60+
for (target_path_raw, source) in files {
5561
let target_path = Path::new(target_path_raw);
5662
// create parent directories
5763
let ancestors: Vec<_> = target_path.ancestors().skip(1).collect();
@@ -70,13 +76,11 @@ pub fn create_fat_filesystem(
7076
.create_file(target_path_raw)
7177
.with_context(|| format!("failed to create file at `{}`", target_path.display()))?;
7278
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+
source.copy_to(&mut new_file)
82+
.with_context(|| format!("failed to copy source data `{:?}` to file at `{}`", source, target_path.display()))?;
7983
}
80-
84+
8185
Ok(())
8286
}

src/lib.rs

Lines changed: 30 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -37,14 +37,15 @@ use anyhow::Context;
3737
use tempfile::NamedTempFile;
3838

3939
pub use bootloader_boot_config::BootConfig;
40+
use crate::file_data_source::FileDataSource;
4041

4142
const KERNEL_FILE_NAME: &str = "kernel-x86_64";
4243
const RAMDISK_FILE_NAME: &str = "ramdisk";
4344
const CONFIG_FILE_NAME: &str = "boot.json";
4445

4546
#[derive(Clone)]
4647
struct DiskImageFile {
47-
source: PathBuf,
48+
source: FileDataSource,
4849
destination: String,
4950
}
5051

@@ -69,64 +70,48 @@ impl DiskImageBuilder {
6970

7071
/// Add or replace a kernel to be included in the final image.
7172
pub fn set_kernel(&mut self, path: &Path) -> &mut Self {
72-
self.add_or_replace_file(path, KERNEL_FILE_NAME)
73+
self.add_or_replace_file(FileDataSource::File(path.to_path_buf()), KERNEL_FILE_NAME)
7374
}
7475

7576
/// Add or replace a ramdisk to be included in the final image.
7677
pub fn set_ramdisk(&mut self, path: &Path) -> &mut Self {
77-
self.add_or_replace_file(path, RAMDISK_FILE_NAME)
78+
self.add_or_replace_file(FileDataSource::File(path.to_path_buf()), RAMDISK_FILE_NAME)
7879
}
7980

8081
/// Configures the runtime behavior of the bootloader.
8182
pub fn set_boot_config(&mut self, boot_config: &BootConfig) -> &mut Self {
8283
let json =
8384
serde_json::to_string_pretty(boot_config).expect("failed to serialize BootConfig");
8485
let bytes = json.as_bytes();
85-
self.add_or_replace_file_byte_content(bytes, CONFIG_FILE_NAME)
86+
self.add_or_replace_file(FileDataSource::Data(bytes.to_vec()), CONFIG_FILE_NAME)
8687
}
87-
88-
/// Add or replace a file from a byte array
89-
pub fn add_or_replace_file_byte_content(&mut self, data: &[u8], target: &str) -> &mut Self {
90-
let temp_path = temp_dir();
91-
let file_name = temp_path.join("bytes.tmp");
92-
fs::create_dir_all(temp_path).expect("Failed to create temp directory");
93-
let mut temp_file =
94-
fs::File::create(file_name.clone()).expect("Failed to create temp file");
95-
temp_file
96-
.write_all(data)
97-
.expect("Failed to write data to temp file");
98-
temp_file
99-
.sync_all()
100-
.expect("Failed to flush temp file to disk");
101-
102-
self.add_or_replace_file(&file_name, target)
103-
}
104-
88+
10589
/// Add or replace arbitrary files.
106-
/// NOTE: You can overwrite internal files if you choose, such as EFI/BOOT/BOOTX64.EFI
107-
/// This can be useful in situations where you want to generate an image, but not use the provided bootloader.
108-
pub fn add_or_replace_file(&mut self, path: &Path, target: &str) -> &mut Self {
90+
pub fn add_or_replace_file(&mut self, file_data_source: FileDataSource, target: &str) -> &mut Self {
10991
self.files.insert(
11092
0,
11193
DiskImageFile {
112-
source: path.to_path_buf(),
94+
source: file_data_source,
11395
destination: target.to_string(),
11496
},
11597
);
11698
self
11799
}
118100
fn create_fat_filesystem_image(
119101
&self,
120-
internal_files: BTreeMap<&str, &Path>,
102+
internal_files: BTreeMap<&str, FileDataSource>,
121103
) -> anyhow::Result<NamedTempFile> {
122104
let mut local_map = BTreeMap::new();
123105

124-
for k in internal_files {
125-
local_map.insert(k.0, k.1);
106+
for f in self.files.as_slice() {
107+
local_map.insert(f.destination.as_str(), f.source.clone());
126108
}
127109

128-
for f in self.files.as_slice() {
129-
local_map.insert(&f.destination, f.source.as_path());
110+
111+
for k in internal_files {
112+
if let Some(_) = local_map.insert(k.0, k.1) {
113+
return Err(anyhow::Error::msg(format!("Attempted to overwrite internal file: {}", k.0)));
114+
}
130115
}
131116

132117
let out_file = NamedTempFile::new().context("failed to create temp file")?;
@@ -145,8 +130,8 @@ impl DiskImageBuilder {
145130
let stage_3_path = Path::new(env!("BIOS_STAGE_3_PATH"));
146131
let stage_4_path = Path::new(env!("BIOS_STAGE_4_PATH"));
147132
let mut internal_files = BTreeMap::new();
148-
internal_files.insert(BIOS_STAGE_3, stage_3_path);
149-
internal_files.insert(BIOS_STAGE_4, stage_4_path);
133+
internal_files.insert(BIOS_STAGE_3, FileDataSource::File(stage_3_path.to_path_buf()));
134+
internal_files.insert(BIOS_STAGE_4, FileDataSource::File(stage_4_path.to_path_buf()));
150135

151136
let fat_partition = self
152137
.create_fat_filesystem_image(internal_files)
@@ -171,7 +156,7 @@ impl DiskImageBuilder {
171156
const UEFI_BOOT_FILENAME: &str = "efi/boot/bootx64.efi";
172157
let bootloader_path = Path::new(env!("UEFI_BOOTLOADER_PATH"));
173158
let mut internal_files = BTreeMap::new();
174-
internal_files.insert(UEFI_BOOT_FILENAME, bootloader_path);
159+
internal_files.insert(UEFI_BOOT_FILENAME, FileDataSource::File(bootloader_path.to_path_buf()));
175160
let fat_partition = self
176161
.create_fat_filesystem_image(internal_files)
177162
.context("failed to create FAT partition")?;
@@ -189,11 +174,11 @@ impl DiskImageBuilder {
189174
pub fn create_uefi_tftp_folder(&self, tftp_path: &Path) -> anyhow::Result<()> {
190175
const UEFI_TFTP_BOOT_FILENAME: &str = "bootloader";
191176
let bootloader_path = Path::new(env!("UEFI_BOOTLOADER_PATH"));
192-
std::fs::create_dir_all(tftp_path)
177+
fs::create_dir_all(tftp_path)
193178
.with_context(|| format!("failed to create out dir at {}", tftp_path.display()))?;
194179

195180
let to = tftp_path.join(UEFI_TFTP_BOOT_FILENAME);
196-
std::fs::copy(bootloader_path, &to).with_context(|| {
181+
fs::copy(bootloader_path, &to).with_context(|| {
197182
format!(
198183
"failed to copy bootloader from {} to {}",
199184
bootloader_path.display(),
@@ -203,7 +188,15 @@ impl DiskImageBuilder {
203188

204189
for f in self.files.as_slice() {
205190
let to = tftp_path.join(f.destination.clone());
206-
std::fs::copy(f.source.clone(), to)?;
191+
192+
let mut new_file = fs::OpenOptions::new()
193+
.read(true)
194+
.write(true)
195+
.create(true)
196+
.truncate(true)
197+
.open(to)?;
198+
199+
f.source.copy_to(&mut new_file)?;
207200
}
208201

209202
Ok(())

0 commit comments

Comments
 (0)