Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 3 additions & 4 deletions library/core/src/cell.rs
Original file line number Diff line number Diff line change
Expand Up @@ -27,10 +27,9 @@
//!
//! ## `Cell<T>`
//!
//! [`Cell<T>`] implements interior mutability by moving values in and out of the cell. That is, an
//! `&mut T` to the inner value can never be obtained, and the value itself cannot be directly
//! obtained without replacing it with something else. Both of these rules ensure that there is
//! never more than one reference pointing to the inner value. This type provides the following
//! [`Cell<T>`] implements interior mutability by moving values in and out of the cell. That is, a
//! `&T` to the inner value can never be obtained, and the value itself cannot be directly
//! obtained without replacing it with something else. This type provides the following
//! methods:
//!
//! - For types that implement [`Copy`], the [`get`](Cell::get) method retrieves the current
Expand Down
2 changes: 1 addition & 1 deletion library/std/src/sys/fs/motor.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ use crate::io::{self, BorrowedCursor, IoSlice, IoSliceMut, SeekFrom};
use crate::os::fd::{AsFd, AsRawFd, BorrowedFd, FromRawFd, IntoRawFd, RawFd};
use crate::path::{Path, PathBuf};
use crate::sys::fd::FileDesc;
pub use crate::sys::fs::common::exists;
pub use crate::sys::fs::common::{Dir, exists};
use crate::sys::time::SystemTime;
use crate::sys::{AsInner, AsInnerMut, FromInner, IntoInner, map_motor_error, unsupported};

Expand Down
48 changes: 39 additions & 9 deletions library/std/src/sys/fs/uefi.rs
Original file line number Diff line number Diff line change
Expand Up @@ -394,8 +394,43 @@ pub fn unlink(p: &Path) -> io::Result<()> {
}
}

pub fn rename(_old: &Path, _new: &Path) -> io::Result<()> {
unsupported()
/// The implementation mirrors `mv` implementation in UEFI shell:
/// https://github.com/tianocore/edk2/blob/66346d5edeac2a00d3cf2f2f3b5f66d423c07b3e/ShellPkg/Library/UefiShellLevel2CommandsLib/Mv.c#L455
///
/// In a nutshell we do the following:
/// 1. Convert both old and new paths to absolute paths.
/// 2. Check that both lie in the same disk.
/// 3. Construct the target path relative to the current disk root.
/// 4. Set this target path as the file_name in the file_info structure.
pub fn rename(old: &Path, new: &Path) -> io::Result<()> {
let old_absolute = crate::path::absolute(old)?;
let new_absolute = crate::path::absolute(new)?;

let mut old_components = old_absolute.components();
let mut new_components = new_absolute.components();

let Some(old_disk) = old_components.next() else {
return Err(io::const_error!(io::ErrorKind::InvalidInput, "Old path is not valid"));
};
let Some(new_disk) = new_components.next() else {
return Err(io::const_error!(io::ErrorKind::InvalidInput, "New path is not valid"));
};

// Ensure that paths are on the same device.
if old_disk != new_disk {
return Err(io::const_error!(io::ErrorKind::CrossesDevices, "Cannot rename across device"));
}

// Construct an path relative the current disk root.
let new_relative =
[crate::path::Component::RootDir].into_iter().chain(new_components).collect::<PathBuf>();

let f = uefi_fs::File::from_path(old, file::MODE_READ | file::MODE_WRITE, 0)?;
let file_info = f.file_info()?;

let new_info = file_info.with_file_name(new_relative.as_os_str())?;

f.set_file_info(new_info)
}

pub fn set_perm(p: &Path, perm: FilePermissions) -> io::Result<()> {
Expand Down Expand Up @@ -760,12 +795,7 @@ mod uefi_fs {
}

pub(crate) fn file_name_from_uefi(info: &UefiBox<file::Info>) -> OsString {
let file_name = {
let size = unsafe { (*info.as_ptr()).size };
let strlen = (size as usize - crate::mem::size_of::<file::Info<0>>() - 1) / 2;
unsafe { crate::slice::from_raw_parts((*info.as_ptr()).file_name.as_ptr(), strlen) }
};

OsString::from_wide(file_name)
let fname = info.file_name();
OsString::from_wide(&fname[..fname.len() - 1])
}
}
59 changes: 57 additions & 2 deletions library/std/src/sys/pal/uefi/helpers.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
//! - More information about protocols can be found [here](https://edk2-docs.gitbook.io/edk-ii-uefi-driver-writer-s-guide/3_foundation/36_protocols_and_handles)

use r_efi::efi::{self, Guid};
use r_efi::protocols::{device_path, device_path_to_text, service_binding, shell};
use r_efi::protocols::{device_path, device_path_to_text, file, service_binding, shell};

use crate::alloc::Layout;
use crate::ffi::{OsStr, OsString};
Expand Down Expand Up @@ -791,7 +791,7 @@ impl<T> UefiBox<T> {

match NonNull::new(ptr.cast()) {
Some(inner) => Ok(Self { inner, size: len }),
None => Err(io::Error::new(io::ErrorKind::OutOfMemory, "Allocation failed")),
None => Err(const_error!(io::ErrorKind::OutOfMemory, "Allocation failed")),
}
}

Expand All @@ -818,3 +818,58 @@ impl<T> Drop for UefiBox<T> {
unsafe { crate::alloc::dealloc(self.inner.as_ptr().cast(), layout) };
}
}

impl UefiBox<file::Info> {
fn size(&self) -> u64 {
unsafe { (*self.as_ptr()).size }
}

fn set_size(&mut self, s: u64) {
unsafe { (*self.as_mut_ptr()).size = s }
}

// Length of string (including NULL), not number of bytes.
fn file_name_len(&self) -> usize {
(self.size() as usize - size_of::<file::Info<0>>()) / size_of::<u16>()
}

pub(crate) fn file_name(&self) -> &[u16] {
unsafe {
crate::slice::from_raw_parts((*self.as_ptr()).file_name.as_ptr(), self.file_name_len())
}
}

fn file_name_mut(&mut self) -> &mut [u16] {
unsafe {
crate::slice::from_raw_parts_mut(
(*self.as_mut_ptr()).file_name.as_mut_ptr(),
self.file_name_len(),
)
}
}

pub(crate) fn with_file_name(mut self, name: &OsStr) -> io::Result<Self> {
// os_string_to_raw returns NULL terminated string. So no need to handle it separately.
let fname = os_string_to_raw(name)
.ok_or(const_error!(io::ErrorKind::OutOfMemory, "Allocation failed"))?;
let new_size = size_of::<file::Info<0>>() + fname.len() * size_of::<u16>();

// Reuse the current structure if the new name can fit in it.
if self.size() >= new_size as u64 {
self.file_name_mut()[..fname.len()].copy_from_slice(&fname);
self.set_size(new_size as u64);

return Ok(self);
}

let mut new_box = UefiBox::new(new_size)?;

unsafe {
crate::ptr::copy_nonoverlapping(self.as_ptr(), new_box.as_mut_ptr(), 1);
}
new_box.set_size(new_size as u64);
new_box.file_name_mut().copy_from_slice(&fname);

Ok(new_box)
}
}
Loading