blob: aae6cb9e0646227e296c3ce11e66b1c243827e5e [file] [log] [blame]
use r_efi::efi::Status;
use r_efi::efi::protocols::{device_path, loaded_image_device_path};
use super::{RawOsError, helpers, unsupported_err};
use crate::ffi::{OsStr, OsString};
use crate::marker::PhantomData;
use crate::os::uefi;
use crate::path::{self, PathBuf};
use crate::ptr::NonNull;
use crate::{fmt, io};
pub fn errno() -> RawOsError {
0
}
pub fn error_string(errno: RawOsError) -> String {
// Keep the List in Alphabetical Order
// The Messages are taken from UEFI Specification Appendix D - Status Codes
#[rustfmt::skip]
let msg = match r_efi::efi::Status::from_usize(errno) {
Status::ABORTED => "The operation was aborted.",
Status::ACCESS_DENIED => "Access was denied.",
Status::ALREADY_STARTED => "The protocol has already been started.",
Status::BAD_BUFFER_SIZE => "The buffer was not the proper size for the request.",
Status::BUFFER_TOO_SMALL => "The buffer is not large enough to hold the requested data. The required buffer size is returned in the appropriate parameter when this error occurs.",
Status::COMPROMISED_DATA => "The security status of the data is unknown or compromised and the data must be updated or replaced to restore a valid security status.",
Status::CONNECTION_FIN => "The receiving operation fails because the communication peer has closed the connection and there is no more data in the receive buffer of the instance.",
Status::CONNECTION_REFUSED => "The receiving or transmission operation fails because this connection is refused.",
Status::CONNECTION_RESET => "The connect fails because the connection is reset either by instance itself or the communication peer.",
Status::CRC_ERROR => "A CRC error was detected.",
Status::DEVICE_ERROR => "The physical device reported an error while attempting the operation.",
Status::END_OF_FILE => "The end of the file was reached.",
Status::END_OF_MEDIA => "Beginning or end of media was reached",
Status::HOST_UNREACHABLE => "The remote host is not reachable.",
Status::HTTP_ERROR => "A HTTP error occurred during the network operation.",
Status::ICMP_ERROR => "An ICMP error occurred during the network operation.",
Status::INCOMPATIBLE_VERSION => "The function encountered an internal version that was incompatible with a version requested by the caller.",
Status::INVALID_LANGUAGE => "The language specified was invalid.",
Status::INVALID_PARAMETER => "A parameter was incorrect.",
Status::IP_ADDRESS_CONFLICT => "There is an address conflict address allocation",
Status::LOAD_ERROR => "The image failed to load.",
Status::MEDIA_CHANGED => "The medium in the device has changed since the last access.",
Status::NETWORK_UNREACHABLE => "The network containing the remote host is not reachable.",
Status::NO_MAPPING => "A mapping to a device does not exist.",
Status::NO_MEDIA => "The device does not contain any medium to perform the operation.",
Status::NO_RESPONSE => "The server was not found or did not respond to the request.",
Status::NOT_FOUND => "The item was not found.",
Status::NOT_READY => "There is no data pending upon return.",
Status::NOT_STARTED => "The protocol has not been started.",
Status::OUT_OF_RESOURCES => "A resource has run out.",
Status::PROTOCOL_ERROR => "A protocol error occurred during the network operation.",
Status::PROTOCOL_UNREACHABLE => "An ICMP protocol unreachable error is received.",
Status::SECURITY_VIOLATION => "The function was not performed due to a security violation.",
Status::TFTP_ERROR => "A TFTP error occurred during the network operation.",
Status::TIMEOUT => "The timeout time expired.",
Status::UNSUPPORTED => "The operation is not supported.",
Status::VOLUME_FULL => "There is no more space on the file system.",
Status::VOLUME_CORRUPTED => "An inconstancy was detected on the file system causing the operating to fail.",
Status::WRITE_PROTECTED => "The device cannot be written to.",
_ => return format!("Status: {errno}"),
};
msg.to_owned()
}
pub fn getcwd() -> io::Result<PathBuf> {
match helpers::open_shell() {
Some(shell) => {
// SAFETY: path_ptr is managed by UEFI shell and should not be deallocated
let path_ptr = unsafe { ((*shell.as_ptr()).get_cur_dir)(crate::ptr::null_mut()) };
helpers::os_string_from_raw(path_ptr)
.map(PathBuf::from)
.ok_or(io::const_error!(io::ErrorKind::InvalidData, "invalid path"))
}
None => {
let mut t = current_exe()?;
// SAFETY: This should never fail since the disk prefix will be present even for root
// executables
assert!(t.pop());
Ok(t)
}
}
}
pub fn chdir(p: &path::Path) -> io::Result<()> {
let shell = helpers::open_shell().ok_or(unsupported_err())?;
let mut p = helpers::os_string_to_raw(p.as_os_str())
.ok_or(io::const_error!(io::ErrorKind::InvalidData, "invalid path"))?;
let r = unsafe { ((*shell.as_ptr()).set_cur_dir)(crate::ptr::null_mut(), p.as_mut_ptr()) };
if r.is_error() { Err(io::Error::from_raw_os_error(r.as_usize())) } else { Ok(()) }
}
pub struct SplitPaths<'a>(!, PhantomData<&'a ()>);
pub fn split_paths(_unparsed: &OsStr) -> SplitPaths<'_> {
panic!("unsupported")
}
impl<'a> Iterator for SplitPaths<'a> {
type Item = PathBuf;
fn next(&mut self) -> Option<PathBuf> {
self.0
}
}
#[derive(Debug)]
pub struct JoinPathsError;
pub fn join_paths<I, T>(_paths: I) -> Result<OsString, JoinPathsError>
where
I: Iterator<Item = T>,
T: AsRef<OsStr>,
{
Err(JoinPathsError)
}
impl fmt::Display for JoinPathsError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
"not supported on this platform yet".fmt(f)
}
}
impl crate::error::Error for JoinPathsError {}
pub fn current_exe() -> io::Result<PathBuf> {
let protocol = helpers::image_handle_protocol::<device_path::Protocol>(
loaded_image_device_path::PROTOCOL_GUID,
)?;
helpers::device_path_to_text(protocol).map(PathBuf::from)
}
pub fn temp_dir() -> PathBuf {
panic!("no filesystem on this platform")
}
pub fn home_dir() -> Option<PathBuf> {
None
}
pub fn exit(code: i32) -> ! {
if let (Some(boot_services), Some(handle)) =
(uefi::env::boot_services(), uefi::env::try_image_handle())
{
let boot_services: NonNull<r_efi::efi::BootServices> = boot_services.cast();
let _ = unsafe {
((*boot_services.as_ptr()).exit)(
handle.as_ptr(),
Status::from_usize(code as usize),
0,
crate::ptr::null_mut(),
)
};
}
crate::intrinsics::abort()
}
pub fn getpid() -> u32 {
panic!("no pids on this platform")
}