2025-10-27 19:47:21 -04:00
|
|
|
use crate::utils;
|
2025-11-03 02:04:21 -05:00
|
|
|
use alloc::string::ToString;
|
|
|
|
|
use alloc::{format, vec};
|
2025-10-27 19:47:21 -04:00
|
|
|
use anyhow::{Context, Result};
|
2025-11-02 23:28:31 -05:00
|
|
|
use edera_sprout_config::RootConfiguration;
|
|
|
|
|
use edera_sprout_config::actions::ActionDeclaration;
|
|
|
|
|
use edera_sprout_config::actions::chainload::ChainloadConfiguration;
|
|
|
|
|
use edera_sprout_config::entries::EntryDeclaration;
|
2025-10-27 19:47:21 -04:00
|
|
|
use uefi::CString16;
|
|
|
|
|
use uefi::fs::{FileSystem, Path};
|
|
|
|
|
use uefi::proto::device_path::DevicePath;
|
|
|
|
|
use uefi::proto::device_path::text::{AllowShortcuts, DisplayOnly};
|
|
|
|
|
|
|
|
|
|
/// The name prefix of the Windows chainload action that will be used to boot Windows.
|
|
|
|
|
const WINDOWS_CHAINLOAD_ACTION_PREFIX: &str = "windows-chainload-";
|
|
|
|
|
|
|
|
|
|
/// Windows boot manager path.
|
|
|
|
|
const BOOTMGR_FW_PATH: &str = "\\EFI\\Microsoft\\Boot\\bootmgfw.efi";
|
|
|
|
|
|
|
|
|
|
/// Scan the specified `filesystem` for Windows configurations.
|
|
|
|
|
pub fn scan(
|
|
|
|
|
filesystem: &mut FileSystem,
|
|
|
|
|
root: &DevicePath,
|
|
|
|
|
config: &mut RootConfiguration,
|
|
|
|
|
) -> Result<bool> {
|
|
|
|
|
// Convert the boot manager firmware path to a path.
|
|
|
|
|
let bootmgr_fw_path =
|
|
|
|
|
CString16::try_from(BOOTMGR_FW_PATH).context("unable to convert path to CString16")?;
|
|
|
|
|
let bootmgr_fw_path = Path::new(&bootmgr_fw_path);
|
|
|
|
|
|
|
|
|
|
// Check if the boot manager firmware path exists, if it doesn't, return false.
|
|
|
|
|
if !filesystem
|
|
|
|
|
.try_exists(bootmgr_fw_path)
|
|
|
|
|
.context("unable to check if bootmgr firmware path exists")?
|
|
|
|
|
{
|
|
|
|
|
return Ok(false);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Convert the device path root to a string we can use in the configuration.
|
|
|
|
|
let mut root = root
|
|
|
|
|
.to_string(DisplayOnly(false), AllowShortcuts(false))
|
|
|
|
|
.context("unable to convert device root to string")?
|
|
|
|
|
.to_string();
|
2025-10-27 23:15:14 -04:00
|
|
|
// Add a trailing forward-slash to the root to ensure the device root is completed.
|
2025-10-27 19:47:21 -04:00
|
|
|
root.push('/');
|
|
|
|
|
|
|
|
|
|
// Generate a unique hash of the root path.
|
|
|
|
|
let root_unique_hash = utils::unique_hash(&root);
|
|
|
|
|
|
|
|
|
|
// Generate a unique name for the Windows chainload action.
|
|
|
|
|
let chainload_action_name = format!("{}{}", WINDOWS_CHAINLOAD_ACTION_PREFIX, root_unique_hash,);
|
|
|
|
|
|
|
|
|
|
// Generate an entry name for Windows.
|
2025-10-30 15:31:26 -04:00
|
|
|
let entry_name = format!("auto-windows-{}", root_unique_hash,);
|
2025-10-27 19:47:21 -04:00
|
|
|
|
|
|
|
|
// Create an entry for Windows and insert it into the configuration.
|
|
|
|
|
let entry = EntryDeclaration {
|
|
|
|
|
title: "Boot Windows".to_string(),
|
|
|
|
|
actions: vec![chainload_action_name.clone()],
|
|
|
|
|
values: Default::default(),
|
|
|
|
|
};
|
|
|
|
|
config.entries.insert(entry_name, entry);
|
|
|
|
|
|
|
|
|
|
// Generate a chainload configuration for Windows.
|
|
|
|
|
let chainload = ChainloadConfiguration {
|
|
|
|
|
path: format!("{}{}", root, bootmgr_fw_path),
|
|
|
|
|
options: vec![],
|
|
|
|
|
..Default::default()
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
// Insert the chainload action into the configuration.
|
|
|
|
|
config.actions.insert(
|
|
|
|
|
chainload_action_name,
|
|
|
|
|
ActionDeclaration {
|
|
|
|
|
chainload: Some(chainload),
|
|
|
|
|
..Default::default()
|
|
|
|
|
},
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
// We have a Windows boot entry, so return true to indicate something was found.
|
|
|
|
|
Ok(true)
|
|
|
|
|
}
|