Skip to content
Merged
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
153 changes: 95 additions & 58 deletions library/std/src/sys/fs/uefi.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ use crate::sys::{helpers, unsupported};

const FILE_PERMISSIONS_MASK: u64 = r_efi::protocols::file::READ_ONLY;

pub struct File(!);
pub struct File(uefi_fs::File);

#[derive(Clone)]
pub struct FileAttr {
Expand Down Expand Up @@ -235,9 +235,11 @@ impl OpenOptions {

pub fn create_new(&mut self, create_new: bool) {
self.create_new = create_new;
if create_new {
self.create(true);
}
}

#[expect(dead_code)]
const fn is_mode_valid(&self) -> bool {
// Valid Combinations: Read, Read/Write, Read/Write/Create
self.mode == file::MODE_READ
Expand All @@ -247,100 +249,125 @@ impl OpenOptions {
}

impl File {
pub fn open(_path: &Path, _opts: &OpenOptions) -> io::Result<File> {
unsupported()
pub fn open(path: &Path, opts: &OpenOptions) -> io::Result<File> {
if !opts.is_mode_valid() {
return Err(io::const_error!(io::ErrorKind::InvalidInput, "Invalid open options"));
}

if opts.create_new && exists(path)? {
return Err(io::const_error!(io::ErrorKind::AlreadyExists, "File already exists"));
}

let f = uefi_fs::File::from_path(path, opts.mode, 0).map(Self)?;

if opts.truncate {
f.truncate(0)?;
}

if opts.append {
f.seek(io::SeekFrom::End(0))?;
}

Ok(f)
}

pub fn file_attr(&self) -> io::Result<FileAttr> {
self.0
self.0.file_info().map(FileAttr::from_uefi)
}

pub fn fsync(&self) -> io::Result<()> {
self.0
unsupported()
}

pub fn datasync(&self) -> io::Result<()> {
self.0
unsupported()
}

pub fn lock(&self) -> io::Result<()> {
self.0
unsupported()
}

pub fn lock_shared(&self) -> io::Result<()> {
self.0
unsupported()
}

pub fn try_lock(&self) -> Result<(), TryLockError> {
self.0
unsupported().map_err(TryLockError::Error)
}

pub fn try_lock_shared(&self) -> Result<(), TryLockError> {
self.0
unsupported().map_err(TryLockError::Error)
}

pub fn unlock(&self) -> io::Result<()> {
self.0
unsupported()
}

pub fn truncate(&self, _size: u64) -> io::Result<()> {
self.0
pub fn truncate(&self, size: u64) -> io::Result<()> {
let mut file_info = self.0.file_info()?;

unsafe { (*file_info.as_mut_ptr()).file_size = size };

self.0.set_file_info(file_info)
}

pub fn read(&self, _buf: &mut [u8]) -> io::Result<usize> {
self.0
unsupported()
}

pub fn read_vectored(&self, _bufs: &mut [IoSliceMut<'_>]) -> io::Result<usize> {
self.0
pub fn read_vectored(&self, bufs: &mut [IoSliceMut<'_>]) -> io::Result<usize> {
crate::io::default_read_vectored(|b| self.read(b), bufs)
}

pub fn is_read_vectored(&self) -> bool {
self.0
false
}

pub fn read_buf(&self, _cursor: BorrowedCursor<'_>) -> io::Result<()> {
self.0
pub fn read_buf(&self, cursor: BorrowedCursor<'_>) -> io::Result<()> {
crate::io::default_read_buf(|buf| self.read(buf), cursor)
}

pub fn write(&self, _buf: &[u8]) -> io::Result<usize> {
self.0
unsupported()
}

pub fn write_vectored(&self, _bufs: &[IoSlice<'_>]) -> io::Result<usize> {
self.0
pub fn write_vectored(&self, bufs: &[IoSlice<'_>]) -> io::Result<usize> {
crate::io::default_write_vectored(|b| self.write(b), bufs)
}

pub fn is_write_vectored(&self) -> bool {
self.0
false
}

pub fn flush(&self) -> io::Result<()> {
self.0
unsupported()
}

pub fn seek(&self, _pos: SeekFrom) -> io::Result<u64> {
self.0
unsupported()
}

pub fn size(&self) -> Option<io::Result<u64>> {
self.0
match self.file_attr() {
Ok(x) => Some(Ok(x.size())),
Err(e) => Some(Err(e)),
}
}

pub fn tell(&self) -> io::Result<u64> {
self.0
unsupported()
}

pub fn duplicate(&self) -> io::Result<File> {
self.0
unsupported()
}

pub fn set_permissions(&self, _perm: FilePermissions) -> io::Result<()> {
self.0
pub fn set_permissions(&self, perm: FilePermissions) -> io::Result<()> {
set_perm_inner(&self.0, perm)
}

pub fn set_times(&self, _times: FileTimes) -> io::Result<()> {
self.0
pub fn set_times(&self, times: FileTimes) -> io::Result<()> {
set_times_inner(&self.0, times)
}
}

Expand All @@ -355,8 +382,10 @@ impl DirBuilder {
}

impl fmt::Debug for File {
fn fmt(&self, _f: &mut fmt::Formatter<'_>) -> fmt::Result {
self.0
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
let mut b = f.debug_struct("File");
b.field("path", &self.0.path());
b.finish()
}
}

Expand Down Expand Up @@ -391,14 +420,7 @@ pub fn rename(_old: &Path, _new: &Path) -> io::Result<()> {

pub fn set_perm(p: &Path, perm: FilePermissions) -> io::Result<()> {
let f = uefi_fs::File::from_path(p, file::MODE_READ | file::MODE_WRITE, 0)?;
let mut file_info = f.file_info()?;

unsafe {
(*file_info.as_mut_ptr()).attribute =
((*file_info.as_ptr()).attribute & !FILE_PERMISSIONS_MASK) | perm.to_attr()
};

f.set_file_info(file_info)
set_perm_inner(&f, perm)
}

pub fn set_times(p: &Path, times: FileTimes) -> io::Result<()> {
Expand All @@ -408,21 +430,7 @@ pub fn set_times(p: &Path, times: FileTimes) -> io::Result<()> {

pub fn set_times_nofollow(p: &Path, times: FileTimes) -> io::Result<()> {
let f = uefi_fs::File::from_path(p, file::MODE_READ | file::MODE_WRITE, 0)?;
let mut file_info = f.file_info()?;

if let Some(x) = times.accessed {
unsafe {
(*file_info.as_mut_ptr()).last_access_time = uefi_fs::systemtime_to_uefi(x);
}
}

if let Some(x) = times.modified {
unsafe {
(*file_info.as_mut_ptr()).modification_time = uefi_fs::systemtime_to_uefi(x);
}
}

f.set_file_info(file_info)
set_times_inner(&f, times)
}

pub fn rmdir(p: &Path) -> io::Result<()> {
Expand Down Expand Up @@ -480,6 +488,35 @@ pub fn copy(_from: &Path, _to: &Path) -> io::Result<u64> {
unsupported()
}

fn set_perm_inner(f: &uefi_fs::File, perm: FilePermissions) -> io::Result<()> {
let mut file_info = f.file_info()?;

unsafe {
(*file_info.as_mut_ptr()).attribute =
((*file_info.as_ptr()).attribute & !FILE_PERMISSIONS_MASK) | perm.to_attr()
};

f.set_file_info(file_info)
}

fn set_times_inner(f: &uefi_fs::File, times: FileTimes) -> io::Result<()> {
let mut file_info = f.file_info()?;

if let Some(x) = times.accessed {
unsafe {
(*file_info.as_mut_ptr()).last_access_time = uefi_fs::systemtime_to_uefi(x);
}
}

if let Some(x) = times.modified {
unsafe {
(*file_info.as_mut_ptr()).modification_time = uefi_fs::systemtime_to_uefi(x);
}
}

f.set_file_info(file_info)
}

mod uefi_fs {
use r_efi::protocols::{device_path, file, simple_file_system};

Expand Down
Loading