efivar_fix/boot/parse/
boot_entry.rs1use std::{fmt::Display, io::Read};
4
5use byteorder::{LittleEndian, ReadBytesExt};
6
7use super::FilePathList;
8use crate::{efi::Variable, push::PushVecU8, utils::read_nt_utf16_string, Error, VarReader};
9use std::convert::TryFrom;
10
11bitflags::bitflags! {
12 #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
14 pub struct BootEntryAttributes : u32 {
15 const LOAD_OPTION_ACTIVE = 0x1;
16 const LOAD_OPTION_FORCE_RECONNECT = 0x2;
17 const LOAD_OPTION_HIDDEN = 0x8;
18 const LOAD_OPTION_CATEGORY_APP = 0x100;
19 }
20}
21
22impl Display for BootEntryAttributes {
23 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
24 Display::fmt(&self.0, f)
25 }
26}
27
28#[derive(Debug, PartialEq, Clone)]
29pub struct BootEntry {
30 pub attributes: BootEntryAttributes,
31 pub description: String,
32 pub file_path_list: Option<FilePathList>,
33 pub optional_data: Vec<u8>,
34}
35
36impl BootEntry {
37 pub fn read(manager: &(impl ?Sized + VarReader), variable: &Variable) -> crate::Result<Self> {
38 let (value, _flags) = manager.read(variable)?;
39 Self::parse(value)
40 }
41
42 pub fn parse(value: Vec<u8>) -> crate::Result<Self> {
43 let mut buf = &value[..];
46
47 let attributes = buf
48 .read_u32::<LittleEndian>()
49 .map_err(|_| Error::VarParseError)?;
50
51 let file_path_list_length = buf
52 .read_u16::<LittleEndian>()
53 .map_err(|_| Error::VarParseError)?;
54
55 let description = read_nt_utf16_string(&mut buf).map_err(crate::Error::StringParseError)?;
56
57 let mut file_path_list_buf = vec![0u8; file_path_list_length.into()];
58 buf.read_exact(&mut file_path_list_buf)
59 .map_err(|_| Error::VarParseError)?;
60
61 let file_path_list = FilePathList::parse(&mut &file_path_list_buf[..])?.into();
62
63 Ok(BootEntry {
64 attributes: BootEntryAttributes::from_bits(attributes).ok_or(Error::VarParseError)?,
65 description,
66 file_path_list,
67 optional_data: buf.to_vec(),
68 })
69 }
70
71 pub fn to_bytes(&self) -> Vec<u8> {
72 let mut bytes: Vec<u8> = vec![];
73
74 bytes.push_u32(self.attributes.bits());
76
77 let mut fpl_bytes: Vec<u8> = if let Some(fpl) = &self.file_path_list {
79 fpl.to_bytes()
80 } else {
81 vec![]
82 };
83 bytes.append(
84 &mut u16::try_from(fpl_bytes.len())
85 .expect("length should fit in u16")
86 .to_le_bytes()
87 .to_vec(),
88 );
89
90 let mut desc_bytes = self
92 .description
93 .encode_utf16()
94 .flat_map(|var| var.to_le_bytes())
95 .collect();
96 bytes.append(&mut desc_bytes);
97 bytes.append(&mut vec![0x00, 0x00]);
99
100 bytes.append(&mut fpl_bytes);
102
103 bytes.append(&mut self.optional_data.clone());
105
106 bytes
107 }
108}