use alloc::vec;
use alloc::vec::Vec;
use core::mem::MaybeUninit;
use uefi::boot::{self, OpenProtocolAttributes, OpenProtocolParams};
use uefi::proto::shell::Shell;
use uefi::{CString16, Result, Status, StatusExt};
use uefi_raw::protocol::file_system::FileMode;
use uefi_raw::protocol::shell::ShellProtocol;
use uefi_raw::protocol::shell_params::ShellFileHandle;
fn get_shell_protocol() -> &'static ShellProtocol {
let handle = boot::get_handle_for_protocol::<Shell>().expect("No Shell handles");
let shell = unsafe {
boot::open_protocol::<Shell>(
OpenProtocolParams {
handle,
agent: boot::image_handle(),
controller: None,
},
OpenProtocolAttributes::GetProtocol,
)
.expect("Failed to open Shell protocol")
};
unsafe {
let proto: &ShellProtocol = core::mem::transmute(shell.get().unwrap());
core::mem::forget(shell);
proto
}
}
pub fn shell_read_file(path: &str) -> Option<Vec<u8>> {
let shell = get_shell_protocol();
let c_path = CString16::try_from(path).ok()?;
unsafe {
let mut handle: MaybeUninit<ShellFileHandle> = MaybeUninit::zeroed();
let status = (shell.open_file_by_name)(
c_path.as_ptr().cast(),
handle.as_mut_ptr(),
FileMode::READ.bits(),
);
if status.is_error() {
return None;
}
let file_handle = handle.assume_init();
let mut file_size: u64 = 0;
let status = (shell.get_file_size)(file_handle, &mut file_size);
if status.is_error() {
let _ = (shell.close_file)(file_handle);
return None;
}
let mut buffer: Vec<u8> = vec![0; file_size as usize];
let mut read_size = file_size as usize;
let status = (shell.read_file)(file_handle, &mut read_size, buffer.as_mut_ptr().cast());
let _ = (shell.close_file)(file_handle);
if status.is_error() {
return None;
}
buffer.truncate(read_size);
Some(buffer)
}
}
pub fn shell_write_file(path: &str, data: &[u8]) -> Result {
let shell = get_shell_protocol();
let c_path =
CString16::try_from(path).map_err(|_| uefi::Error::from(Status::INVALID_PARAMETER))?;
unsafe {
let mode = FileMode::READ | FileMode::WRITE | FileMode::CREATE;
let mut handle: MaybeUninit<ShellFileHandle> = MaybeUninit::zeroed();
(shell.open_file_by_name)(c_path.as_ptr().cast(), handle.as_mut_ptr(), mode.bits())
.to_result()?;
let file_handle = handle.assume_init();
let mut write_size = data.len();
let status = (shell.write_file)(file_handle, &mut write_size, data.as_ptr() as *mut _);
let _ = (shell.close_file)(file_handle);
status.to_result()
}
}