|
| 1 | +#![forbid(unsafe_op_in_unsafe_fn)] |
| 2 | +use crate::ffi::OsStr; |
| 3 | +use crate::io; |
| 4 | +use crate::path::{Path, PathBuf, Prefix}; |
| 5 | +use crate::sys::{helpers, unsupported_err}; |
| 6 | + |
| 7 | +const FORWARD_SLASH: u8 = b'/'; |
| 8 | +const COLON: u8 = b':'; |
| 9 | + |
| 10 | +#[inline] |
| 11 | +pub fn is_sep_byte(b: u8) -> bool { |
| 12 | + b == b'\\' |
| 13 | +} |
| 14 | + |
| 15 | +#[inline] |
| 16 | +pub fn is_verbatim_sep(b: u8) -> bool { |
| 17 | + b == b'\\' |
| 18 | +} |
| 19 | + |
| 20 | +pub fn parse_prefix(_: &OsStr) -> Option<Prefix<'_>> { |
| 21 | + None |
| 22 | +} |
| 23 | + |
| 24 | +pub const MAIN_SEP_STR: &str = "\\"; |
| 25 | +pub const MAIN_SEP: char = '\\'; |
| 26 | + |
| 27 | +/// UEFI paths can be of 4 types: |
| 28 | +/// |
| 29 | +/// 1. Absolute Shell Path: Uses shell mappings (eg: `FS0:`). Does not exist if UEFI shell not present. |
| 30 | +/// It can be identified with `:`. |
| 31 | +/// Eg: FS0:\abc\run.efi |
| 32 | +/// |
| 33 | +/// 2. Absolute Device Path: this is what we want |
| 34 | +/// It can be identified with `/`. |
| 35 | +/// Eg: PciRoot(0x0)/Pci(0x1,0x1)/Ata(Secondary,Slave,0x0)/\abc\run.efi |
| 36 | +/// |
| 37 | +/// 3: Relative root: path relative to the current volume. |
| 38 | +/// It will start with `\`. |
| 39 | +/// Eg: \abc\run.efi |
| 40 | +/// |
| 41 | +/// 4: Relative |
| 42 | +/// Eg: run.efi |
| 43 | +/// |
| 44 | +/// The algorithm is mostly taken from edk2 UEFI shell implementation and is |
| 45 | +/// somewhat simple. Check for the path type in order. |
| 46 | +/// |
| 47 | +/// The volume mapping in Absolute Shell Path (not the rest of the path) can be converted to Device |
| 48 | +/// Path Protocol using `EFI_SHELL->GetDevicePathFromMap`. The rest of the path (Relative root |
| 49 | +/// path), can just be appended to the remaining path. |
| 50 | +/// |
| 51 | +/// For Relative root, we get the current volume (either in Shell Mapping, or Device Path Protocol |
| 52 | +/// form) and join it with the relative root path. We then recurse the function to resolve the Shell |
| 53 | +/// Mapping if present. |
| 54 | +/// |
| 55 | +/// For Relative paths, we use the current working directory to construct |
| 56 | +/// the new path and recurse the function to resolve the Shell mapping if present. |
| 57 | +/// |
| 58 | +/// Finally, at the end, we get the 2nd form, i.e. Absolute Device Path, which can be used in the |
| 59 | +/// normal UEFI APIs such as file, process, etc. |
| 60 | +/// Eg: PciRoot(0x0)/Pci(0x1,0x1)/Ata(Secondary,Slave,0x0)/\abc\run.efi |
| 61 | +pub(crate) fn absolute(path: &Path) -> io::Result<PathBuf> { |
| 62 | + // Absolute Shell Path |
| 63 | + if path.as_os_str().as_encoded_bytes().contains(&COLON) { |
| 64 | + let mut path_components = path.components(); |
| 65 | + // Since path is not empty, it has at least one Component |
| 66 | + let prefix = path_components.next().unwrap(); |
| 67 | + |
| 68 | + let dev_path = helpers::get_device_path_from_map(prefix.as_ref())?; |
| 69 | + let mut dev_path_text = dev_path.to_text().map_err(|_| unsupported_err())?; |
| 70 | + |
| 71 | + // UEFI Shell does not seem to end device path with `/` |
| 72 | + if *dev_path_text.as_encoded_bytes().last().unwrap() != FORWARD_SLASH { |
| 73 | + dev_path_text.push("/"); |
| 74 | + } |
| 75 | + |
| 76 | + let mut ans = PathBuf::from(dev_path_text); |
| 77 | + ans.push(path_components); |
| 78 | + |
| 79 | + return Ok(ans); |
| 80 | + } |
| 81 | + |
| 82 | + // Absolute Device Path |
| 83 | + if path.as_os_str().as_encoded_bytes().contains(&FORWARD_SLASH) { |
| 84 | + return Ok(path.to_path_buf()); |
| 85 | + } |
| 86 | + |
| 87 | + // cur_dir() always returns something |
| 88 | + let cur_dir = crate::env::current_dir().unwrap(); |
| 89 | + let mut path_components = path.components(); |
| 90 | + |
| 91 | + // Relative Root |
| 92 | + if path_components.next().unwrap() == crate::path::Component::RootDir { |
| 93 | + let mut ans = PathBuf::new(); |
| 94 | + ans.push(cur_dir.components().next().unwrap()); |
| 95 | + ans.push(path_components); |
| 96 | + return absolute(&ans); |
| 97 | + } |
| 98 | + |
| 99 | + absolute(&cur_dir.join(path)) |
| 100 | +} |
| 101 | + |
| 102 | +pub(crate) fn is_absolute(path: &Path) -> bool { |
| 103 | + let temp = path.as_os_str().as_encoded_bytes(); |
| 104 | + temp.contains(&COLON) || temp.contains(&FORWARD_SLASH) |
| 105 | +} |
0 commit comments