From 1869f1a9033a5c10c00b4cd8a7a7f08b44542246 Mon Sep 17 00:00:00 2001 From: Mahdi Ali-Raihan Date: Thu, 30 Jul 2026 14:18:49 -0400 Subject: [PATCH] Implemented different with_native_path conversion methods, refactoring fs functions to utilize with_native_path, and move exists to use with_native_path --- library/std/src/sys/fs/common.rs | 8 -- library/std/src/sys/fs/hermit.rs | 60 ++++++------ library/std/src/sys/fs/mod.rs | 17 +--- library/std/src/sys/fs/motor.rs | 43 ++++----- library/std/src/sys/fs/solid.rs | 91 ++++++++----------- library/std/src/sys/fs/uefi.rs | 25 +++-- library/std/src/sys/fs/unix.rs | 9 +- library/std/src/sys/fs/vexos.rs | 85 ++++++++++++----- library/std/src/sys/path/mod.rs | 22 ++++- library/std/src/sys/path/motor.rs | 8 ++ library/std/src/sys/path/solid.rs | 53 +++++++++++ library/std/src/sys/path/uefi.rs | 6 ++ .../src/sys/path/{unix.rs => unix_like.rs} | 0 library/std/src/sys/path/unsupported.rs | 7 ++ .../std/src/sys/path/unsupported_backslash.rs | 26 ------ 15 files changed, 264 insertions(+), 196 deletions(-) create mode 100644 library/std/src/sys/path/motor.rs create mode 100644 library/std/src/sys/path/solid.rs rename library/std/src/sys/path/{unix.rs => unix_like.rs} (100%) create mode 100644 library/std/src/sys/path/unsupported.rs delete mode 100644 library/std/src/sys/path/unsupported_backslash.rs diff --git a/library/std/src/sys/fs/common.rs b/library/std/src/sys/fs/common.rs index 17b98a4506544..b186f11055f1a 100644 --- a/library/std/src/sys/fs/common.rs +++ b/library/std/src/sys/fs/common.rs @@ -54,14 +54,6 @@ fn remove_dir_all_recursive(path: &Path) -> io::Result<()> { ignore_notfound(fs::remove_dir(path)) } -pub fn exists(path: &Path) -> io::Result { - match fs::metadata(path) { - Ok(_) => Ok(true), - Err(error) if error.kind() == io::ErrorKind::NotFound => Ok(false), - Err(error) => Err(error), - } -} - pub struct Dir { path: PathBuf, } diff --git a/library/std/src/sys/fs/hermit.rs b/library/std/src/sys/fs/hermit.rs index 33feee4fc1c97..2beb07b4edb7d 100644 --- a/library/std/src/sys/fs/hermit.rs +++ b/library/std/src/sys/fs/hermit.rs @@ -11,7 +11,7 @@ use crate::os::hermit::io::{AsFd, AsRawFd, BorrowedFd, FromRawFd, IntoRawFd, Raw use crate::path::{Path, PathBuf}; use crate::sync::Arc; use crate::sys::fd::FileDesc; -pub use crate::sys::fs::common::{Dir, copy, exists}; +pub use crate::sys::fs::common::{Dir, copy}; use crate::sys::helpers::run_path_with_cstr; use crate::sys::io::DEFAULT_BUF_SIZE; use crate::sys::time::SystemTime; @@ -293,9 +293,7 @@ impl DirEntry { } pub fn metadata(&self) -> io::Result { - let mut path = self.path(); - path.set_file_name(self.file_name_os_str()); - lstat(&path) + run_path_with_cstr(&self.path(), &lstat) } pub fn file_type(&self) -> io::Result { @@ -586,66 +584,70 @@ pub fn readdir(path: &Path) -> io::Result { Ok(ReadDir { inner, fd, buf }) } -pub fn unlink(path: &Path) -> io::Result<()> { - run_path_with_cstr(path, &|path| cvt(unsafe { hermit_abi::unlink(path.as_ptr()) }).map(|_| ())) +pub fn unlink(path: &CStr) -> io::Result<()> { + cvt(unsafe { hermit_abi::unlink(path.as_ptr()) }).map(|_| ()) } -pub fn rename(_old: &Path, _new: &Path) -> io::Result<()> { +pub fn rename(_old: &CStr, _new: &CStr) -> io::Result<()> { unsupported() } -pub fn set_perm(_p: &Path, _perm: FilePermissions) -> io::Result<()> { +pub fn set_perm(_p: &CStr, _perm: FilePermissions) -> io::Result<()> { unsupported() } -pub fn set_perm_nofollow(_p: &Path, _perm: FilePermissions) -> io::Result<()> { +pub fn set_perm_nofollow(_p: &CStr, _perm: FilePermissions) -> io::Result<()> { unsupported() } -pub fn set_times(_p: &Path, _times: FileTimes) -> io::Result<()> { +pub fn set_times(_p: &CStr, _times: FileTimes) -> io::Result<()> { unsupported() } -pub fn set_times_nofollow(_p: &Path, _times: FileTimes) -> io::Result<()> { +pub fn set_times_nofollow(_p: &CStr, _times: FileTimes) -> io::Result<()> { unsupported() } -pub fn rmdir(path: &Path) -> io::Result<()> { - run_path_with_cstr(path, &|path| cvt(unsafe { hermit_abi::rmdir(path.as_ptr()) }).map(|_| ())) +pub fn rmdir(path: &CStr) -> io::Result<()> { + cvt(unsafe { hermit_abi::rmdir(path.as_ptr()) }).map(|_| ()) +} + +pub fn exists(path: &CStr) -> io::Result { + match stat(path) { + Ok(_) => Ok(true), + Err(error) if error.kind() == io::ErrorKind::NotFound => Ok(false), + Err(error) => Err(error), + } } pub fn remove_dir_all(_path: &Path) -> io::Result<()> { unsupported() } -pub fn readlink(_p: &Path) -> io::Result { +pub fn readlink(_p: &CStr) -> io::Result { unsupported() } -pub fn symlink(_original: &Path, _link: &Path) -> io::Result<()> { +pub fn symlink(_original: &CStr, _link: &CStr) -> io::Result<()> { unsupported() } -pub fn link(_original: &Path, _link: &Path) -> io::Result<()> { +pub fn link(_original: &CStr, _link: &CStr) -> io::Result<()> { unsupported() } -pub fn stat(path: &Path) -> io::Result { - run_path_with_cstr(path, &|path| { - let mut stat_val: stat_struct = unsafe { mem::zeroed() }; - cvt(unsafe { hermit_abi::stat(path.as_ptr(), &mut stat_val) })?; - Ok(FileAttr::from_stat(stat_val)) - }) +pub fn stat(path: &CStr) -> io::Result { + let mut stat_val: stat_struct = unsafe { mem::zeroed() }; + cvt(unsafe { hermit_abi::stat(path.as_ptr(), &mut stat_val) })?; + Ok(FileAttr::from_stat(stat_val)) } -pub fn lstat(path: &Path) -> io::Result { - run_path_with_cstr(path, &|path| { - let mut stat_val: stat_struct = unsafe { mem::zeroed() }; - cvt(unsafe { hermit_abi::lstat(path.as_ptr(), &mut stat_val) })?; - Ok(FileAttr::from_stat(stat_val)) - }) +pub fn lstat(path: &CStr) -> io::Result { + let mut stat_val: stat_struct = unsafe { mem::zeroed() }; + cvt(unsafe { hermit_abi::lstat(path.as_ptr(), &mut stat_val) })?; + Ok(FileAttr::from_stat(stat_val)) } -pub fn canonicalize(_p: &Path) -> io::Result { +pub fn canonicalize(_p: &CStr) -> io::Result { unsupported() } diff --git a/library/std/src/sys/fs/mod.rs b/library/std/src/sys/fs/mod.rs index b2666eb2a3da9..e4cd81fdfd5a1 100644 --- a/library/std/src/sys/fs/mod.rs +++ b/library/std/src/sys/fs/mod.rs @@ -17,15 +17,11 @@ cfg_select! { pub(crate) use unix::debug_assert_fd_is_open; #[cfg(not(target_os = "wasi"))] pub use unix::{chown, fchown, lchown, mkfifo}; - - use crate::sys::helpers::run_path_with_cstr as with_native_path; } target_os = "windows" => { mod windows; use windows as imp; pub use windows::{junction_point, symlink_inner}; - - use crate::sys::path::with_native_path; } target_os = "hermit" => { mod hermit; @@ -53,18 +49,13 @@ cfg_select! { } } -// FIXME: Replace this with platform-specific path conversion functions. -#[cfg(not(any(target_family = "unix", target_os = "windows", target_os = "wasi")))] -#[inline] -pub fn with_native_path(path: &Path, f: &dyn Fn(&Path) -> io::Result) -> io::Result { - f(path) -} - pub use imp::{ Dir, DirBuilder, DirEntry, File, FileAttr, FilePermissions, FileTimes, FileType, OpenOptions, ReadDir, }; +use crate::sys::path::with_native_path; + pub fn read_dir(path: &Path) -> io::Result { // FIXME: use with_native_path on all platforms imp::readdir(path) @@ -139,10 +130,6 @@ pub fn copy(from: &Path, to: &Path) -> io::Result { } pub fn exists(path: &Path) -> io::Result { - // FIXME: use with_native_path on all platforms - #[cfg(not(windows))] - return imp::exists(path); - #[cfg(windows)] with_native_path(path, &imp::exists) } diff --git a/library/std/src/sys/fs/motor.rs b/library/std/src/sys/fs/motor.rs index 938d1537790a1..3b3e3dcc7a33c 100644 --- a/library/std/src/sys/fs/motor.rs +++ b/library/std/src/sys/fs/motor.rs @@ -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::{Dir, exists}; +pub use crate::sys::fs::common::Dir; use crate::sys::time::SystemTime; use crate::sys::{ AsInner, AsInnerMut, FromInner, IntoInner, io_slices, io_slices_mut, map_motor_error, @@ -313,69 +313,70 @@ impl DirBuilder { } } -pub fn unlink(path: &Path) -> io::Result<()> { - let path = path.to_str().ok_or(io::Error::from(io::ErrorKind::InvalidFilename))?; +pub fn unlink(path: &str) -> io::Result<()> { moto_rt::fs::unlink(path).map_err(map_motor_error) } -pub fn rename(old: &Path, new: &Path) -> io::Result<()> { - let old = old.to_str().ok_or(io::Error::from(io::ErrorKind::InvalidFilename))?; - let new = new.to_str().ok_or(io::Error::from(io::ErrorKind::InvalidFilename))?; +pub fn rename(old: &str, new: &str) -> io::Result<()> { moto_rt::fs::rename(old, new).map_err(map_motor_error) } -pub fn rmdir(path: &Path) -> io::Result<()> { - let path = path.to_str().ok_or(io::Error::from(io::ErrorKind::InvalidFilename))?; +pub fn rmdir(path: &str) -> io::Result<()> { moto_rt::fs::rmdir(path).map_err(map_motor_error) } +pub fn exists(path: &str) -> io::Result { + match stat(path) { + Ok(_) => Ok(true), + Err(error) if error.kind() == io::ErrorKind::NotFound => Ok(false), + Err(error) => Err(error), + } +} + pub fn remove_dir_all(path: &Path) -> io::Result<()> { let path = path.to_str().ok_or(io::Error::from(io::ErrorKind::InvalidFilename))?; moto_rt::fs::rmdir_all(path).map_err(map_motor_error) } -pub fn set_perm(path: &Path, perm: FilePermissions) -> io::Result<()> { +pub fn set_perm(path: &str, perm: FilePermissions) -> io::Result<()> { // Motor does not support symlinks set_perm_nofollow(path, perm) } -pub fn set_perm_nofollow(path: &Path, perm: FilePermissions) -> io::Result<()> { - let path = path.to_str().ok_or(io::Error::from(io::ErrorKind::InvalidFilename))?; +pub fn set_perm_nofollow(path: &str, perm: FilePermissions) -> io::Result<()> { moto_rt::fs::set_perm(path, perm.rt_perm).map_err(map_motor_error) } -pub fn set_times(_p: &Path, _times: FileTimes) -> io::Result<()> { +pub fn set_times(_p: &str, _times: FileTimes) -> io::Result<()> { unsupported() } -pub fn set_times_nofollow(_p: &Path, _times: FileTimes) -> io::Result<()> { +pub fn set_times_nofollow(_p: &str, _times: FileTimes) -> io::Result<()> { unsupported() } -pub fn readlink(_p: &Path) -> io::Result { +pub fn readlink(_p: &str) -> io::Result { unsupported() } -pub fn symlink(_original: &Path, _link: &Path) -> io::Result<()> { +pub fn symlink(_original: &str, _link: &str) -> io::Result<()> { unsupported() } -pub fn link(_src: &Path, _dst: &Path) -> io::Result<()> { +pub fn link(_src: &str, _dst: &str) -> io::Result<()> { unsupported() } -pub fn stat(path: &Path) -> io::Result { - let path = path.to_str().ok_or(io::Error::from(io::ErrorKind::InvalidFilename))?; +pub fn stat(path: &str) -> io::Result { let inner = moto_rt::fs::stat(path).map_err(map_motor_error)?; Ok(FileAttr { inner }) } -pub fn lstat(path: &Path) -> io::Result { +pub fn lstat(path: &str) -> io::Result { stat(path) } -pub fn canonicalize(path: &Path) -> io::Result { - let path = path.to_str().ok_or(io::Error::from(io::ErrorKind::InvalidFilename))?; +pub fn canonicalize(path: &str) -> io::Result { let path = moto_rt::fs::canonicalize(path).map_err(map_motor_error)?; Ok(path.into()) } diff --git a/library/std/src/sys/fs/solid.rs b/library/std/src/sys/fs/solid.rs index bd963b1d2f038..94e663443848f 100644 --- a/library/std/src/sys/fs/solid.rs +++ b/library/std/src/sys/fs/solid.rs @@ -1,6 +1,6 @@ #![allow(dead_code)] -use crate::ffi::{CStr, CString, OsStr, OsString}; +use crate::ffi::{CStr, OsStr, OsString}; use crate::fmt; use crate::fs::TryLockError; use crate::io::{self, BorrowedCursor, IoSlice, IoSliceMut, SeekFrom}; @@ -9,9 +9,10 @@ use crate::os::raw::{c_int, c_short}; use crate::os::solid::ffi::OsStrExt; use crate::path::{Path, PathBuf}; use crate::sync::Arc; -pub use crate::sys::fs::common::{Dir, exists}; +pub use crate::sys::fs::common::Dir; use crate::sys::helpers::ignore_notfound; use crate::sys::pal::{abi, error}; +use crate::sys::path::cstr; use crate::sys::time::SystemTime; use crate::sys::{unsupported, unsupported_err}; @@ -206,7 +207,8 @@ impl DirEntry { } pub fn metadata(&self) -> io::Result { - lstat(&self.path()) + let cstr = cstr(&self.path())?; + lstat(&cstr) } pub fn file_type(&self) -> io::Result { @@ -216,7 +218,7 @@ impl DirEntry { abi::DT_REG => Ok(FileType(abi::S_IFREG)), abi::DT_DIR => Ok(FileType(abi::S_IFDIR)), abi::DT_BLK => Ok(FileType(abi::S_IFBLK)), - _ => lstat(&self.path()).map(|m| m.file_type()), + _ => lstat(&cstr(&self.path())?).map(|m| m.file_type()), } } } @@ -296,26 +298,6 @@ impl OpenOptions { } } -fn cstr(path: &Path) -> io::Result { - let path = path.as_os_str().as_bytes(); - - if !path.starts_with(br"\") { - // Relative paths aren't supported - return Err(crate::io::const_error!( - crate::io::ErrorKind::Unsupported, - "relative path is not supported on this platform", - )); - } - - // Apply the thread-safety wrapper - const SAFE_PREFIX: &[u8] = br"\TS"; - let wrapped_path = [SAFE_PREFIX, &path, &[0]].concat(); - - CString::from_vec_with_nul(wrapped_path).map_err(|_| { - crate::io::const_error!(io::ErrorKind::InvalidInput, "path provided contains a nul byte") - }) -} - impl File { pub fn open(path: &Path, opts: &OpenOptions) -> io::Result { let flags = opts.get_access_mode()? @@ -512,48 +494,44 @@ impl fmt::Debug for File { } } -pub fn unlink(p: &Path) -> io::Result<()> { +pub fn unlink(p: &CStr) -> io::Result<()> { if stat(p)?.file_type().is_dir() { Err(io::const_error!(io::ErrorKind::IsADirectory, "is a directory")) } else { - error::SolidError::err_if_negative(unsafe { abi::SOLID_FS_Unlink(cstr(p)?.as_ptr()) }) + error::SolidError::err_if_negative(unsafe { abi::SOLID_FS_Unlink(p.as_ptr()) }) .map_err(|e| e.as_io_error())?; Ok(()) } } -pub fn rename(old: &Path, new: &Path) -> io::Result<()> { - error::SolidError::err_if_negative(unsafe { - abi::SOLID_FS_Rename(cstr(old)?.as_ptr(), cstr(new)?.as_ptr()) - }) - .map_err(|e| e.as_io_error())?; +pub fn rename(old: &CStr, new: &CStr) -> io::Result<()> { + error::SolidError::err_if_negative(unsafe { abi::SOLID_FS_Rename(old.as_ptr(), new.as_ptr()) }) + .map_err(|e| e.as_io_error())?; Ok(()) } -pub fn set_perm(p: &Path, perm: FilePermissions) -> io::Result<()> { +pub fn set_perm(p: &CStr, perm: FilePermissions) -> io::Result<()> { // Solid does not support symlinks set_perm_nofollow(p, perm) } -pub fn set_perm_nofollow(p: &Path, perm: FilePermissions) -> io::Result<()> { - error::SolidError::err_if_negative(unsafe { - abi::SOLID_FS_Chmod(cstr(p)?.as_ptr(), perm.0.into()) - }) - .map_err(|e| e.as_io_error())?; +pub fn set_perm_nofollow(p: &CStr, perm: FilePermissions) -> io::Result<()> { + error::SolidError::err_if_negative(unsafe { abi::SOLID_FS_Chmod(p.as_ptr(), perm.0.into()) }) + .map_err(|e| e.as_io_error())?; Ok(()) } -pub fn set_times(_p: &Path, _times: FileTimes) -> io::Result<()> { +pub fn set_times(_p: &CStr, _times: FileTimes) -> io::Result<()> { unsupported() } -pub fn set_times_nofollow(_p: &Path, _times: FileTimes) -> io::Result<()> { +pub fn set_times_nofollow(_p: &CStr, _times: FileTimes) -> io::Result<()> { unsupported() } -pub fn rmdir(p: &Path) -> io::Result<()> { +pub fn rmdir(p: &CStr) -> io::Result<()> { if stat(p)?.file_type().is_dir() { - error::SolidError::err_if_negative(unsafe { abi::SOLID_FS_Unlink(cstr(p)?.as_ptr()) }) + error::SolidError::err_if_negative(unsafe { abi::SOLID_FS_Unlink(p.as_ptr()) }) .map_err(|e| e.as_io_error())?; Ok(()) } else { @@ -561,6 +539,14 @@ pub fn rmdir(p: &Path) -> io::Result<()> { } } +pub fn exists(path: &CStr) -> io::Result { + match stat(path) { + Ok(_) => Ok(true), + Err(error) if error.kind() == io::ErrorKind::NotFound => Ok(false), + Err(error) => Err(error), + } +} + pub fn remove_dir_all(path: &Path) -> io::Result<()> { for child in readdir(path)? { let result: io::Result<()> = try { @@ -569,7 +555,7 @@ pub fn remove_dir_all(path: &Path) -> io::Result<()> { if child_type.is_dir() { remove_dir_all(&child.path())?; } else { - unlink(&child.path())?; + unlink(&cstr(&child.path())?)?; } }; // ignore internal NotFound errors @@ -579,43 +565,40 @@ pub fn remove_dir_all(path: &Path) -> io::Result<()> { return result; } } - ignore_notfound(rmdir(path)) + ignore_notfound(rmdir(&cstr(path)?)) } -pub fn readlink(p: &Path) -> io::Result { +pub fn readlink(p: &CStr) -> io::Result { // This target doesn't support symlinks stat(p)?; Err(io::const_error!(io::ErrorKind::InvalidInput, "not a symbolic link")) } -pub fn symlink(_original: &Path, _link: &Path) -> io::Result<()> { +pub fn symlink(_original: &CStr, _link: &CStr) -> io::Result<()> { // This target doesn't support symlinks unsupported() } -pub fn link(_src: &Path, _dst: &Path) -> io::Result<()> { +pub fn link(_src: &CStr, _dst: &CStr) -> io::Result<()> { // This target doesn't support symlinks unsupported() } -pub fn stat(p: &Path) -> io::Result { +pub fn stat(p: &CStr) -> io::Result { // This target doesn't support symlinks lstat(p) } -pub fn lstat(p: &Path) -> io::Result { +pub fn lstat(p: &CStr) -> io::Result { unsafe { let mut out_stat = MaybeUninit::uninit(); - error::SolidError::err_if_negative(abi::SOLID_FS_Stat( - cstr(p)?.as_ptr(), - out_stat.as_mut_ptr(), - )) - .map_err(|e| e.as_io_error())?; + error::SolidError::err_if_negative(abi::SOLID_FS_Stat(p.as_ptr(), out_stat.as_mut_ptr())) + .map_err(|e| e.as_io_error())?; Ok(FileAttr { stat: out_stat.assume_init() }) } } -pub fn canonicalize(_p: &Path) -> io::Result { +pub fn canonicalize(_p: &CStr) -> io::Result { unsupported() } diff --git a/library/std/src/sys/fs/uefi.rs b/library/std/src/sys/fs/uefi.rs index 08473e245cc8e..a0cbeeba32573 100644 --- a/library/std/src/sys/fs/uefi.rs +++ b/library/std/src/sys/fs/uefi.rs @@ -263,7 +263,9 @@ impl File { return Err(io::const_error!(io::ErrorKind::InvalidInput, "Invalid open options")); } - if opts.create_new && exists(path)? { + let path = crate::path::absolute(path)?; + + if opts.create_new && exists(path.clone())? { return Err(io::const_error!(io::ErrorKind::AlreadyExists, "File already exists")); } @@ -412,7 +414,7 @@ impl fmt::Debug for File { pub fn readdir(p: &Path) -> io::Result { let path = crate::path::absolute(p)?; - let f = uefi_fs::File::from_path(&path, file::MODE_READ, 0)?; + let f = uefi_fs::File::from_path(path, file::MODE_READ, 0)?; let file_info = f.file_info()?; let file_attr = FileAttr::from_uefi(file_info); @@ -444,11 +446,8 @@ pub fn unlink(p: &Path) -> io::Result<()> { /// 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 mut old_components = old.components(); + let mut new_components = new.components(); let Some(old_disk) = old_components.next() else { return Err(io::const_error!(io::ErrorKind::InvalidInput, "Old path is not valid")); @@ -538,7 +537,7 @@ pub fn lstat(p: &Path) -> io::Result { } pub fn canonicalize(p: &Path) -> io::Result { - crate::path::absolute(p) + Ok(p) } fn set_perm_inner(f: &uefi_fs::File, perm: FilePermissions) -> io::Result<()> { @@ -577,7 +576,7 @@ mod uefi_fs { use crate::ffi::OsString; use crate::io; use crate::os::uefi::ffi::OsStringExt; - use crate::path::Path; + use crate::path::{Path, PathBuf}; use crate::ptr::NonNull; use crate::sys::pal::helpers::{self, UefiBox}; use crate::sys::pal::system_time; @@ -585,7 +584,7 @@ mod uefi_fs { pub(crate) struct File { protocol: NonNull, - path: crate::path::PathBuf, + path: PathBuf, } // SAFETY: UEFI has no regular threads, and as per @@ -595,13 +594,11 @@ mod uefi_fs { impl File { pub(crate) fn from_path(path: &Path, open_mode: u64, attr: u64) -> io::Result { - let absolute = crate::path::absolute(path)?; - - let p = helpers::OwnedDevicePath::from_text(absolute.as_os_str())?; + let p = helpers::OwnedDevicePath::from_text(path.as_os_str())?; let (vol, mut path_remaining) = Self::open_volume_from_device_path(p.borrow())?; let protocol = Self::open(vol, &mut path_remaining, open_mode, attr)?; - Ok(Self { protocol, path: absolute }) + Ok(Self { protocol, path: path.to_path_buf() }) } /// Open Filesystem volume given a devicepath to the volume, or a file/directory in the diff --git a/library/std/src/sys/fs/unix.rs b/library/std/src/sys/fs/unix.rs index 74b4322d027c5..cf223bb49cea1 100644 --- a/library/std/src/sys/fs/unix.rs +++ b/library/std/src/sys/fs/unix.rs @@ -57,7 +57,6 @@ use crate::os::wasi::prelude::*; use crate::path::{Path, PathBuf}; use crate::sync::Arc; use crate::sys::fd::FileDesc; -pub use crate::sys::fs::common::exists; use crate::sys::helpers::run_path_with_cstr; use crate::sys::time::SystemTime; #[cfg(all(target_os = "linux", target_env = "gnu"))] @@ -1976,6 +1975,14 @@ pub fn rmdir(p: &CStr) -> io::Result<()> { cvt(unsafe { libc::rmdir(p.as_ptr()) }).map(|_| ()) } +pub fn exists(path: &CStr) -> io::Result { + match stat(path) { + Ok(_) => Ok(true), + Err(error) if error.kind() == io::ErrorKind::NotFound => Ok(false), + Err(error) => Err(error), + } +} + pub fn readlink(c_path: &CStr) -> io::Result { let p = c_path.as_ptr(); diff --git a/library/std/src/sys/fs/vexos.rs b/library/std/src/sys/fs/vexos.rs index 1357787c44c77..d97ad5998736d 100644 --- a/library/std/src/sys/fs/vexos.rs +++ b/library/std/src/sys/fs/vexos.rs @@ -1,4 +1,4 @@ -use crate::ffi::{OsString, c_char}; +use crate::ffi::{CStr, OsString, c_char}; use crate::fmt; use crate::fs::TryLockError; use crate::hash::Hash; @@ -11,10 +11,7 @@ use crate::sys::{unsupported, unsupported_err}; #[expect(dead_code)] #[path = "unsupported.rs"] mod unsupported_fs; -pub use unsupported_fs::{ - Dir, DirBuilder, FileTimes, canonicalize, link, readlink, remove_dir_all, rename, rmdir, - symlink, unlink, -}; +pub use unsupported_fs::{Dir, DirBuilder, FileTimes}; /// VEXos file descriptor. /// @@ -149,7 +146,7 @@ impl DirEntry { } pub fn metadata(&self) -> io::Result { - stat(&self.path) + run_path_with_cstr(&self.path(), &stat) } pub fn file_type(&self) -> io::Result { @@ -488,51 +485,91 @@ pub fn readdir(_p: &Path) -> io::Result { unsupported() } -pub fn set_perm(_p: &Path, _perm: FilePermissions) -> io::Result<()> { +pub fn unlink(_p: &CStr) -> io::Result<()> { unsupported() } -pub fn set_perm_nofollow(_p: &Path, _perm: FilePermissions) -> io::Result<()> { +pub fn rename(_old: &CStr, _new: &CStr) -> io::Result<()> { unsupported() } -pub fn set_times(_p: &Path, _times: FileTimes) -> io::Result<()> { +pub fn set_perm(_p: &CStr, _perm: FilePermissions) -> io::Result<()> { unsupported() } -pub fn set_times_nofollow(_p: &Path, _times: FileTimes) -> io::Result<()> { +pub fn set_perm_nofollow(_p: &CStr, _perm: FilePermissions) -> io::Result<()> { unsupported() } -pub fn exists(path: &Path) -> io::Result { - run_path_with_cstr(path, &|path| Ok(unsafe { vex_sdk::vexFileStatus(path.as_ptr()) } != 0)) +pub fn set_times(_p: &CStr, _times: FileTimes) -> io::Result<()> { + unsupported() +} + +pub fn set_times_nofollow(_p: &CStr, _times: FileTimes) -> io::Result<()> { + unsupported() +} + +pub fn rmdir(_p: &CStr) -> io::Result<()> { + unsupported() } -pub fn stat(p: &Path) -> io::Result { +pub fn remove_dir_all(_path: &Path) -> io::Result<()> { + unsupported() +} + +pub fn exists(path: &CStr) -> io::Result { + Ok(unsafe { vex_sdk::vexFileStatus(path.as_ptr()) } != 0) +} + +pub fn readlink(_p: &CStr) -> io::Result { + unsupported() +} + +pub fn symlink(_original: &CStr, _link: &CStr) -> io::Result<()> { + unsupported() +} + +pub fn link(_src: &CStr, _dst: &CStr) -> io::Result<()> { + unsupported() +} + +pub fn stat(p: &CStr) -> io::Result { // `vexFileStatus` returns 3 if the given path is a directory, 1 if the path is a // file, or 0 if no such path exists. const FILE_STATUS_DIR: u32 = 3; + let file_type = unsafe { vex_sdk::vexFileStatus(p.as_ptr()) }; - run_path_with_cstr(p, &|c_path| { - let file_type = unsafe { vex_sdk::vexFileStatus(c_path.as_ptr()) }; + // We can't get the size if its a directory because we cant open it as a file + if file_type == FILE_STATUS_DIR { + Ok(FileAttr::Dir) + } else { + let file = unsafe { vex_sdk::vexFileOpen(p.as_ptr(), c"".as_ptr()) }; - // We can't get the size if its a directory because we cant open it as a file - if file_type == FILE_STATUS_DIR { - Ok(FileAttr::Dir) + if file.is_null() { + Err(io::const_error!(io::ErrorKind::NotFound, "could not open file")) } else { - let mut opts = OpenOptions::new(); - opts.read(true); - let file = File::open(p, &opts)?; - file.file_attr() + // `vexFileSize` returns -1 upon error, so u64::try_from will fail on error. + if let Ok(size) = u64::try_from(unsafe { + // SAFETY: `self.fd` contains a valid pointer to `FIL` for this struct's lifetime. + vex_sdk::vexFileSize(file) + }) { + Ok(FileAttr::File { size }) + } else { + Err(io::const_error!(io::ErrorKind::InvalidData, "failed to get file size")) + } } - }) + } } -pub fn lstat(p: &Path) -> io::Result { +pub fn lstat(p: &CStr) -> io::Result { // Symlinks aren't supported in this filesystem stat(p) } +pub fn canonicalize(_p: &CStr) -> io::Result { + unsupported() +} + // Cannot use `copy` from `common` here, since `File::set_permissions` is unsupported on this target. pub fn copy(from: &Path, to: &Path) -> io::Result { use crate::fs::File; diff --git a/library/std/src/sys/path/mod.rs b/library/std/src/sys/path/mod.rs index bbb7577e186ae..354436dbbbb71 100644 --- a/library/std/src/sys/path/mod.rs +++ b/library/std/src/sys/path/mod.rs @@ -28,8 +28,8 @@ cfg_select! { pub use sgx::*; } target_os = "solid_asp3" => { - mod unsupported_backslash; - pub use unsupported_backslash::*; + mod solid; + pub use solid::*; } target_os = "uefi" => { mod uefi; @@ -40,8 +40,22 @@ cfg_select! { mod windows_prefix; pub use cygwin::*; } + target_os = "motor" => { + mod motor; + mod unix_like; + pub use motor::*; + pub use unix_like::*; + } + any(target_family = "unix", target_os = "vexos", target_os = "hermit", target_os = "wasi") => { + mod unix_like; + pub use unix_like::*; + + pub use crate::sys::helpers::run_path_with_cstr as with_native_path; + } _ => { - mod unix; - pub use unix::*; + mod unix_like; + mod unsupported; + pub use unix_like::*; + pub use unsupported::*; } } diff --git a/library/std/src/sys/path/motor.rs b/library/std/src/sys/path/motor.rs new file mode 100644 index 0000000000000..7f76fbc442792 --- /dev/null +++ b/library/std/src/sys/path/motor.rs @@ -0,0 +1,8 @@ +use crate::io; +use crate::os::motor::ffi::OsStrExt; +use crate::path::Path; + +#[inline] +pub fn with_native_path(path: &Path, f: &dyn Fn(&str) -> io::Result) -> io::Result { + f(path.as_str()) +} diff --git a/library/std/src/sys/path/solid.rs b/library/std/src/sys/path/solid.rs new file mode 100644 index 0000000000000..e13190c2d0311 --- /dev/null +++ b/library/std/src/sys/path/solid.rs @@ -0,0 +1,53 @@ +#![forbid(unsafe_op_in_unsafe_fn)] +use crate::ffi::{CStr, CString, OsStr}; +use crate::io; +use crate::os::solid::ffi::OsStrExt; +use crate::path::{Path, PathBuf, Prefix}; +use crate::sys::unsupported; + +path_separator_bytes!(b'\\'); + +pub fn cstr(path: &Path) -> io::Result { + let path = path.as_os_str().as_bytes(); + + if !path.starts_with(br"\") { + // Relative paths aren't supported + return Err(crate::io::const_error!( + crate::io::ErrorKind::Unsupported, + "relative path is not supported on this platform", + )); + } + + // Apply the thread-safety wrapper + const SAFE_PREFIX: &[u8] = br"\TS"; + let wrapped_path = [SAFE_PREFIX, &path, &[0]].concat(); + + CString::from_vec_with_nul(wrapped_path).map_err(|_| { + crate::io::const_error!(io::ErrorKind::InvalidInput, "path provided contains a nul byte") + }) +} + +#[inline] +pub const fn is_verbatim_sep(b: u8) -> bool { + is_sep_byte(b) +} + +pub fn parse_prefix(_: &OsStr) -> Option> { + None +} + +pub const HAS_PREFIXES: bool = true; + +#[inline] +pub fn with_native_path(path: &Path, f: &dyn Fn(&CStr) -> io::Result) -> io::Result { + let path = cstr(path)?; + f(&path) +} + +pub(crate) fn absolute(_path: &Path) -> io::Result { + unsupported() +} + +pub(crate) fn is_absolute(path: &Path) -> bool { + path.has_root() && path.prefix().is_some() +} diff --git a/library/std/src/sys/path/uefi.rs b/library/std/src/sys/path/uefi.rs index 8c911ee5f9c53..6dd31fa51e693 100644 --- a/library/std/src/sys/path/uefi.rs +++ b/library/std/src/sys/path/uefi.rs @@ -21,6 +21,12 @@ pub fn parse_prefix(_: &OsStr) -> Option> { pub const HAS_PREFIXES: bool = true; +#[inline] +pub fn with_native_path(path: &Path, f: &dyn Fn(&Path) -> io::Result) -> io::Result { + let path = absolute(path)?; + f(path.as_ref()) +} + /// UEFI paths can be of 4 types: /// /// 1. Absolute Shell Path: Uses shell mappings (eg: `FS0:`). Does not exist if UEFI shell not present. diff --git a/library/std/src/sys/path/unix.rs b/library/std/src/sys/path/unix_like.rs similarity index 100% rename from library/std/src/sys/path/unix.rs rename to library/std/src/sys/path/unix_like.rs diff --git a/library/std/src/sys/path/unsupported.rs b/library/std/src/sys/path/unsupported.rs new file mode 100644 index 0000000000000..2b3e49c155d67 --- /dev/null +++ b/library/std/src/sys/path/unsupported.rs @@ -0,0 +1,7 @@ +use crate::io; +use crate::path::Path; + +#[inline] +pub fn with_native_path(path: &Path, f: &dyn Fn(&Path) -> io::Result) -> io::Result { + f(path) +} diff --git a/library/std/src/sys/path/unsupported_backslash.rs b/library/std/src/sys/path/unsupported_backslash.rs deleted file mode 100644 index ce1851e938395..0000000000000 --- a/library/std/src/sys/path/unsupported_backslash.rs +++ /dev/null @@ -1,26 +0,0 @@ -#![forbid(unsafe_op_in_unsafe_fn)] -use crate::ffi::OsStr; -use crate::io; -use crate::path::{Path, PathBuf, Prefix}; -use crate::sys::unsupported; - -path_separator_bytes!(b'\\'); - -#[inline] -pub const fn is_verbatim_sep(b: u8) -> bool { - is_sep_byte(b) -} - -pub fn parse_prefix(_: &OsStr) -> Option> { - None -} - -pub const HAS_PREFIXES: bool = true; - -pub(crate) fn absolute(_path: &Path) -> io::Result { - unsupported() -} - -pub(crate) fn is_absolute(path: &Path) -> bool { - path.has_root() && path.prefix().is_some() -}