| 
1 | 1 | use r_efi::efi::Status;  | 
2 | 2 | use r_efi::efi::protocols::{device_path, loaded_image_device_path};  | 
3 | 3 | 
 
  | 
4 |  | -use super::{RawOsError, helpers, unsupported};  | 
 | 4 | +use super::{RawOsError, helpers, unsupported_err};  | 
5 | 5 | use crate::error::Error as StdError;  | 
6 | 6 | use crate::ffi::{OsStr, OsString};  | 
7 | 7 | use crate::marker::PhantomData;  | 
@@ -125,11 +125,32 @@ pub fn error_string(errno: RawOsError) -> String {  | 
125 | 125 | }  | 
126 | 126 | 
 
  | 
127 | 127 | pub fn getcwd() -> io::Result<PathBuf> {  | 
128 |  | -    unsupported()  | 
 | 128 | +    match uefi_shell::open_shell() {  | 
 | 129 | +        Some(shell) => {  | 
 | 130 | +            // SAFETY: path_ptr is managed by UEFI shell and should not be deallocated  | 
 | 131 | +            let path_ptr = unsafe { ((*shell.as_ptr()).get_cur_dir)(crate::ptr::null_mut()) };  | 
 | 132 | +            helpers::os_string_from_raw(path_ptr)  | 
 | 133 | +                .map(PathBuf::from)  | 
 | 134 | +                .ok_or(io::const_io_error!(io::ErrorKind::InvalidData, "Invalid path"))  | 
 | 135 | +        }  | 
 | 136 | +        None => {  | 
 | 137 | +            let mut t = current_exe()?;  | 
 | 138 | +            // SAFETY: This should never fail since the disk prefix will be present even for root  | 
 | 139 | +            // executables  | 
 | 140 | +            assert!(t.pop());  | 
 | 141 | +            Ok(t)  | 
 | 142 | +        }  | 
 | 143 | +    }  | 
129 | 144 | }  | 
130 | 145 | 
 
  | 
131 |  | -pub fn chdir(_: &path::Path) -> io::Result<()> {  | 
132 |  | -    unsupported()  | 
 | 146 | +pub fn chdir(p: &path::Path) -> io::Result<()> {  | 
 | 147 | +    let shell = uefi_shell::open_shell().ok_or(unsupported_err())?;  | 
 | 148 | + | 
 | 149 | +    let mut p = helpers::os_string_to_raw(p.as_os_str())  | 
 | 150 | +        .ok_or(io::const_io_error!(io::ErrorKind::InvalidData, "Invalid path"))?;  | 
 | 151 | + | 
 | 152 | +    let r = unsafe { ((*shell.as_ptr()).set_cur_dir)(crate::ptr::null_mut(), p.as_mut_ptr()) };  | 
 | 153 | +    if r.is_error() { Err(io::Error::from_raw_os_error(r.as_usize())) } else { Ok(()) }  | 
133 | 154 | }  | 
134 | 155 | 
 
  | 
135 | 156 | pub struct SplitPaths<'a>(!, PhantomData<&'a ()>);  | 
@@ -239,3 +260,37 @@ pub fn exit(code: i32) -> ! {  | 
239 | 260 | pub fn getpid() -> u32 {  | 
240 | 261 |     panic!("no pids on this platform")  | 
241 | 262 | }  | 
 | 263 | + | 
 | 264 | +mod uefi_shell {  | 
 | 265 | +    use r_efi::protocols::shell;  | 
 | 266 | + | 
 | 267 | +    use super::super::helpers;  | 
 | 268 | +    use crate::ptr::NonNull;  | 
 | 269 | +    use crate::sync::atomic::{AtomicPtr, Ordering};  | 
 | 270 | + | 
 | 271 | +    pub fn open_shell() -> Option<NonNull<shell::Protocol>> {  | 
 | 272 | +        static LAST_VALID_HANDLE: AtomicPtr<crate::ffi::c_void> =  | 
 | 273 | +            AtomicPtr::new(crate::ptr::null_mut());  | 
 | 274 | + | 
 | 275 | +        if let Some(handle) = NonNull::new(LAST_VALID_HANDLE.load(Ordering::Acquire)) {  | 
 | 276 | +            if let Ok(protocol) = helpers::open_protocol::<shell::Protocol>(  | 
 | 277 | +                handle,  | 
 | 278 | +                r_efi::protocols::shell::PROTOCOL_GUID,  | 
 | 279 | +            ) {  | 
 | 280 | +                return Some(protocol);  | 
 | 281 | +            }  | 
 | 282 | +        }  | 
 | 283 | + | 
 | 284 | +        let handles = helpers::locate_handles(shell::PROTOCOL_GUID).ok()?;  | 
 | 285 | +        for handle in handles {  | 
 | 286 | +            if let Ok(protocol) =  | 
 | 287 | +                helpers::open_protocol::<shell::Protocol>(handle, shell::PROTOCOL_GUID)  | 
 | 288 | +            {  | 
 | 289 | +                LAST_VALID_HANDLE.store(handle.as_ptr(), Ordering::Release);  | 
 | 290 | +                return Some(protocol);  | 
 | 291 | +            }  | 
 | 292 | +        }  | 
 | 293 | + | 
 | 294 | +        None  | 
 | 295 | +    }  | 
 | 296 | +}  | 
0 commit comments