2025-10-13 00:55:11 -07:00
|
|
|
use crate::context::SproutContext;
|
|
|
|
|
use crate::utils;
|
|
|
|
|
use anyhow::{Context, Result};
|
|
|
|
|
use serde::{Deserialize, Serialize};
|
|
|
|
|
use std::ops::Deref;
|
|
|
|
|
use std::rc::Rc;
|
|
|
|
|
use uefi::CString16;
|
|
|
|
|
use uefi::fs::{FileSystem, Path};
|
|
|
|
|
use uefi::proto::device_path::DevicePath;
|
|
|
|
|
use uefi::proto::media::file::{File, FileSystemVolumeLabel};
|
|
|
|
|
use uefi::proto::media::fs::SimpleFileSystem;
|
|
|
|
|
|
|
|
|
|
#[derive(Serialize, Deserialize, Default, Clone)]
|
2025-10-13 01:02:51 -07:00
|
|
|
pub struct FilesystemDeviceMatchExtractor {
|
|
|
|
|
#[serde(default, rename = "has-label")]
|
|
|
|
|
pub has_label: Option<String>,
|
|
|
|
|
#[serde(default, rename = "has-item")]
|
|
|
|
|
pub has_item: Option<String>,
|
2025-10-13 00:55:11 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pub fn extract(
|
|
|
|
|
context: Rc<SproutContext>,
|
2025-10-13 01:02:51 -07:00
|
|
|
extractor: &FilesystemDeviceMatchExtractor,
|
2025-10-13 00:55:11 -07:00
|
|
|
) -> Result<String> {
|
|
|
|
|
let handles = uefi::boot::find_handles::<SimpleFileSystem>()
|
|
|
|
|
.context("failed to find filesystem handles")?;
|
|
|
|
|
for handle in handles {
|
|
|
|
|
let mut filesystem = uefi::boot::open_protocol_exclusive::<SimpleFileSystem>(handle)
|
|
|
|
|
.context("failed to open filesystem protocol")?;
|
|
|
|
|
|
2025-10-13 01:02:51 -07:00
|
|
|
if let Some(ref label) = extractor.has_label {
|
2025-10-13 00:55:11 -07:00
|
|
|
let want_label = CString16::try_from(context.stamp(label).as_str())
|
|
|
|
|
.context("failed to convert label to CString16")?;
|
|
|
|
|
let mut root = filesystem
|
|
|
|
|
.open_volume()
|
|
|
|
|
.context("failed to open filesystem volume")?;
|
|
|
|
|
let label = root
|
|
|
|
|
.get_boxed_info::<FileSystemVolumeLabel>()
|
|
|
|
|
.context("failed to get filesystem volume label")?;
|
|
|
|
|
|
|
|
|
|
if label.volume_label() != want_label {
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2025-10-13 01:02:51 -07:00
|
|
|
if let Some(ref item) = extractor.has_item {
|
2025-10-13 00:55:11 -07:00
|
|
|
let want_item = CString16::try_from(context.stamp(item).as_str())
|
|
|
|
|
.context("failed to convert item to CString16")?;
|
|
|
|
|
let mut filesystem = FileSystem::new(filesystem);
|
|
|
|
|
let metadata = filesystem.metadata(Path::new(&want_item));
|
|
|
|
|
|
|
|
|
|
if metadata.is_err() {
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
let metadata = metadata?;
|
|
|
|
|
if !(metadata.is_directory() || metadata.is_regular_file()) {
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
let path = uefi::boot::open_protocol_exclusive::<DevicePath>(handle)
|
|
|
|
|
.context("failed to open filesystem device path")?;
|
|
|
|
|
let path = path.deref();
|
|
|
|
|
return utils::device_path_root(path).context("failed to get device path root");
|
|
|
|
|
}
|
|
|
|
|
Ok(String::new())
|
|
|
|
|
}
|