2025-10-11 14:35:29 -07:00
|
|
|
use anyhow::{Context, Result};
|
2025-10-13 00:55:11 -07:00
|
|
|
use std::ops::Deref;
|
2025-10-01 21:30:43 -07:00
|
|
|
use uefi::fs::{FileSystem, Path};
|
2025-10-02 00:24:19 -07:00
|
|
|
use uefi::proto::device_path::text::{AllowShortcuts, DevicePathFromText, DisplayOnly};
|
|
|
|
|
use uefi::proto::device_path::{DevicePath, PoolDevicePath};
|
2025-10-01 21:30:43 -07:00
|
|
|
use uefi::proto::media::fs::SimpleFileSystem;
|
2025-10-13 00:55:11 -07:00
|
|
|
use uefi::{CString16, Handle};
|
2025-10-01 21:30:43 -07:00
|
|
|
|
2025-10-11 14:11:31 -07:00
|
|
|
pub mod framebuffer;
|
2025-10-12 20:22:24 -07:00
|
|
|
pub mod linux_media_initrd;
|
2025-10-11 14:11:31 -07:00
|
|
|
|
2025-10-11 14:35:29 -07:00
|
|
|
pub fn text_to_device_path(path: &str) -> Result<PoolDevicePath> {
|
|
|
|
|
let path = CString16::try_from(path).context("unable to convert path to CString16")?;
|
2025-10-01 21:30:43 -07:00
|
|
|
let device_path_from_text = uefi::boot::open_protocol_exclusive::<DevicePathFromText>(
|
|
|
|
|
uefi::boot::get_handle_for_protocol::<DevicePathFromText>()
|
2025-10-11 14:35:29 -07:00
|
|
|
.context("no device path from text protocol")?,
|
2025-10-01 21:30:43 -07:00
|
|
|
)
|
2025-10-11 14:35:29 -07:00
|
|
|
.context("unable to open device path from text protocol")?;
|
2025-10-01 21:30:43 -07:00
|
|
|
|
|
|
|
|
device_path_from_text
|
|
|
|
|
.convert_text_to_device_path(&path)
|
2025-10-11 14:35:29 -07:00
|
|
|
.context("unable to convert text to device path")
|
2025-10-01 21:30:43 -07:00
|
|
|
}
|
|
|
|
|
|
2025-10-11 14:35:29 -07:00
|
|
|
pub fn device_path_root(path: &DevicePath) -> Result<String> {
|
2025-10-02 00:24:19 -07:00
|
|
|
let mut path = path
|
|
|
|
|
.node_iter()
|
|
|
|
|
.filter_map(|item| {
|
2025-10-11 14:35:29 -07:00
|
|
|
let item = item.to_string(DisplayOnly(false), AllowShortcuts(false));
|
|
|
|
|
if item
|
|
|
|
|
.as_ref()
|
|
|
|
|
.map(|item| item.to_string().contains("("))
|
|
|
|
|
.unwrap_or(false)
|
|
|
|
|
{
|
|
|
|
|
Some(item.unwrap_or_default())
|
2025-10-02 00:24:19 -07:00
|
|
|
} else {
|
|
|
|
|
None
|
|
|
|
|
}
|
|
|
|
|
})
|
|
|
|
|
.map(|item| item.to_string())
|
|
|
|
|
.collect::<Vec<_>>()
|
|
|
|
|
.join("/");
|
|
|
|
|
path.push('/');
|
2025-10-11 14:35:29 -07:00
|
|
|
Ok(path)
|
2025-10-02 00:24:19 -07:00
|
|
|
}
|
|
|
|
|
|
2025-10-13 00:55:11 -07:00
|
|
|
pub fn device_path_subpath(path: &DevicePath) -> Result<String> {
|
|
|
|
|
let path = path
|
|
|
|
|
.node_iter()
|
|
|
|
|
.filter_map(|item| {
|
|
|
|
|
let item = item.to_string(DisplayOnly(false), AllowShortcuts(false));
|
|
|
|
|
if item
|
|
|
|
|
.as_ref()
|
|
|
|
|
.map(|item| item.to_string().contains("("))
|
|
|
|
|
.unwrap_or(false)
|
|
|
|
|
{
|
|
|
|
|
None
|
|
|
|
|
} else {
|
|
|
|
|
Some(item.unwrap_or_default())
|
|
|
|
|
}
|
|
|
|
|
})
|
|
|
|
|
.map(|item| item.to_string())
|
|
|
|
|
.collect::<Vec<_>>()
|
|
|
|
|
.join("\\");
|
|
|
|
|
Ok(path)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pub struct ResolvedPath {
|
|
|
|
|
pub root_path: Box<DevicePath>,
|
|
|
|
|
pub sub_path: Box<DevicePath>,
|
|
|
|
|
pub full_path: Box<DevicePath>,
|
|
|
|
|
pub filesystem_handle: Handle,
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pub fn resolve_path(default_root_path: &DevicePath, input: &str) -> Result<ResolvedPath> {
|
|
|
|
|
let mut path = text_to_device_path(input).context("failed to convert text to path")?;
|
|
|
|
|
let path_has_device = path
|
|
|
|
|
.node_iter()
|
|
|
|
|
.next()
|
|
|
|
|
.map(|it| {
|
|
|
|
|
it.to_string(DisplayOnly(false), AllowShortcuts(false))
|
|
|
|
|
.unwrap_or_default()
|
|
|
|
|
})
|
|
|
|
|
.map(|it| it.to_string().contains("("))
|
|
|
|
|
.unwrap_or(false);
|
|
|
|
|
if !path_has_device {
|
|
|
|
|
let mut input = input.to_string();
|
|
|
|
|
if !input.starts_with("\\") {
|
|
|
|
|
input.insert(0, '\\');
|
|
|
|
|
}
|
|
|
|
|
input.insert_str(
|
|
|
|
|
0,
|
|
|
|
|
device_path_root(default_root_path)
|
|
|
|
|
.context("failed to get loaded image device root")?
|
|
|
|
|
.as_str(),
|
|
|
|
|
);
|
|
|
|
|
path = text_to_device_path(input.as_str()).context("failed to convert text to path")?;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
let path = path.to_boxed();
|
|
|
|
|
let root = device_path_root(path.as_ref()).context("failed to convert root to path")?;
|
|
|
|
|
let root_path = text_to_device_path(root.as_str())
|
|
|
|
|
.context("failed to convert root to path")?
|
|
|
|
|
.to_boxed();
|
|
|
|
|
let mut root_path = root_path.as_ref();
|
|
|
|
|
let handle = uefi::boot::locate_device_path::<SimpleFileSystem>(&mut root_path)
|
|
|
|
|
.context("failed to locate filesystem device path")?;
|
|
|
|
|
let subpath = device_path_subpath(path.deref()).context("failed to get device subpath")?;
|
|
|
|
|
Ok(ResolvedPath {
|
|
|
|
|
root_path: root_path.to_boxed(),
|
|
|
|
|
sub_path: text_to_device_path(subpath.as_str())?.to_boxed(),
|
|
|
|
|
full_path: path,
|
|
|
|
|
filesystem_handle: handle,
|
|
|
|
|
})
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pub fn read_file_contents(default_root_path: &DevicePath, input: &str) -> Result<Vec<u8>> {
|
|
|
|
|
let resolved = resolve_path(default_root_path, input)?;
|
|
|
|
|
let fs = uefi::boot::open_protocol_exclusive::<SimpleFileSystem>(resolved.filesystem_handle)
|
|
|
|
|
.context("unable to open filesystem protocol")?;
|
2025-10-01 21:30:43 -07:00
|
|
|
let mut fs = FileSystem::new(fs);
|
2025-10-13 00:55:11 -07:00
|
|
|
let path = resolved
|
|
|
|
|
.sub_path
|
|
|
|
|
.to_string(DisplayOnly(false), AllowShortcuts(false))?;
|
2025-10-01 21:30:43 -07:00
|
|
|
let content = fs.read(Path::new(&path));
|
2025-10-11 14:35:29 -07:00
|
|
|
content.context("unable to read file contents")
|
2025-10-01 21:30:43 -07:00
|
|
|
}
|