uefi_run/
image.rs

1use super::*;
2use std::ffi::OsStr;
3use std::fs;
4use std::io::Write;
5use std::path::Path;
6
7/// Default startup script that just runs `run.efi`
8pub const DEFAULT_STARTUP_NSH: &[u8] = include_bytes!("startup.nsh");
9
10/// Handle to a FAT filesystem used as an EFI partition
11pub struct EfiImage {
12    fs: fatfs::FileSystem<fs::File>,
13}
14
15impl EfiImage {
16    /// Create a new image at the given path
17    pub fn new<P: AsRef<Path>>(path: P, size: u64) -> Result<Self> {
18        // Create regular file and truncate it to size.
19        let file = std::fs::OpenOptions::new()
20            .read(true)
21            .write(true)
22            .create_new(true)
23            .open(&path)?;
24        file.set_len(size)?;
25
26        // Create FAT fs and open it
27        fatfs::format_volume(&file, fatfs::FormatVolumeOptions::new())?;
28        let fs = fatfs::FileSystem::new(file, fatfs::FsOptions::new())?;
29
30        Ok(Self { fs })
31    }
32
33    /// Add file to the image
34    fn add_file<P: AsRef<Path>>(&mut self, path: P) -> Result<fatfs::File<'_, fs::File>> {
35        let path = path.as_ref();
36        let file_name = path
37            .file_name()
38            .ok_or_else(|| Error::msg("Invalid path"))?
39            .to_str()
40            .ok_or_else(|| Error::msg("Invalid filename encoding"))?;
41        let mut dir = self.fs.root_dir();
42        if let Some(dir_path) = path.parent() {
43            for dir_path_component in dir_path.iter() {
44                if dir_path_component == OsStr::new(&std::path::MAIN_SEPARATOR.to_string()) {
45                    continue;
46                }
47                let dir_path_component = dir_path_component
48                    .to_str()
49                    .ok_or_else(|| Error::msg("Cannot convert path to string"))?;
50                dir = dir.create_dir(dir_path_component)?;
51            }
52        }
53        let mut file = dir.create_file(file_name)?;
54        file.truncate()?;
55        Ok(file)
56    }
57
58    /// Copy file from host filesystem to the image
59    pub fn copy_host_file<P1: AsRef<Path>, P2: AsRef<Path>>(
60        &mut self,
61        src: P1,
62        dst: P2,
63    ) -> Result<()> {
64        let file_contents = fs::read(src)?;
65        let mut file = self.add_file(dst)?;
66        file.write_all(&file_contents)?;
67        Ok(())
68    }
69
70    /// Write file contents
71    pub fn set_file_contents<P: AsRef<Path>, B: AsRef<[u8]>>(
72        &mut self,
73        path: P,
74        contents: B,
75    ) -> Result<()> {
76        let mut file = self.add_file(path)?;
77        file.write_all(contents.as_ref())?;
78        Ok(())
79    }
80}