diff --git a/library/std/src/sys/fs/common.rs b/library/std/src/sys/fs/common.rs index 6a7a1f52c15ac..4c06f8acf208f 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 32ed0bd76214f..c8fe9a6db6fd7 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, ExtraHomeDirs, ExtraMediaDirs, copy, exists}; +pub use crate::sys::fs::common::{Dir, ExtraHomeDirs, ExtraMediaDirs, copy}; use crate::sys::helpers::run_path_with_cstr; use crate::sys::io::DEFAULT_BUF_SIZE; use crate::sys::time::SystemTime; @@ -301,9 +301,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 { @@ -594,70 +592,74 @@ 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 rename_noreplace(_old: &Path, _new: &Path) -> io::Result<()> { +pub fn rename_noreplace(_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 e15841b363d18..4f8dccea71096 100644 --- a/library/std/src/sys/fs/mod.rs +++ b/library/std/src/sys/fs/mod.rs @@ -2,6 +2,7 @@ use crate::io; use crate::path::{Path, PathBuf}; +use crate::sys::path::with_native_path; pub mod common; @@ -17,15 +18,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,13 +50,6 @@ 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, ExtraHomeDirs, ExtraMediaDirs, File, FileAttr, FilePermissions, FileTimes, FileType, OpenOptions, ReadDir, @@ -143,10 +133,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 269ece5666494..0e8d743f3068d 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, ExtraHomeDirs, ExtraMediaDirs, exists}; +pub use crate::sys::fs::common::{Dir, ExtraHomeDirs, ExtraMediaDirs}; use crate::sys::time::SystemTime; use crate::sys::{ AsInner, AsInnerMut, FromInner, IntoInner, io_slices, io_slices_mut, map_motor_error, @@ -313,73 +313,74 @@ 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 rename_noreplace(_old: &Path, _new: &Path) -> io::Result<()> { +pub fn rename_noreplace(_old: &str, _new: &str) -> io::Result<()> { unsupported() } -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 c43a4794e620e..00242f7e8cc6e 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, ExtraHomeDirs, ExtraMediaDirs, exists}; +pub use crate::sys::fs::common::{Dir, ExtraHomeDirs, ExtraMediaDirs}; 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}; @@ -214,7 +215,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 { @@ -224,7 +226,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()), } } } @@ -304,26 +306,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()? @@ -520,52 +502,48 @@ 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 rename_noreplace(_old: &Path, _new: &Path) -> io::Result<()> { +pub fn rename_noreplace(_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<()> { // 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 { @@ -573,6 +551,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 { @@ -581,7 +567,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 @@ -591,43 +577,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 945eaeaff1d7d..6de0b8597fcd3 100644 --- a/library/std/src/sys/fs/uefi.rs +++ b/library/std/src/sys/fs/uefi.rs @@ -271,7 +271,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")); } @@ -420,7 +422,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); @@ -452,11 +454,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")); @@ -550,7 +549,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<()> { @@ -589,7 +588,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; @@ -597,7 +596,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 @@ -607,13 +606,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 f66fdeabb8a83..609c97d1962d1 100644 --- a/library/std/src/sys/fs/unix.rs +++ b/library/std/src/sys/fs/unix.rs @@ -64,7 +64,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; #[cfg(target_os = "wasi")] pub use crate::sys::fs::common::{ExtraHomeDirs, ExtraMediaDirs}; use crate::sys::helpers::run_path_with_cstr; @@ -2048,6 +2047,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 5dbcdfef7c80d..fc88dc9e67a9a 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, - rename_noreplace, rmdir, symlink, unlink, -}; +pub use unsupported_fs::{Dir, DirBuilder, FileTimes}; pub use crate::sys::fs::common::{ExtraHomeDirs, ExtraMediaDirs}; @@ -157,7 +154,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 { @@ -199,84 +196,85 @@ impl OpenOptions { impl File { pub fn open(path: &Path, opts: &OpenOptions) -> io::Result { - run_path_with_cstr(path, &|path| { - // Enforce the invariants of `create_new`/`create`. - // - // Since VEXos doesn't have anything akin to POSIX's `oflags`, we need to enforce - // the requirements that `create_new` can't have an existing file and `!create` - // doesn't create a file ourselves. - if !opts.read && (opts.write || opts.append) && (opts.create_new || !opts.create) { - let status = unsafe { vex_sdk::vexFileStatus(path.as_ptr()) }; - - if opts.create_new && status != 0 { - return Err(io::const_error!(io::ErrorKind::AlreadyExists, "file exists",)); - } else if !opts.create && status == 0 { - return Err(io::const_error!( - io::ErrorKind::NotFound, - "no such file or directory", - )); - } + run_path_with_cstr(path, &|path| File::open_c(path, opts)) + } + + pub fn open_c(path: &CStr, opts: &OpenOptions) -> io::Result { + // Enforce the invariants of `create_new`/`create`. + // + // Since VEXos doesn't have anything akin to POSIX's `oflags`, we need to enforce + // the requirements that `create_new` can't have an existing file and `!create` + // doesn't create a file ourselves. + if !opts.read && (opts.write || opts.append) && (opts.create_new || !opts.create) { + let status = unsafe { vex_sdk::vexFileStatus(path.as_ptr()) }; + + if opts.create_new && status != 0 { + return Err(io::const_error!(io::ErrorKind::AlreadyExists, "file exists",)); + } else if !opts.create && status == 0 { + return Err( + io::const_error!(io::ErrorKind::NotFound, "no such file or directory",), + ); } + } - let file = match opts { - // read + write - unsupported - OpenOptions { read: true, write: true, .. } => { - return Err(io::const_error!( - io::ErrorKind::InvalidInput, - "opening files with read and write access is unsupported on this target", - )); - } + let file = match opts { + // read + write - unsupported + OpenOptions { read: true, write: true, .. } => { + return Err(io::const_error!( + io::ErrorKind::InvalidInput, + "opening files with read and write access is unsupported on this target", + )); + } - // read - OpenOptions { - read: true, - write: false, - append: _, - truncate: false, - create: false, - create_new: false, - } => unsafe { vex_sdk::vexFileOpen(path.as_ptr(), c"".as_ptr()) }, - - // append - OpenOptions { - read: false, - write: _, - append: true, - truncate: false, - create: _, - create_new: _, - } => unsafe { vex_sdk::vexFileOpenWrite(path.as_ptr()) }, - - // write - OpenOptions { - read: false, - write: true, - append: false, - truncate, - create: _, - create_new: _, - } => unsafe { - if *truncate { - vex_sdk::vexFileOpenCreate(path.as_ptr()) - } else { - // Open in append, but jump to the start of the file. - let fd = vex_sdk::vexFileOpenWrite(path.as_ptr()); - vex_sdk::vexFileSeek(fd, 0, 0); - fd - } - }, - - _ => { - return Err(io::const_error!(io::ErrorKind::InvalidInput, "invalid argument")); + // read + OpenOptions { + read: true, + write: false, + append: _, + truncate: false, + create: false, + create_new: false, + } => unsafe { vex_sdk::vexFileOpen(path.as_ptr(), c"".as_ptr()) }, + + // append + OpenOptions { + read: false, + write: _, + append: true, + truncate: false, + create: _, + create_new: _, + } => unsafe { vex_sdk::vexFileOpenWrite(path.as_ptr()) }, + + // write + OpenOptions { + read: false, + write: true, + append: false, + truncate, + create: _, + create_new: _, + } => unsafe { + if *truncate { + vex_sdk::vexFileOpenCreate(path.as_ptr()) + } else { + // Open in append, but jump to the start of the file. + let fd = vex_sdk::vexFileOpenWrite(path.as_ptr()); + vex_sdk::vexFileSeek(fd, 0, 0); + fd } - }; + }, - if file.is_null() { - Err(io::const_error!(io::ErrorKind::NotFound, "could not open file")) - } else { - Ok(Self { fd: FileDesc(file) }) + _ => { + return Err(io::const_error!(io::ErrorKind::InvalidInput, "invalid argument")); } - }) + }; + + if file.is_null() { + Err(io::const_error!(io::ErrorKind::NotFound, "could not open file")) + } else { + Ok(Self { fd: FileDesc(file) }) + } } pub fn file_attr(&self) -> io::Result { @@ -503,51 +501,84 @@ 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 rename(_old: &CStr, _new: &CStr) -> io::Result<()> { unsupported() } -pub fn set_perm_nofollow(_p: &Path, _perm: FilePermissions) -> io::Result<()> { +pub fn rename_noreplace(_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 mut opts = OpenOptions::new(); - opts.read(true); - let file = File::open(p, &opts)?; - file.file_attr() - } - }) + // 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 mut opts = OpenOptions::new(); + opts.read(true); + let file = File::open_c(p, &opts)?; + file.file_attr() + } } -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..bd7a499e13188 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; @@ -41,7 +41,7 @@ cfg_select! { pub use cygwin::*; } _ => { - mod unix; - pub use unix::*; + mod unix_like; + pub use unix_like::*; } } 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 76% rename from library/std/src/sys/path/unix.rs rename to library/std/src/sys/path/unix_like.rs index 5a8c0c77745e0..aae61c958bf5a 100644 --- a/library/std/src/sys/path/unix.rs +++ b/library/std/src/sys/path/unix_like.rs @@ -1,7 +1,33 @@ use crate::ffi::OsStr; +#[cfg(target_os = "motor")] +use crate::os::motor::ffi::OsStrExt; use crate::path::{Path, PathBuf, Prefix}; use crate::{env, io}; +cfg_select! { + target_os = "motor" => { + #[inline] + pub fn with_native_path( + path: &Path, + f: &dyn Fn(&str) -> io::Result, + ) -> io::Result { + f(path.as_os_str().as_str()) + } + } + any(target_family = "unix", target_os = "vexos", target_os = "hermit", target_os = "wasi") => { + pub use crate::sys::helpers::run_path_with_cstr as with_native_path; + } + _ => { + #[inline] + pub fn with_native_path( + path: &Path, + f: &dyn Fn(&Path) -> io::Result, + ) -> io::Result { + f(path) + } + } +} + path_separator_bytes!(b'/'); #[inline] 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() -}