diff --git a/library/std/src/sys/fs/uefi.rs b/library/std/src/sys/fs/uefi.rs index 1c65e3e2b1554..41d35c01252a7 100644 --- a/library/std/src/sys/fs/uefi.rs +++ b/library/std/src/sys/fs/uefi.rs @@ -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 { @@ -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 @@ -247,100 +249,125 @@ impl OpenOptions { } impl File { - pub fn open(_path: &Path, _opts: &OpenOptions) -> io::Result { - unsupported() + pub fn open(path: &Path, opts: &OpenOptions) -> io::Result { + 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 { - 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 { - self.0 + unsupported() } - pub fn read_vectored(&self, _bufs: &mut [IoSliceMut<'_>]) -> io::Result { - self.0 + pub fn read_vectored(&self, bufs: &mut [IoSliceMut<'_>]) -> io::Result { + 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 { - self.0 + unsupported() } - pub fn write_vectored(&self, _bufs: &[IoSlice<'_>]) -> io::Result { - self.0 + pub fn write_vectored(&self, bufs: &[IoSlice<'_>]) -> io::Result { + 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 { - self.0 + unsupported() } pub fn size(&self) -> Option> { - self.0 + match self.file_attr() { + Ok(x) => Some(Ok(x.size())), + Err(e) => Some(Err(e)), + } } pub fn tell(&self) -> io::Result { - self.0 + unsupported() } pub fn duplicate(&self) -> io::Result { - 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) } } @@ -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() } } @@ -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<()> { @@ -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<()> { @@ -480,6 +488,35 @@ pub fn copy(_from: &Path, _to: &Path) -> io::Result { 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};