mirror of
https://github.com/edera-dev/sprout.git
synced 2026-11-04 19:52:22 +00:00
fix(path): tell device and file path nodes apart by their type
Device path nodes were treated as device nodes when their text
contained "(", and as file path nodes otherwise. A file name with
parentheses, like \EFI\Linux\vmlinuz(1).efi, was then treated as a
device node, so it couldn't be resolved or loaded. Check whether each
node is a media file path node instead.
This commit is contained in:
1 parent
8447861985
commit
079bf0c3e8
1 file changed
+23
-39
+23
-39
@@ -6,7 +6,9 @@ use anyhow::{Context, Result};
|
|||||||
use core::ops::Deref;
|
use core::ops::Deref;
|
||||||
use uefi::fs::{FileSystem, Path};
|
use uefi::fs::{FileSystem, Path};
|
||||||
use uefi::proto::device_path::text::{AllowShortcuts, DevicePathFromText, DisplayOnly};
|
use uefi::proto::device_path::text::{AllowShortcuts, DevicePathFromText, DisplayOnly};
|
||||||
use uefi::proto::device_path::{DevicePath, PoolDevicePath};
|
use uefi::proto::device_path::{
|
||||||
|
DevicePath, DevicePathNode, DeviceSubType, DeviceType, PoolDevicePath,
|
||||||
|
};
|
||||||
use uefi::proto::media::fs::SimpleFileSystem;
|
use uefi::proto::media::fs::SimpleFileSystem;
|
||||||
use uefi::{CString16, Handle};
|
use uefi::{CString16, Handle};
|
||||||
|
|
||||||
@@ -40,10 +42,17 @@ impl ResolvedPath {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Checks if a [CString16] contains a char `c`.
|
/// Checks if the device path `node` is a file path node, rather than a device node.
|
||||||
/// We need to call to_string() because CString16 doesn't support `contains` with a char.
|
fn is_file_path_node(node: &DevicePathNode) -> bool {
|
||||||
fn cstring16_contains_char(string: &CString16, c: char) -> bool {
|
node.device_type() == DeviceType::MEDIA && node.sub_type() == DeviceSubType::MEDIA_FILE_PATH
|
||||||
string.to_string().contains(c)
|
}
|
||||||
|
|
||||||
|
/// Converts the device path `node` to its text form.
|
||||||
|
fn node_to_string(node: &DevicePathNode) -> Result<String> {
|
||||||
|
Ok(node
|
||||||
|
.to_string16(DisplayOnly(false), AllowShortcuts(false))
|
||||||
|
.context("unable to convert device path node to string")?
|
||||||
|
.to_string())
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Parses the input `path` as a [DevicePath].
|
/// Parses the input `path` as a [DevicePath].
|
||||||
@@ -67,20 +76,9 @@ pub fn text_to_device_path(path: impl AsRef<str>) -> Result<PoolDevicePath> {
|
|||||||
pub fn device_path_root(path: &DevicePath) -> Result<String> {
|
pub fn device_path_root(path: &DevicePath) -> Result<String> {
|
||||||
let mut path = path
|
let mut path = path
|
||||||
.node_iter()
|
.node_iter()
|
||||||
.filter_map(|item| {
|
.filter(|node| !is_file_path_node(node))
|
||||||
let item = item.to_string16(DisplayOnly(false), AllowShortcuts(false));
|
.map(node_to_string)
|
||||||
if item
|
.collect::<Result<Vec<_>>>()?
|
||||||
.as_ref()
|
|
||||||
.map(|item| cstring16_contains_char(item, '('))
|
|
||||||
.unwrap_or(false)
|
|
||||||
{
|
|
||||||
Some(item.unwrap_or_default())
|
|
||||||
} else {
|
|
||||||
None
|
|
||||||
}
|
|
||||||
})
|
|
||||||
.map(|item| item.to_string())
|
|
||||||
.collect::<Vec<_>>()
|
|
||||||
.join("/");
|
.join("/");
|
||||||
path.push('/');
|
path.push('/');
|
||||||
Ok(path)
|
Ok(path)
|
||||||
@@ -92,20 +90,9 @@ pub fn device_path_root(path: &DevicePath) -> Result<String> {
|
|||||||
pub fn device_path_subpath(path: &DevicePath) -> Result<String> {
|
pub fn device_path_subpath(path: &DevicePath) -> Result<String> {
|
||||||
let path = path
|
let path = path
|
||||||
.node_iter()
|
.node_iter()
|
||||||
.filter_map(|item| {
|
.filter(|node| is_file_path_node(node))
|
||||||
let item = item.to_string16(DisplayOnly(false), AllowShortcuts(false));
|
.map(node_to_string)
|
||||||
if item
|
.collect::<Result<Vec<_>>>()?
|
||||||
.as_ref()
|
|
||||||
.map(|item| cstring16_contains_char(item, '('))
|
|
||||||
.unwrap_or(false)
|
|
||||||
{
|
|
||||||
None
|
|
||||||
} else {
|
|
||||||
Some(item.unwrap_or_default())
|
|
||||||
}
|
|
||||||
})
|
|
||||||
.map(|item| item.to_string())
|
|
||||||
.collect::<Vec<_>>()
|
|
||||||
.join("\\");
|
.join("\\");
|
||||||
Ok(path)
|
Ok(path)
|
||||||
}
|
}
|
||||||
@@ -120,15 +107,12 @@ pub fn resolve_path(
|
|||||||
let mut input = input.to_string();
|
let mut input = input.to_string();
|
||||||
|
|
||||||
let mut path = text_to_device_path(&input).context("unable to convert text to path")?;
|
let mut path = text_to_device_path(&input).context("unable to convert text to path")?;
|
||||||
|
// A path that starts with a device node has a device, while a path that starts
|
||||||
|
// with a file path node is relative to the default root path.
|
||||||
let path_has_device = path
|
let path_has_device = path
|
||||||
.node_iter()
|
.node_iter()
|
||||||
.next()
|
.next()
|
||||||
.map(|it| {
|
.is_some_and(|node| !is_file_path_node(node));
|
||||||
it.to_string16(DisplayOnly(false), AllowShortcuts(false))
|
|
||||||
.unwrap_or_default()
|
|
||||||
})
|
|
||||||
.map(|it| it.to_string().contains('('))
|
|
||||||
.unwrap_or(false);
|
|
||||||
if !path_has_device {
|
if !path_has_device {
|
||||||
if !input.starts_with('\\') {
|
if !input.starts_with('\\') {
|
||||||
input.insert(0, '\\');
|
input.insert(0, '\\');
|
||||||
|
|||||||
Reference in new issue
Block a user