diff --git a/library/std/src/fs.rs b/library/std/src/fs.rs
index 694cc34cdc171..bffb9296e1156 100644
--- a/library/std/src/fs.rs
+++ b/library/std/src/fs.rs
@@ -14,10 +14,11 @@ mod tests;
use crate::ffi::OsString;
use crate::fmt;
use crate::io::{self, BorrowedCursor, IoSlice, IoSliceMut, Read, Seek, SeekFrom, Write};
-use crate::path::{Path, PathBuf};
+use crate::path::{AsPath, Path, PathBuf};
use crate::sealed::Sealed;
use crate::sync::Arc;
-use crate::sys::fs as fs_imp;
+use crate::sys;
+use crate::sys::fs::fs_imp;
use crate::sys_common::{AsInner, AsInnerMut, FromInner, IntoInner};
use crate::time::SystemTime;
@@ -256,16 +257,16 @@ pub struct DirBuilder {
/// }
/// ```
#[stable(feature = "fs_read_write_bytes", since = "1.26.0")]
-pub fn read<P: AsRef<Path>>(path: P) -> io::Result<Vec<u8>> {
- fn inner(path: &Path) -> io::Result<Vec<u8>> {
- let mut file = File::open(path)?;
+pub fn read<P: AsPath>(path: P) -> io::Result<Vec<u8>> {
+ fn inner(mut file: File) -> io::Result<Vec<u8>> {
let size = file.metadata().map(|m| m.len() as usize).ok();
let mut bytes = Vec::new();
bytes.try_reserve_exact(size.unwrap_or(0)).map_err(|_| io::ErrorKind::OutOfMemory)?;
io::default_read_to_end(&mut file, &mut bytes, size)?;
Ok(bytes)
}
- inner(path.as_ref())
+ let file = File::open(path)?;
+ inner(file)
}
/// Read the entire contents of a file into a string.
@@ -299,16 +300,16 @@ pub fn read<P: AsRef<Path>>(path: P) -> io::Result<Vec<u8>> {
/// }
/// ```
#[stable(feature = "fs_read_write", since = "1.26.0")]
-pub fn read_to_string<P: AsRef<Path>>(path: P) -> io::Result<String> {
- fn inner(path: &Path) -> io::Result<String> {
- let mut file = File::open(path)?;
+pub fn read_to_string<P: AsPath>(path: P) -> io::Result<String> {
+ fn inner(mut file: File) -> io::Result<String> {
let size = file.metadata().map(|m| m.len() as usize).ok();
let mut string = String::new();
string.try_reserve_exact(size.unwrap_or(0)).map_err(|_| io::ErrorKind::OutOfMemory)?;
io::default_read_to_string(&mut file, &mut string, size)?;
Ok(string)
}
- inner(path.as_ref())
+ let file = File::open(path)?;
+ inner(file)
}
/// Write a slice as the entire contents of a file.
@@ -336,11 +337,12 @@ pub fn read_to_string<P: AsRef<Path>>(path: P) -> io::Result<String> {
/// }
/// ```
#[stable(feature = "fs_read_write_bytes", since = "1.26.0")]
-pub fn write<P: AsRef<Path>, C: AsRef<[u8]>>(path: P, contents: C) -> io::Result<()> {
- fn inner(path: &Path, contents: &[u8]) -> io::Result<()> {
- File::create(path)?.write_all(contents)
+pub fn write<P: AsPath, C: AsRef<[u8]>>(path: P, contents: C) -> io::Result<()> {
+ fn inner(mut file: File, contents: &[u8]) -> io::Result<()> {
+ file.write_all(contents)
}
- inner(path.as_ref(), contents.as_ref())
+ let file = File::create(path)?;
+ inner(file, contents.as_ref())
}
impl File {
@@ -371,8 +373,8 @@ impl File {
/// }
/// ```
#[stable(feature = "rust1", since = "1.0.0")]
- pub fn open<P: AsRef<Path>>(path: P) -> io::Result<File> {
- OpenOptions::new().read(true).open(path.as_ref())
+ pub fn open<P: AsPath>(path: P) -> io::Result<File> {
+ OpenOptions::new().read(true).open(path)
}
/// Opens a file in write-only mode.
@@ -400,8 +402,8 @@ impl File {
/// }
/// ```
#[stable(feature = "rust1", since = "1.0.0")]
- pub fn create<P: AsRef<Path>>(path: P) -> io::Result<File> {
- OpenOptions::new().write(true).create(true).truncate(true).open(path.as_ref())
+ pub fn create<P: AsPath>(path: P) -> io::Result<File> {
+ OpenOptions::new().write(true).create(true).truncate(true).open(path)
}
/// Creates a new file in read-write mode; error if the file exists.
@@ -429,8 +431,8 @@ impl File {
/// }
/// ```
#[stable(feature = "file_create_new", since = "1.77.0")]
- pub fn create_new<P: AsRef<Path>>(path: P) -> io::Result<File> {
- OpenOptions::new().read(true).write(true).create_new(true).open(path.as_ref())
+ pub fn create_new<P: AsPath>(path: P) -> io::Result<File> {
+ OpenOptions::new().read(true).write(true).create_new(true).open(path)
}
/// Returns a new OpenOptions object.
@@ -1127,12 +1129,12 @@ impl OpenOptions {
/// [`NotFound`]: io::ErrorKind::NotFound
/// [`PermissionDenied`]: io::ErrorKind::PermissionDenied
#[stable(feature = "rust1", since = "1.0.0")]
- pub fn open<P: AsRef<Path>>(&self, path: P) -> io::Result<File> {
- self._open(path.as_ref())
+ pub fn open<P: AsPath>(&self, path: P) -> io::Result<File> {
+ path.with_native_path(|path| self._open(path))
}
- fn _open(&self, path: &Path) -> io::Result<File> {
- fs_imp::File::open(path, &self.0).map(|inner| File { inner })
+ fn _open(&self, path: &sys::path::NativePath) -> io::Result<File> {
+ fs_imp::File::open_native(path, &self.0).map(|inner| File { inner })
}
}
@@ -1884,8 +1886,8 @@ impl AsInner<fs_imp::DirEntry> for DirEntry {
/// ```
#[doc(alias = "rm", alias = "unlink", alias = "DeleteFile")]
#[stable(feature = "rust1", since = "1.0.0")]
-pub fn remove_file<P: AsRef<Path>>(path: P) -> io::Result<()> {
- fs_imp::unlink(path.as_ref())
+pub fn remove_file<P: AsPath>(path: P) -> io::Result<()> {
+ fs_imp::remove_file(path)
}
/// Given a path, query the file system to get information about a file,
@@ -1923,8 +1925,8 @@ pub fn remove_file<P: AsRef<Path>>(path: P) -> io::Result<()> {
/// ```
#[doc(alias = "stat")]
#[stable(feature = "rust1", since = "1.0.0")]
-pub fn metadata<P: AsRef<Path>>(path: P) -> io::Result<Metadata> {
- fs_imp::stat(path.as_ref()).map(Metadata)
+pub fn metadata<P: AsPath>(path: P) -> io::Result<Metadata> {
+ fs_imp::metadata(path).map(Metadata)
}
/// Query the metadata about a file without following symlinks.
@@ -1958,8 +1960,8 @@ pub fn metadata<P: AsRef<Path>>(path: P) -> io::Result<Metadata> {
/// ```
#[doc(alias = "lstat")]
#[stable(feature = "symlink_metadata", since = "1.1.0")]
-pub fn symlink_metadata<P: AsRef<Path>>(path: P) -> io::Result<Metadata> {
- fs_imp::lstat(path.as_ref()).map(Metadata)
+pub fn symlink_metadata<P: AsPath>(path: P) -> io::Result<Metadata> {
+ fs_imp::symlink_metadata(path).map(Metadata)
}
/// Rename a file or directory to a new name, replacing the original file if
@@ -2002,8 +2004,8 @@ pub fn symlink_metadata<P: AsRef<Path>>(path: P) -> io::Result<Metadata> {
/// ```
#[doc(alias = "mv", alias = "MoveFile", alias = "MoveFileEx")]
#[stable(feature = "rust1", since = "1.0.0")]
-pub fn rename<P: AsRef<Path>, Q: AsRef<Path>>(from: P, to: Q) -> io::Result<()> {
- fs_imp::rename(from.as_ref(), to.as_ref())
+pub fn rename<P: AsPath, Q: AsPath>(from: P, to: Q) -> io::Result<()> {
+ fs_imp::rename(from, to)
}
/// Copies the contents of one file to another. This function will also
@@ -2063,8 +2065,8 @@ pub fn rename<P: AsRef<Path>, Q: AsRef<Path>>(from: P, to: Q) -> io::Result<()>
#[doc(alias = "CopyFile", alias = "CopyFileEx")]
#[doc(alias = "fclonefileat", alias = "fcopyfile")]
#[stable(feature = "rust1", since = "1.0.0")]
-pub fn copy<P: AsRef<Path>, Q: AsRef<Path>>(from: P, to: Q) -> io::Result<u64> {
- fs_imp::copy(from.as_ref(), to.as_ref())
+pub fn copy<P: AsPath, Q: AsPath>(from: P, to: Q) -> io::Result<u64> {
+ fs_imp::copy(from, to)
}
/// Creates a new hard link on the filesystem.
@@ -2108,8 +2110,8 @@ pub fn copy<P: AsRef<Path>, Q: AsRef<Path>>(from: P, to: Q) -> io::Result<u64> {
/// ```
#[doc(alias = "CreateHardLink", alias = "linkat")]
#[stable(feature = "rust1", since = "1.0.0")]
-pub fn hard_link<P: AsRef<Path>, Q: AsRef<Path>>(original: P, link: Q) -> io::Result<()> {
- fs_imp::link(original.as_ref(), link.as_ref())
+pub fn hard_link<P: AsPath, Q: AsPath>(original: P, link: Q) -> io::Result<()> {
+ fs_imp::hard_link(original, link)
}
/// Creates a new symbolic link on the filesystem.
@@ -2140,8 +2142,8 @@ pub fn hard_link<P: AsRef<Path>, Q: AsRef<Path>>(original: P, link: Q) -> io::Re
note = "replaced with std::os::unix::fs::symlink and \
std::os::windows::fs::{symlink_file, symlink_dir}"
)]
-pub fn soft_link<P: AsRef<Path>, Q: AsRef<Path>>(original: P, link: Q) -> io::Result<()> {
- fs_imp::symlink(original.as_ref(), link.as_ref())
+pub fn soft_link<P: AsPath, Q: AsPath>(original: P, link: Q) -> io::Result<()> {
+ fs_imp::soft_link(original, link)
}
/// Reads a symbolic link, returning the file that the link points to.
@@ -2174,8 +2176,8 @@ pub fn soft_link<P: AsRef<Path>, Q: AsRef<Path>>(original: P, link: Q) -> io::Re
/// }
/// ```
#[stable(feature = "rust1", since = "1.0.0")]
-pub fn read_link<P: AsRef<Path>>(path: P) -> io::Result<PathBuf> {
- fs_imp::readlink(path.as_ref())
+pub fn read_link<P: AsPath>(path: P) -> io::Result<PathBuf> {
+ fs_imp::read_link(path)
}
/// Returns the canonical, absolute form of a path with all intermediate
@@ -2217,8 +2219,8 @@ pub fn read_link<P: AsRef<Path>>(path: P) -> io::Result<PathBuf> {
#[doc(alias = "realpath")]
#[doc(alias = "GetFinalPathNameByHandle")]
#[stable(feature = "fs_canonicalize", since = "1.5.0")]
-pub fn canonicalize<P: AsRef<Path>>(path: P) -> io::Result<PathBuf> {
- fs_imp::canonicalize(path.as_ref())
+pub fn canonicalize<P: AsPath>(path: P) -> io::Result<PathBuf> {
+ fs_imp::canonicalize(path)
}
/// Creates a new, empty directory at the provided path
@@ -2259,8 +2261,8 @@ pub fn canonicalize<P: AsRef<Path>>(path: P) -> io::Result<PathBuf> {
#[doc(alias = "mkdir", alias = "CreateDirectory")]
#[stable(feature = "rust1", since = "1.0.0")]
#[cfg_attr(not(test), rustc_diagnostic_item = "fs_create_dir")]
-pub fn create_dir<P: AsRef<Path>>(path: P) -> io::Result<()> {
- DirBuilder::new().create(path.as_ref())
+pub fn create_dir<P: AsPath>(path: P) -> io::Result<()> {
+ DirBuilder::new().create(path)
}
/// Recursively create a directory and all of its parent components if they
@@ -2303,8 +2305,8 @@ pub fn create_dir<P: AsRef<Path>>(path: P) -> io::Result<()> {
/// }
/// ```
#[stable(feature = "rust1", since = "1.0.0")]
-pub fn create_dir_all<P: AsRef<Path>>(path: P) -> io::Result<()> {
- DirBuilder::new().recursive(true).create(path.as_ref())
+pub fn create_dir_all<P: AsPath>(path: P) -> io::Result<()> {
+ DirBuilder::new().recursive(true).create(path)
}
/// Removes an empty directory.
@@ -2339,8 +2341,8 @@ pub fn create_dir_all<P: AsRef<Path>>(path: P) -> io::Result<()> {
/// ```
#[doc(alias = "rmdir", alias = "RemoveDirectory")]
#[stable(feature = "rust1", since = "1.0.0")]
-pub fn remove_dir<P: AsRef<Path>>(path: P) -> io::Result<()> {
- fs_imp::rmdir(path.as_ref())
+pub fn remove_dir<P: AsPath>(path: P) -> io::Result<()> {
+ fs_imp::remove_dir(path)
}
/// Removes a directory at this path, after removing all its contents. Use
@@ -2386,8 +2388,8 @@ pub fn remove_dir<P: AsRef<Path>>(path: P) -> io::Result<()> {
/// }
/// ```
#[stable(feature = "rust1", since = "1.0.0")]
-pub fn remove_dir_all<P: AsRef<Path>>(path: P) -> io::Result<()> {
- fs_imp::remove_dir_all(path.as_ref())
+pub fn remove_dir_all<P: AsPath>(path: P) -> io::Result<()> {
+ fs_imp::remove_dir_all(path)
}
/// Returns an iterator over the entries within a directory.
@@ -2462,8 +2464,8 @@ pub fn remove_dir_all<P: AsRef<Path>>(path: P) -> io::Result<()> {
/// ```
#[doc(alias = "ls", alias = "opendir", alias = "FindFirstFile", alias = "FindNextFile")]
#[stable(feature = "rust1", since = "1.0.0")]
-pub fn read_dir<P: AsRef<Path>>(path: P) -> io::Result<ReadDir> {
- fs_imp::readdir(path.as_ref()).map(ReadDir)
+pub fn read_dir<P: AsPath>(path: P) -> io::Result<ReadDir> {
+ fs_imp::read_dir(path).map(ReadDir)
}
/// Changes the permissions found on a file or a directory.
@@ -2498,8 +2500,8 @@ pub fn read_dir<P: AsRef<Path>>(path: P) -> io::Result<ReadDir> {
/// ```
#[doc(alias = "chmod", alias = "SetFileAttributes")]
#[stable(feature = "set_permissions", since = "1.1.0")]
-pub fn set_permissions<P: AsRef<Path>>(path: P, perm: Permissions) -> io::Result<()> {
- fs_imp::set_perm(path.as_ref(), perm.0)
+pub fn set_permissions<P: AsPath>(path: P, perm: Permissions) -> io::Result<()> {
+ fs_imp::set_permissions(path, perm.0)
}
impl DirBuilder {
@@ -2558,8 +2560,8 @@ impl DirBuilder {
/// assert!(fs::metadata(path).unwrap().is_dir());
/// ```
#[stable(feature = "dir_builder", since = "1.6.0")]
- pub fn create<P: AsRef<Path>>(&self, path: P) -> io::Result<()> {
- self._create(path.as_ref())
+ pub fn create<P: AsPath>(&self, path: P) -> io::Result<()> {
+ path.with_path(|path| self._create(path))
}
fn _create(&self, path: &Path) -> io::Result<()> {
@@ -2630,6 +2632,6 @@ impl AsInnerMut<fs_imp::DirBuilder> for DirBuilder {
// instead.
#[unstable(feature = "fs_try_exists", issue = "83186")]
#[inline]
-pub fn try_exists<P: AsRef<Path>>(path: P) -> io::Result<bool> {
- fs_imp::try_exists(path.as_ref())
+pub fn try_exists<P: AsPath>(path: P) -> io::Result<bool> {
+ fs_imp::try_exists(path)
}
diff --git a/library/std/src/os/unix/ffi/mod.rs b/library/std/src/os/unix/ffi/mod.rs
index 5b49f50763d74..45d07d2a98347 100644
--- a/library/std/src/os/unix/ffi/mod.rs
+++ b/library/std/src/os/unix/ffi/mod.rs
@@ -38,5 +38,24 @@
mod os_str;
+use crate::ffi::CStr;
+use crate::path::NativePath;
+
#[stable(feature = "rust1", since = "1.0.0")]
pub use self::os_str::{OsStrExt, OsStringExt};
+
+#[unstable(feature = "fs_native_path", issue = "108979")]
+pub trait NativePathExt: crate::sealed::Sealed {
+ fn from_cstr(cstr: &CStr) -> &NativePath;
+ fn into_cstr(&self) -> &CStr;
+}
+
+#[unstable(feature = "fs_native_path", issue = "108979")]
+impl NativePathExt for NativePath {
+ fn from_cstr(cstr: &CStr) -> &NativePath {
+ unsafe { &*(cstr as *const CStr as *const NativePath) }
+ }
+ fn into_cstr(&self) -> &CStr {
+ unsafe { &*(self as *const Self as *const CStr) }
+ }
+}
diff --git a/library/std/src/os/unix/fs.rs b/library/std/src/os/unix/fs.rs
index 058e9b90cc7a1..a065ed60ce13a 100644
--- a/library/std/src/os/unix/fs.rs
+++ b/library/std/src/os/unix/fs.rs
@@ -8,7 +8,7 @@ use super::platform::fs::MetadataExt as _;
use crate::fs::{self, OpenOptions, Permissions};
use crate::io;
use crate::os::unix::io::{AsFd, AsRawFd};
-use crate::path::Path;
+use crate::path::{AsPath, Path};
use crate::sys;
use crate::sys_common::{AsInner, AsInnerMut, FromInner};
// Used for `File::read` on intra-doc links
@@ -954,8 +954,8 @@ impl DirEntryExt2 for fs::DirEntry {
/// }
/// ```
#[stable(feature = "symlink", since = "1.1.0")]
-pub fn symlink<P: AsRef<Path>, Q: AsRef<Path>>(original: P, link: Q) -> io::Result<()> {
- sys::fs::symlink(original.as_ref(), link.as_ref())
+pub fn symlink<P: AsPath, Q: AsPath>(original: P, link: Q) -> io::Result<()> {
+ sys::fs::fs_imp::soft_link(original, link)
}
/// Unix-specific extensions to [`fs::DirBuilder`].
diff --git a/library/std/src/os/wasi/fs.rs b/library/std/src/os/wasi/fs.rs
index 4525c3aa91477..e8e79f4193743 100644
--- a/library/std/src/os/wasi/fs.rs
+++ b/library/std/src/os/wasi/fs.rs
@@ -563,7 +563,9 @@ pub fn symlink<P: AsRef<Path>, U: AsRef<Path>>(
/// This is a convenience API similar to `std::os::unix::fs::symlink` and
/// `std::os::windows::fs::symlink_file` and `std::os::windows::fs::symlink_dir`.
pub fn symlink_path<P: AsRef<Path>, U: AsRef<Path>>(old_path: P, new_path: U) -> io::Result<()> {
- crate::sys::fs::symlink(old_path.as_ref(), new_path.as_ref())
+ crate::sys::common::small_c_string::run_path_with_cstr(new_path.as_ref(), &|new_path| {
+ crate::sys::fs::symlink(old_path.as_ref(), new_path)
+ })
}
fn osstr2str(f: &OsStr) -> io::Result<&str> {
diff --git a/library/std/src/os/windows/ffi.rs b/library/std/src/os/windows/ffi.rs
index 96bab59d3f8d7..1e20f1cbededf 100644
--- a/library/std/src/os/windows/ffi.rs
+++ b/library/std/src/os/windows/ffi.rs
@@ -54,6 +54,8 @@
#![stable(feature = "rust1", since = "1.0.0")]
use crate::ffi::{OsStr, OsString};
+#[cfg(not(target_os = "uefi"))]
+use crate::path::NativePath;
use crate::sealed::Sealed;
use crate::sys::os_str::Buf;
use crate::sys_common::wtf8::Wtf8Buf;
@@ -134,3 +136,37 @@ impl OsStrExt for OsStr {
self.as_inner().inner.encode_wide()
}
}
+
+/// On Windows `NativePath` wraps a wide string for use in filesystem function calls.
+/// These strings are `&[u16]` slices.
+///
+/// # Wide strings
+///
+/// Filesystem paths in Windows are encoded as UTF-16 strings.
+/// However, because the kernel does not verify validity this may contain invalid UTF-16.
+/// Therefore we use the term "wide string" for potentially invalid UTF-16.
+#[cfg(windows)]
+#[unstable(feature = "fs_native_path", issue = "108979")]
+pub trait NativePathExt: Sealed {
+ /// Wrap a Windows wide string as a `NativePath`.
+ /// The `wide` string must be null terminated and must not otherwise contain nulls.
+ fn from_wide(wide: &[u16]) -> &NativePath;
+ /// Wrap a Windows wide string as a `NativePath` without checking for null termination or internal nulls.
+ unsafe fn from_wide_unchecked(wide: &[u16]) -> &NativePath;
+ /// Unwrap the `NativePath` to return the inner wide string.
+ fn into_wide(&self) -> &[u16];
+}
+#[cfg(windows)]
+#[unstable(feature = "fs_native_path", issue = "108979")]
+impl NativePathExt for NativePath {
+ fn from_wide(wide: &[u16]) -> &NativePath {
+ assert_eq!(crate::sys::unrolled_find_u16s(0, wide), Some(wide.len().saturating_sub(1)));
+ unsafe { Self::from_wide_unchecked(wide) }
+ }
+ unsafe fn from_wide_unchecked(wide: &[u16]) -> &NativePath {
+ &*(wide as *const [u16] as *const Self)
+ }
+ fn into_wide(&self) -> &[u16] {
+ unsafe { &*(self as *const Self as *const [u16]) }
+ }
+}
diff --git a/library/std/src/os/windows/fs.rs b/library/std/src/os/windows/fs.rs
index e9d7a13e9d5b2..cff92e0944d2b 100644
--- a/library/std/src/os/windows/fs.rs
+++ b/library/std/src/os/windows/fs.rs
@@ -6,7 +6,7 @@
use crate::fs::{self, Metadata, OpenOptions};
use crate::io;
-use crate::path::Path;
+use crate::path::AsPath;
use crate::sealed::Sealed;
use crate::sys;
use crate::sys_common::{AsInner, AsInnerMut, IntoInner};
@@ -578,8 +578,9 @@ impl FileTimesExt for fs::FileTimes {
///
/// [symlink-security]: https://docs.microsoft.com/en-us/windows/security/threat-protection/security-policy-settings/create-symbolic-links
#[stable(feature = "symlink", since = "1.1.0")]
-pub fn symlink_file<P: AsRef<Path>, Q: AsRef<Path>>(original: P, link: Q) -> io::Result<()> {
- sys::fs::symlink_inner(original.as_ref(), link.as_ref(), false)
+pub fn symlink_file<P: AsPath, Q: AsPath>(original: P, link: Q) -> io::Result<()> {
+ original
+ .with_path(|original| link.with_path(|link| sys::fs::symlink_inner(original, link, false)))
}
/// Creates a new symlink to a directory on the filesystem.
@@ -617,6 +618,7 @@ pub fn symlink_file<P: AsRef<Path>, Q: AsRef<Path>>(original: P, link: Q) -> io:
///
/// [symlink-security]: https://docs.microsoft.com/en-us/windows/security/threat-protection/security-policy-settings/create-symbolic-links
#[stable(feature = "symlink", since = "1.1.0")]
-pub fn symlink_dir<P: AsRef<Path>, Q: AsRef<Path>>(original: P, link: Q) -> io::Result<()> {
- sys::fs::symlink_inner(original.as_ref(), link.as_ref(), true)
+pub fn symlink_dir<P: AsPath, Q: AsPath>(original: P, link: Q) -> io::Result<()> {
+ original
+ .with_path(|original| link.with_path(|link| sys::fs::symlink_inner(original, link, true)))
}
diff --git a/library/std/src/path.rs b/library/std/src/path.rs
index 56ea51226f9d5..f05f05a4b75a1 100644
--- a/library/std/src/path.rs
+++ b/library/std/src/path.rs
@@ -86,7 +86,9 @@ use crate::sync::Arc;
use crate::ffi::{os_str, OsStr, OsString};
use crate::sys;
-use crate::sys::path::{is_sep_byte, is_verbatim_sep, parse_prefix, MAIN_SEP_STR};
+use crate::sys::path::{
+ is_sep_byte, is_verbatim_sep, parse_prefix, NativePath as NativePathImpl, MAIN_SEP_STR,
+};
////////////////////////////////////////////////////////////////////////////////
// GENERAL NOTES
@@ -1108,6 +1110,55 @@ impl FusedIterator for Ancestors<'_> {}
// Basic types and traits
////////////////////////////////////////////////////////////////////////////////
+/// Represents a path in a form native to the OS.
+#[derive(Debug)]
+#[repr(transparent)]
+#[unstable(feature = "fs_native_path", issue = "108979")]
+pub struct NativePath(pub(crate) NativePathImpl);
+
+#[unstable(feature = "sealed", issue = "none")]
+impl crate::sealed::Sealed for NativePath {}
+#[unstable(feature = "sealed", issue = "none")]
+impl crate::sealed::Sealed for &NativePath {}
+
+/// # Stable use
+///
+/// Functions that need a filesystem path will often accept any type that implements [`AsRef<Path>`].
+///
+/// These types include [`Path`], [`OsStr`] and [`str`] as well as their owned
+/// counterparts [`PathBuf`], [`OsString`] and [`String`].
+///
+/// You can also implement you own [`AsRef<Path>`] for your own types and they'll
+/// automatically work for filesystem functions.
+///
+/// ## Example
+///
+/// ```no_run
+/// use std::ffi::OsStr;
+/// use std::path::Path;
+/// use std::fs;
+///
+/// // These are all equivalent.
+/// let metadata = fs::metadata("path/to/file")?;
+/// let metadata = fs::metadata(Path::new("path/to/file"))?;
+/// let metadata = fs::metadata(OsStr::new("path/to/file"))?;
+/// # Ok::<(), std::io::Error>(())
+/// ```
+///
+/// # Unstable use
+///
+/// The `AsPath` trait can also be used with [`NativePath`] to pass platform
+/// native paths more directly to system APIs.
+#[unstable(feature = "fs_native_path", issue = "108979")]
+pub trait AsPath {
+ #[doc(hidden)]
+ #[unstable(feature = "fs_native_path_internals", issue = "none")]
+ fn with_path<T, F: FnOnce(&Path) -> io::Result<T>>(self, f: F) -> io::Result<T>;
+ #[doc(hidden)]
+ #[unstable(feature = "fs_native_path_internals", issue = "none")]
+ fn with_native_path<T, F: Fn(&NativePathImpl) -> io::Result<T>>(self, f: F) -> io::Result<T>;
+}
+
/// An owned, mutable path (akin to [`String`]).
///
/// This type provides methods like [`push`] and [`set_extension`] that mutate
diff --git a/library/std/src/sys/pal/hermit/fs.rs b/library/std/src/sys/pal/hermit/fs.rs
index d4da53fd3df9e..ead14ed4cbb38 100644
--- a/library/std/src/sys/pal/hermit/fs.rs
+++ b/library/std/src/sys/pal/hermit/fs.rs
@@ -7,15 +7,66 @@ use crate::io::{self, Error, ErrorKind};
use crate::io::{BorrowedCursor, IoSlice, IoSliceMut, SeekFrom};
use crate::os::hermit::io::{AsFd, AsRawFd, BorrowedFd, FromRawFd, IntoRawFd, RawFd};
use crate::path::{Path, PathBuf};
-use crate::sys::common::small_c_string::run_path_with_cstr;
use crate::sys::cvt;
use crate::sys::time::SystemTime;
use crate::sys::unsupported;
use crate::sys_common::{AsInner, AsInnerMut, FromInner, IntoInner};
-pub use crate::sys_common::fs::{copy, try_exists};
//pub use crate::sys_common::fs::remove_dir_all;
+pub(crate) mod fs_imp {
+ pub(crate) use super::{
+ DirBuilder, DirEntry, File, FileAttr, FilePermissions, FileTimes, FileType, OpenOptions,
+ ReadDir,
+ };
+ use crate::io;
+ use crate::path::{AsPath, PathBuf};
+ use crate::sys::unsupported;
+
+ pub(crate) fn remove_file<P: AsPath>(_path: P) -> io::Result<()> {
+ unsupported()
+ }
+ pub(crate) fn symlink_metadata<P: AsPath>(_path: P) -> io::Result<FileAttr> {
+ unsupported()
+ }
+ pub(crate) fn metadata<P: AsPath>(_path: P) -> io::Result<FileAttr> {
+ unsupported()
+ }
+ pub(crate) fn rename<P: AsPath, Q: AsPath>(_from: P, _to: Q) -> io::Result<()> {
+ unsupported()
+ }
+ pub(crate) fn hard_link<P: AsPath, Q: AsPath>(_original: P, _link: Q) -> io::Result<()> {
+ unsupported()
+ }
+ pub(crate) fn soft_link<P: AsPath, Q: AsPath>(_original: P, _link: Q) -> io::Result<()> {
+ unsupported()
+ }
+ pub(crate) fn remove_dir<P: AsPath>(_path: P) -> io::Result<()> {
+ unsupported()
+ }
+ pub(crate) fn read_dir<P: AsPath>(_path: P) -> io::Result<ReadDir> {
+ unsupported()
+ }
+ pub(crate) fn set_permissions<P: AsPath>(_path: P, _perms: FilePermissions) -> io::Result<()> {
+ unsupported()
+ }
+ pub(crate) fn copy<P: AsPath, Q: AsPath>(_from: P, _to: Q) -> io::Result<u64> {
+ unsupported()
+ }
+ pub(crate) fn canonicalize<P: AsPath>(_path: P) -> io::Result<PathBuf> {
+ unsupported()
+ }
+ pub(crate) fn remove_dir_all<P: AsPath>(_path: P) -> io::Result<()> {
+ unsupported()
+ }
+ pub(crate) fn read_link<P: AsPath>(_path: P) -> io::Result<PathBuf> {
+ unsupported()
+ }
+ pub(crate) fn try_exists<P: AsPath>(_path: P) -> io::Result<bool> {
+ unsupported()
+ }
+}
+
#[derive(Debug)]
pub struct File(FileDesc);
@@ -268,11 +319,7 @@ impl OpenOptions {
}
impl File {
- pub fn open(path: &Path, opts: &OpenOptions) -> io::Result<File> {
- run_path_with_cstr(path, &|path| File::open_c(&path, opts))
- }
-
- pub fn open_c(path: &CStr, opts: &OpenOptions) -> io::Result<File> {
+ pub fn open_native(path: &CStr, opts: &OpenOptions) -> io::Result<File> {
let mut flags = opts.get_access_mode()?;
flags = flags | opts.get_creation_mode()?;
@@ -415,52 +462,3 @@ impl FromRawFd for File {
Self(FromRawFd::from_raw_fd(raw_fd))
}
}
-
-pub fn readdir(_p: &Path) -> io::Result<ReadDir> {
- unsupported()
-}
-
-pub fn unlink(path: &Path) -> io::Result<()> {
- run_path_with_cstr(path, &|path| cvt(unsafe { abi::unlink(path.as_ptr()) }).map(|_| ()))
-}
-
-pub fn rename(_old: &Path, _new: &Path) -> io::Result<()> {
- unsupported()
-}
-
-pub fn set_perm(_p: &Path, perm: FilePermissions) -> io::Result<()> {
- match perm.0 {}
-}
-
-pub fn rmdir(_p: &Path) -> io::Result<()> {
- unsupported()
-}
-
-pub fn remove_dir_all(_path: &Path) -> io::Result<()> {
- //unsupported()
- Ok(())
-}
-
-pub fn readlink(_p: &Path) -> io::Result<PathBuf> {
- unsupported()
-}
-
-pub fn symlink(_original: &Path, _link: &Path) -> io::Result<()> {
- unsupported()
-}
-
-pub fn link(_original: &Path, _link: &Path) -> io::Result<()> {
- unsupported()
-}
-
-pub fn stat(_p: &Path) -> io::Result<FileAttr> {
- unsupported()
-}
-
-pub fn lstat(_p: &Path) -> io::Result<FileAttr> {
- unsupported()
-}
-
-pub fn canonicalize(_p: &Path) -> io::Result<PathBuf> {
- unsupported()
-}
diff --git a/library/std/src/sys/pal/solid/fs.rs b/library/std/src/sys/pal/solid/fs.rs
index a6c1336109ad7..92ec2f024c6a7 100644
--- a/library/std/src/sys/pal/solid/fs.rs
+++ b/library/std/src/sys/pal/solid/fs.rs
@@ -14,6 +14,58 @@ use crate::{
pub use crate::sys_common::fs::try_exists;
+pub(crate) mod fs_imp {
+ pub(crate) use super::{
+ DirBuilder, DirEntry, File, FileAttr, FilePermissions, FileTimes, FileType, OpenOptions,
+ ReadDir,
+ };
+ use crate::io;
+ use crate::path::{AsPath, PathBuf};
+
+ pub(crate) fn remove_file<P: AsPath>(path: P) -> io::Result<()> {
+ path.with_path(super::unlink)
+ }
+ pub(crate) fn symlink_metadata<P: AsPath>(path: P) -> io::Result<FileAttr> {
+ path.with_path(|path| super::lstat(path))
+ }
+ pub(crate) fn metadata<P: AsPath>(path: P) -> io::Result<FileAttr> {
+ path.with_path(|path| super::stat(path))
+ }
+ pub(crate) fn rename<P: AsPath, Q: AsPath>(from: P, to: Q) -> io::Result<()> {
+ from.with_path(|from| to.with_path(|to| super::rename(from, to)))
+ }
+ pub(crate) fn hard_link<P: AsPath, Q: AsPath>(original: P, link: Q) -> io::Result<()> {
+ original.with_path(|original| link.with_path(|link| super::link(original, link)))
+ }
+ pub(crate) fn soft_link<P: AsPath, Q: AsPath>(original: P, link: Q) -> io::Result<()> {
+ original.with_path(|original| link.with_path(|link| super::symlink(original, link)))
+ }
+ pub(crate) fn remove_dir<P: AsPath>(path: P) -> io::Result<()> {
+ path.with_path(super::rmdir)
+ }
+ pub(crate) fn read_dir<P: AsPath>(path: P) -> io::Result<ReadDir> {
+ path.with_path(super::readdir)
+ }
+ pub(crate) fn set_permissions<P: AsPath>(path: P, perms: FilePermissions) -> io::Result<()> {
+ path.with_path(|path| super::set_perm(path, perms))
+ }
+ pub(crate) fn copy<P: AsPath, Q: AsPath>(from: P, to: Q) -> io::Result<u64> {
+ from.with_path(|from| to.with_path(|to| super::copy(from, to)))
+ }
+ pub(crate) fn canonicalize<P: AsPath>(path: P) -> io::Result<PathBuf> {
+ path.with_path(super::canonicalize)
+ }
+ pub(crate) fn remove_dir_all<P: AsPath>(path: P) -> io::Result<()> {
+ path.with_path(super::remove_dir_all)
+ }
+ pub(crate) fn read_link<P: AsPath>(path: P) -> io::Result<PathBuf> {
+ path.with_path(super::readlink)
+ }
+ pub(crate) fn try_exists<P: AsPath>(path: P) -> io::Result<bool> {
+ path.with_path(super::try_exists)
+ }
+}
+
/// A file descriptor.
#[derive(Clone, Copy)]
#[rustc_layout_scalar_valid_range_start(0)]
@@ -324,7 +376,7 @@ fn cstr(path: &Path) -> io::Result<CString> {
}
impl File {
- pub fn open(path: &Path, opts: &OpenOptions) -> io::Result<File> {
+ pub fn open_native(path: &CStr, opts: &OpenOptions) -> io::Result<File> {
let flags = opts.get_access_mode()?
| opts.get_creation_mode()?
| (opts.custom_flags as c_int & !abi::O_ACCMODE);
@@ -332,7 +384,7 @@ impl File {
let mut fd = MaybeUninit::uninit();
error::SolidError::err_if_negative(abi::SOLID_FS_Open(
fd.as_mut_ptr(),
- cstr(path)?.as_ptr(),
+ path.as_ptr(),
flags,
))
.map_err(|e| e.as_io_error())?;
diff --git a/library/std/src/sys/pal/unix/fs.rs b/library/std/src/sys/pal/unix/fs.rs
index 422a99380cc59..efdd41865e9c8 100644
--- a/library/std/src/sys/pal/unix/fs.rs
+++ b/library/std/src/sys/pal/unix/fs.rs
@@ -109,6 +109,60 @@ use libc::{dirent64, fstat64, ftruncate64, lseek64, lstat64, off64_t, open64, st
pub use crate::sys_common::fs::try_exists;
+pub(crate) mod fs_imp {
+ use crate::io;
+ use crate::path::AsPath;
+ use crate::path::PathBuf;
+ use crate::sys::fs;
+ pub(crate) use crate::sys::fs::{
+ DirBuilder, DirEntry, File, FileAttr, FilePermissions, FileTimes, FileType, OpenOptions,
+ ReadDir,
+ };
+
+ pub(crate) fn remove_file<P: AsPath>(path: P) -> io::Result<()> {
+ path.with_path(fs::unlink)
+ }
+ pub(crate) fn symlink_metadata<P: AsPath>(path: P) -> io::Result<FileAttr> {
+ path.with_path(|path| fs::lstat(path))
+ }
+ pub(crate) fn metadata<P: AsPath>(path: P) -> io::Result<FileAttr> {
+ path.with_path(|path| fs::stat(path))
+ }
+ pub(crate) fn rename<P: AsPath, Q: AsPath>(from: P, to: Q) -> io::Result<()> {
+ from.with_path(|from| to.with_path(|to| fs::rename(from, to)))
+ }
+ pub(crate) fn hard_link<P: AsPath, Q: AsPath>(original: P, link: Q) -> io::Result<()> {
+ original.with_path(|original| link.with_path(|link| fs::link(original, link)))
+ }
+ pub(crate) fn soft_link<P: AsPath, Q: AsPath>(original: P, link: Q) -> io::Result<()> {
+ original.with_path(|original| link.with_path(|link| fs::symlink(original, link)))
+ }
+ pub(crate) fn remove_dir<P: AsPath>(path: P) -> io::Result<()> {
+ path.with_path(fs::rmdir)
+ }
+ pub(crate) fn read_dir<P: AsPath>(path: P) -> io::Result<ReadDir> {
+ path.with_path(fs::readdir)
+ }
+ pub(crate) fn set_permissions<P: AsPath>(path: P, perms: FilePermissions) -> io::Result<()> {
+ path.with_path(|path| fs::set_perm(path, perms))
+ }
+ pub(crate) fn copy<P: AsPath, Q: AsPath>(from: P, to: Q) -> io::Result<u64> {
+ from.with_path(|from| to.with_path(|to| fs::copy(from, to)))
+ }
+ pub(crate) fn canonicalize<P: AsPath>(path: P) -> io::Result<PathBuf> {
+ path.with_path(fs::canonicalize)
+ }
+ pub(crate) fn remove_dir_all<P: AsPath>(path: P) -> io::Result<()> {
+ path.with_path(fs::remove_dir_all)
+ }
+ pub(crate) fn read_link<P: AsPath>(path: P) -> io::Result<PathBuf> {
+ path.with_path(fs::readlink)
+ }
+ pub(crate) fn try_exists<P: AsPath>(path: P) -> io::Result<bool> {
+ path.with_path(fs::try_exists)
+ }
+}
+
pub struct File(FileDesc);
// FIXME: This should be available on Linux with all `target_env`.
@@ -1117,11 +1171,7 @@ impl OpenOptions {
}
impl File {
- pub fn open(path: &Path, opts: &OpenOptions) -> io::Result<File> {
- run_path_with_cstr(path, &|path| File::open_c(path, opts))
- }
-
- pub fn open_c(path: &CStr, opts: &OpenOptions) -> io::Result<File> {
+ pub fn open_native(path: &CStr, opts: &OpenOptions) -> io::Result<File> {
let flags = libc::O_CLOEXEC
| opts.get_access_mode()?
| opts.get_creation_mode()?
diff --git a/library/std/src/sys/pal/unix/process/process_common.rs b/library/std/src/sys/pal/unix/process/process_common.rs
index f615e8086dccf..7b43ad66589a9 100644
--- a/library/std/src/sys/pal/unix/process/process_common.rs
+++ b/library/std/src/sys/pal/unix/process/process_common.rs
@@ -481,7 +481,7 @@ impl Stdio {
let mut opts = OpenOptions::new();
opts.read(readable);
opts.write(!readable);
- let fd = File::open_c(DEV_NULL, &opts)?;
+ let fd = File::open_native(DEV_NULL, &opts)?;
Ok((ChildStdio::Owned(fd.into_inner()), None))
}
diff --git a/library/std/src/sys/pal/unsupported/fs.rs b/library/std/src/sys/pal/unsupported/fs.rs
index 6ac1b5d2bcfca..f0ec12c394516 100644
--- a/library/std/src/sys/pal/unsupported/fs.rs
+++ b/library/std/src/sys/pal/unsupported/fs.rs
@@ -1,4 +1,4 @@
-use crate::ffi::OsString;
+use crate::ffi::{CStr, OsString};
use crate::fmt;
use crate::hash::{Hash, Hasher};
use crate::io::{self, BorrowedCursor, IoSlice, IoSliceMut, SeekFrom};
@@ -14,6 +14,60 @@ pub struct ReadDir(!);
pub struct DirEntry(!);
+#[allow(unused_variables)]
+pub(crate) mod fs_imp {
+ use super::unsupported;
+ pub(crate) use super::{
+ DirBuilder, DirEntry, File, FileAttr, FilePermissions, FileTimes, FileType, OpenOptions,
+ ReadDir,
+ };
+ use crate::io;
+ use crate::path::{AsPath, PathBuf};
+
+ pub(crate) fn remove_file<P: AsPath>(path: P) -> io::Result<()> {
+ unsupported()
+ }
+ pub(crate) fn symlink_metadata<P: AsPath>(path: P) -> io::Result<FileAttr> {
+ unsupported()
+ }
+ pub(crate) fn metadata<P: AsPath>(path: P) -> io::Result<FileAttr> {
+ unsupported()
+ }
+ pub(crate) fn rename<P: AsPath, Q: AsPath>(from: P, to: Q) -> io::Result<()> {
+ unsupported()
+ }
+ pub(crate) fn hard_link<P: AsPath, Q: AsPath>(original: P, link: Q) -> io::Result<()> {
+ unsupported()
+ }
+ pub(crate) fn soft_link<P: AsPath, Q: AsPath>(original: P, link: Q) -> io::Result<()> {
+ unsupported()
+ }
+ pub(crate) fn remove_dir<P: AsPath>(path: P) -> io::Result<()> {
+ unsupported()
+ }
+ pub(crate) fn read_dir<P: AsPath>(path: P) -> io::Result<ReadDir> {
+ unsupported()
+ }
+ pub(crate) fn set_permissions<P: AsPath>(path: P, perms: FilePermissions) -> io::Result<()> {
+ unsupported()
+ }
+ pub(crate) fn copy<P: AsPath, Q: AsPath>(from: P, to: Q) -> io::Result<u64> {
+ unsupported()
+ }
+ pub(crate) fn canonicalize<P: AsPath>(path: P) -> io::Result<PathBuf> {
+ unsupported()
+ }
+ pub(crate) fn remove_dir_all<P: AsPath>(path: P) -> io::Result<()> {
+ unsupported()
+ }
+ pub(crate) fn read_link<P: AsPath>(path: P) -> io::Result<PathBuf> {
+ unsupported()
+ }
+ pub(crate) fn try_exists<P: AsPath>(path: P) -> io::Result<bool> {
+ unsupported()
+ }
+}
+
#[derive(Clone, Debug)]
pub struct OpenOptions {}
@@ -182,7 +236,7 @@ impl OpenOptions {
}
impl File {
- pub fn open(_path: &Path, _opts: &OpenOptions) -> io::Result<File> {
+ pub fn open_native(_path: &CStr, _opts: &OpenOptions) -> io::Result<File> {
unsupported()
}
@@ -266,59 +320,3 @@ impl fmt::Debug for File {
self.0
}
}
-
-pub fn readdir(_p: &Path) -> io::Result<ReadDir> {
- unsupported()
-}
-
-pub fn unlink(_p: &Path) -> io::Result<()> {
- unsupported()
-}
-
-pub fn rename(_old: &Path, _new: &Path) -> io::Result<()> {
- unsupported()
-}
-
-pub fn set_perm(_p: &Path, perm: FilePermissions) -> io::Result<()> {
- match perm.0 {}
-}
-
-pub fn rmdir(_p: &Path) -> io::Result<()> {
- unsupported()
-}
-
-pub fn remove_dir_all(_path: &Path) -> io::Result<()> {
- unsupported()
-}
-
-pub fn try_exists(_path: &Path) -> io::Result<bool> {
- unsupported()
-}
-
-pub fn readlink(_p: &Path) -> io::Result<PathBuf> {
- unsupported()
-}
-
-pub fn symlink(_original: &Path, _link: &Path) -> io::Result<()> {
- unsupported()
-}
-
-pub fn link(_src: &Path, _dst: &Path) -> io::Result<()> {
- unsupported()
-}
-
-pub fn stat(_p: &Path) -> io::Result<FileAttr> {
- unsupported()
-}
-
-pub fn lstat(_p: &Path) -> io::Result<FileAttr> {
- unsupported()
-}
-
-pub fn canonicalize(_p: &Path) -> io::Result<PathBuf> {
- unsupported()
-}
-
-pub fn copy(_from: &Path, _to: &Path) -> io::Result<u64> {
- unsupported()
-}
diff --git a/library/std/src/sys/pal/wasi/fs.rs b/library/std/src/sys/pal/wasi/fs.rs
index 529b82e019893..3db22df9021dd 100644
--- a/library/std/src/sys/pal/wasi/fs.rs
+++ b/library/std/src/sys/pal/wasi/fs.rs
@@ -17,7 +17,58 @@ use crate::sys::time::SystemTime;
use crate::sys::unsupported;
use crate::sys_common::{AsInner, FromInner, IntoInner};
-pub use crate::sys_common::fs::try_exists;
+pub(crate) mod fs_imp {
+ pub(crate) use super::{
+ DirBuilder, DirEntry, File, FileAttr, FilePermissions, FileTimes, FileType, OpenOptions,
+ ReadDir,
+ };
+ use crate::io;
+ use crate::path::AsPath;
+ use crate::path::PathBuf;
+
+ pub(crate) fn remove_file<P: AsPath>(path: P) -> io::Result<()> {
+ path.with_native_path(super::unlink)
+ }
+ pub(crate) fn symlink_metadata<P: AsPath>(path: P) -> io::Result<FileAttr> {
+ path.with_native_path(|path| super::lstat(path))
+ }
+ pub(crate) fn metadata<P: AsPath>(path: P) -> io::Result<FileAttr> {
+ path.with_native_path(|path| super::stat(path))
+ }
+ pub(crate) fn rename<P: AsPath, Q: AsPath>(from: P, to: Q) -> io::Result<()> {
+ to.with_path(|to| from.with_native_path(|from| super::rename(from, to)))
+ }
+ pub(crate) fn hard_link<P: AsPath, Q: AsPath>(original: P, link: Q) -> io::Result<()> {
+ link.with_path(|link| original.with_native_path(|original| super::link(original, link)))
+ }
+ pub(crate) fn soft_link<P: AsPath, Q: AsPath>(original: P, link: Q) -> io::Result<()> {
+ original.with_path(|original| link.with_native_path(|link| super::symlink(original, link)))
+ }
+ pub(crate) fn remove_dir<P: AsPath>(path: P) -> io::Result<()> {
+ path.with_native_path(super::rmdir)
+ }
+ pub(crate) fn read_dir<P: AsPath>(path: P) -> io::Result<ReadDir> {
+ path.with_path(super::readdir)
+ }
+ pub(crate) fn set_permissions<P: AsPath>(path: P, perms: FilePermissions) -> io::Result<()> {
+ path.with_path(|path| super::set_perm(path, perms))
+ }
+ pub(crate) fn copy<P: AsPath, Q: AsPath>(from: P, to: Q) -> io::Result<u64> {
+ from.with_path(|from| to.with_path(|to| super::copy(from, to)))
+ }
+ pub(crate) fn canonicalize<P: AsPath>(path: P) -> io::Result<PathBuf> {
+ path.with_path(super::canonicalize)
+ }
+ pub(crate) fn remove_dir_all<P: AsPath>(path: P) -> io::Result<()> {
+ path.with_path(super::remove_dir_all)
+ }
+ pub(crate) fn read_link<P: AsPath>(path: P) -> io::Result<PathBuf> {
+ path.with_native_path(super::readlink)
+ }
+ pub(crate) fn try_exists<P: AsPath>(path: P) -> io::Result<bool> {
+ path.with_path(crate::sys_common::fs::try_exists)
+ }
+}
pub struct File {
fd: WasiFd,
@@ -398,7 +449,7 @@ impl OpenOptions {
}
impl File {
- pub fn open(path: &Path, opts: &OpenOptions) -> io::Result<File> {
+ pub fn open_native(path: &CStr, opts: &OpenOptions) -> io::Result<File> {
let (dir, file) = open_parent(path)?;
open_at(&dir, &file, opts)
}
@@ -548,8 +599,10 @@ impl DirBuilder {
}
pub fn mkdir(&self, p: &Path) -> io::Result<()> {
- let (dir, file) = open_parent(p)?;
- dir.create_directory(osstr2str(file.as_ref())?)
+ run_path_with_cstr(p, &|p| {
+ let (dir, file) = open_parent(p)?;
+ dir.create_directory(osstr2str(file.as_ref())?)
+ })
}
}
@@ -563,18 +616,18 @@ pub fn readdir(p: &Path) -> io::Result<ReadDir> {
let mut opts = OpenOptions::new();
opts.directory(true);
opts.read(true);
- let dir = File::open(p, &opts)?;
+ let dir = run_path_with_cstr(p, &|p| File::open_native(p, &opts))?;
Ok(ReadDir::new(dir, p.to_path_buf()))
}
-pub fn unlink(p: &Path) -> io::Result<()> {
+pub fn unlink(p: &CStr) -> io::Result<()> {
let (dir, file) = open_parent(p)?;
dir.unlink_file(osstr2str(file.as_ref())?)
}
-pub fn rename(old: &Path, new: &Path) -> io::Result<()> {
+pub fn rename(old: &CStr, new: &Path) -> io::Result<()> {
let (old, old_file) = open_parent(old)?;
- let (new, new_file) = open_parent(new)?;
+ let (new, new_file) = run_path_with_cstr(new, &|new| open_parent(new))?;
old.rename(osstr2str(old_file.as_ref())?, &new, osstr2str(new_file.as_ref())?)
}
@@ -584,12 +637,12 @@ pub fn set_perm(_p: &Path, _perm: FilePermissions) -> io::Result<()> {
unsupported()
}
-pub fn rmdir(p: &Path) -> io::Result<()> {
+pub fn rmdir(p: &CStr) -> io::Result<()> {
let (dir, file) = open_parent(p)?;
dir.remove_directory(osstr2str(file.as_ref())?)
}
-pub fn readlink(p: &Path) -> io::Result<PathBuf> {
+pub fn readlink(p: &CStr) -> io::Result<PathBuf> {
let (dir, file) = open_parent(p)?;
read_link(&dir, &file)
}
@@ -625,24 +678,24 @@ fn read_link(fd: &WasiFd, file: &Path) -> io::Result<PathBuf> {
}
}
-pub fn symlink(original: &Path, link: &Path) -> io::Result<()> {
+pub fn symlink(original: &Path, link: &CStr) -> io::Result<()> {
let (link, link_file) = open_parent(link)?;
link.symlink(osstr2str(original.as_ref())?, osstr2str(link_file.as_ref())?)
}
-pub fn link(original: &Path, link: &Path) -> io::Result<()> {
+pub fn link(original: &CStr, link: &Path) -> io::Result<()> {
let (original, original_file) = open_parent(original)?;
- let (link, link_file) = open_parent(link)?;
+ let (link, link_file) = run_path_with_cstr(link, &|link| open_parent(link))?;
// Pass 0 as the flags argument, meaning don't follow symlinks.
original.link(0, osstr2str(original_file.as_ref())?, &link, osstr2str(link_file.as_ref())?)
}
-pub fn stat(p: &Path) -> io::Result<FileAttr> {
+pub fn stat(p: &CStr) -> io::Result<FileAttr> {
let (dir, file) = open_parent(p)?;
metadata_at(&dir, wasi::LOOKUPFLAGS_SYMLINK_FOLLOW, &file)
}
-pub fn lstat(p: &Path) -> io::Result<FileAttr> {
+pub fn lstat(p: &CStr) -> io::Result<FileAttr> {
let (dir, file) = open_parent(p)?;
metadata_at(&dir, 0, &file)
}
@@ -697,53 +750,51 @@ fn open_at(fd: &WasiFd, path: &Path, opts: &OpenOptions) -> io::Result<File> {
///
/// Note that this can fail if `p` doesn't look like it can be opened relative
/// to any pre-opened file descriptor.
-fn open_parent(p: &Path) -> io::Result<(ManuallyDrop<WasiFd>, PathBuf)> {
- run_path_with_cstr(p, &|p| {
- let mut buf = Vec::<u8>::with_capacity(512);
- loop {
- unsafe {
- let mut relative_path = buf.as_ptr().cast();
- let mut abs_prefix = ptr::null();
- let fd = __wasilibc_find_relpath(
- p.as_ptr(),
- &mut abs_prefix,
- &mut relative_path,
- buf.capacity(),
- );
- if fd == -1 {
- if io::Error::last_os_error().raw_os_error() == Some(libc::ENOMEM) {
- // Trigger the internal buffer resizing logic of `Vec` by requiring
- // more space than the current capacity.
- let cap = buf.capacity();
- buf.set_len(cap);
- buf.reserve(1);
- continue;
- }
- let msg = format!(
- "failed to find a pre-opened file descriptor \
- through which {:?} could be opened",
- p
- );
- return Err(io::Error::new(io::ErrorKind::Uncategorized, msg));
+fn open_parent(p: &CStr) -> io::Result<(ManuallyDrop<WasiFd>, PathBuf)> {
+ let mut buf = Vec::<u8>::with_capacity(512);
+ loop {
+ unsafe {
+ let mut relative_path = buf.as_ptr().cast();
+ let mut abs_prefix = ptr::null();
+ let fd = __wasilibc_find_relpath(
+ p.as_ptr(),
+ &mut abs_prefix,
+ &mut relative_path,
+ buf.capacity(),
+ );
+ if fd == -1 {
+ if io::Error::last_os_error().raw_os_error() == Some(libc::ENOMEM) {
+ // Trigger the internal buffer resizing logic of `Vec` by requiring
+ // more space than the current capacity.
+ let cap = buf.capacity();
+ buf.set_len(cap);
+ buf.reserve(1);
+ continue;
}
- let relative = CStr::from_ptr(relative_path).to_bytes().to_vec();
-
- return Ok((
- ManuallyDrop::new(WasiFd::from_raw_fd(fd as c_int)),
- PathBuf::from(OsString::from_vec(relative)),
- ));
+ let msg = format!(
+ "failed to find a pre-opened file descriptor \
+ through which {:?} could be opened",
+ p
+ );
+ return Err(io::Error::new(io::ErrorKind::Uncategorized, msg));
}
- }
+ let relative = CStr::from_ptr(relative_path).to_bytes().to_vec();
- extern "C" {
- pub fn __wasilibc_find_relpath(
- path: *const libc::c_char,
- abs_prefix: *mut *const libc::c_char,
- relative_path: *mut *const libc::c_char,
- relative_path_len: libc::size_t,
- ) -> libc::c_int;
+ return Ok((
+ ManuallyDrop::new(WasiFd::from_raw_fd(fd as c_int)),
+ PathBuf::from(OsString::from_vec(relative)),
+ ));
}
- })
+ }
+
+ extern "C" {
+ pub fn __wasilibc_find_relpath(
+ path: *const libc::c_char,
+ abs_prefix: *mut *const libc::c_char,
+ relative_path: *mut *const libc::c_char,
+ relative_path_len: libc::size_t,
+ ) -> libc::c_int;
+ }
}
pub fn osstr2str(f: &OsStr) -> io::Result<&str> {
@@ -761,7 +812,7 @@ pub fn copy(from: &Path, to: &Path) -> io::Result<u64> {
}
pub fn remove_dir_all(path: &Path) -> io::Result<()> {
- let (parent, path) = open_parent(path)?;
+ let (parent, path) = run_path_with_cstr(path, &|path| open_parent(path))?;
remove_dir_all_recursive(&parent, &path)
}
diff --git a/library/std/src/sys/pal/windows/fs.rs b/library/std/src/sys/pal/windows/fs.rs
index 3a9e7b4660b36..fbac36f2edf23 100644
--- a/library/std/src/sys/pal/windows/fs.rs
+++ b/library/std/src/sys/pal/windows/fs.rs
@@ -11,6 +11,7 @@ use crate::ptr;
use crate::slice;
use crate::sync::Arc;
use crate::sys::handle::Handle;
+use crate::sys::path::NativePath;
use crate::sys::time::SystemTime;
use crate::sys::{c, cvt, Align8};
use crate::sys_common::{AsInner, FromInner, IntoInner};
@@ -19,6 +20,60 @@ use crate::thread;
use super::{api, to_u16s, IoResult};
use crate::sys::path::maybe_verbatim;
+/// The crate-public interface
+pub(crate) mod fs_imp {
+ use crate::io;
+ use crate::path::AsPath;
+ use crate::path::PathBuf;
+ use crate::sys::fs;
+ pub(crate) use crate::sys::fs::{
+ DirBuilder, DirEntry, File, FileAttr, FilePermissions, FileTimes, FileType, OpenOptions,
+ ReadDir,
+ };
+ pub(crate) fn remove_file<P: AsPath>(path: P) -> io::Result<()> {
+ path.with_path(fs::unlink)
+ }
+ pub(crate) fn symlink_metadata<P: AsPath>(path: P) -> io::Result<FileAttr> {
+ path.with_native_path(fs::lstat)
+ }
+ pub(crate) fn metadata<P: AsPath>(path: P) -> io::Result<FileAttr> {
+ path.with_native_path(fs::stat)
+ }
+ pub(crate) fn rename<P: AsPath, Q: AsPath>(from: P, to: Q) -> io::Result<()> {
+ from.with_path(|from| to.with_path(|to| fs::rename(from, to)))
+ }
+ pub(crate) fn hard_link<P: AsPath, Q: AsPath>(original: P, link: Q) -> io::Result<()> {
+ original.with_path(|original| link.with_path(|link| fs::link(original, link)))
+ }
+ pub(crate) fn soft_link<P: AsPath, Q: AsPath>(original: P, link: Q) -> io::Result<()> {
+ original.with_path(|original| link.with_path(|link| fs::symlink(original, link)))
+ }
+ pub(crate) fn remove_dir<P: AsPath>(path: P) -> io::Result<()> {
+ path.with_path(fs::rmdir)
+ }
+ pub(crate) fn read_dir<P: AsPath>(path: P) -> io::Result<ReadDir> {
+ path.with_path(fs::readdir)
+ }
+ pub(crate) fn set_permissions<P: AsPath>(path: P, perms: FilePermissions) -> io::Result<()> {
+ path.with_path(|path| fs::set_perm(path, perms))
+ }
+ pub(crate) fn copy<P: AsPath, Q: AsPath>(from: P, to: Q) -> io::Result<u64> {
+ from.with_path(|from| to.with_path(|to| fs::copy(from, to)))
+ }
+ pub(crate) fn canonicalize<P: AsPath>(path: P) -> io::Result<PathBuf> {
+ path.with_native_path(fs::canonicalize)
+ }
+ pub(crate) fn remove_dir_all<P: AsPath>(path: P) -> io::Result<()> {
+ path.with_native_path(fs::remove_dir_all)
+ }
+ pub(crate) fn read_link<P: AsPath>(path: P) -> io::Result<PathBuf> {
+ path.with_native_path(fs::readlink)
+ }
+ pub(crate) fn try_exists<P: AsPath>(path: P) -> io::Result<bool> {
+ path.with_native_path(fs::try_exists)
+ }
+}
+
pub struct File {
handle: Handle,
}
@@ -294,8 +349,7 @@ impl OpenOptions {
}
impl File {
- pub fn open(path: &Path, opts: &OpenOptions) -> io::Result<File> {
- let path = maybe_verbatim(path)?;
+ pub fn open_native(path: &NativePath, opts: &OpenOptions) -> io::Result<File> {
let creation = opts.get_creation_mode()?;
let handle = unsafe {
c::CreateFileW(
@@ -1132,16 +1186,16 @@ pub fn rmdir(p: &Path) -> io::Result<()> {
}
/// Open a file or directory without following symlinks.
-fn open_link(path: &Path, access_mode: u32) -> io::Result<File> {
+fn open_link(path: &NativePath, access_mode: u32) -> io::Result<File> {
let mut opts = OpenOptions::new();
opts.access_mode(access_mode);
// `FILE_FLAG_BACKUP_SEMANTICS` allows opening directories.
// `FILE_FLAG_OPEN_REPARSE_POINT` opens a link instead of its target.
opts.custom_flags(c::FILE_FLAG_BACKUP_SEMANTICS | c::FILE_FLAG_OPEN_REPARSE_POINT);
- File::open(path, &opts)
+ File::open_native(path, &opts)
}
-pub fn remove_dir_all(path: &Path) -> io::Result<()> {
+pub fn remove_dir_all(path: &NativePath) -> io::Result<()> {
let file = open_link(path, c::DELETE | c::FILE_LIST_DIRECTORY)?;
// Test if the file is not a directory or a symlink to a directory.
@@ -1241,14 +1295,14 @@ fn remove_dir_all_iterative(f: &File, delete: fn(&File) -> io::Result<()>) -> io
Ok(())
}
-pub fn readlink(path: &Path) -> io::Result<PathBuf> {
+pub fn readlink(path: &NativePath) -> io::Result<PathBuf> {
// Open the link with no access mode, instead of generic read.
// By default FILE_LIST_DIRECTORY is denied for the junction "C:\Documents and Settings", so
// this is needed for a common case.
let mut opts = OpenOptions::new();
opts.access_mode(0);
opts.custom_flags(c::FILE_FLAG_OPEN_REPARSE_POINT | c::FILE_FLAG_BACKUP_SEMANTICS);
- let file = File::open(path, &opts)?;
+ let file = File::open_native(path, &opts)?;
file.readlink()
}
@@ -1301,7 +1355,7 @@ pub fn link(_original: &Path, _link: &Path) -> io::Result<()> {
));
}
-pub fn stat(path: &Path) -> io::Result<FileAttr> {
+pub fn stat(path: &NativePath) -> io::Result<FileAttr> {
match metadata(path, ReparsePoint::Follow) {
Err(err) if err.raw_os_error() == Some(c::ERROR_CANT_ACCESS_FILE as i32) => {
if let Ok(attrs) = lstat(path) {
@@ -1315,7 +1369,7 @@ pub fn stat(path: &Path) -> io::Result<FileAttr> {
}
}
-pub fn lstat(path: &Path) -> io::Result<FileAttr> {
+pub fn lstat(path: &NativePath) -> io::Result<FileAttr> {
metadata(path, ReparsePoint::Open)
}
@@ -1331,7 +1385,7 @@ impl ReparsePoint {
}
}
-fn metadata(path: &Path, reparse: ReparsePoint) -> io::Result<FileAttr> {
+fn metadata(path: &NativePath, reparse: ReparsePoint) -> io::Result<FileAttr> {
let mut opts = OpenOptions::new();
// No read or write permissions are necessary
opts.access_mode(0);
@@ -1340,7 +1394,7 @@ fn metadata(path: &Path, reparse: ReparsePoint) -> io::Result<FileAttr> {
// Attempt to open the file normally.
// If that fails with `ERROR_SHARING_VIOLATION` then retry using `FindFirstFileW`.
// If the fallback fails for any reason we return the original error.
- match File::open(path, &opts) {
+ match File::open_native(path, &opts) {
Ok(file) => file.file_attr(),
Err(e)
if [Some(c::ERROR_SHARING_VIOLATION as _), Some(c::ERROR_ACCESS_DENIED as _)]
@@ -1353,8 +1407,6 @@ fn metadata(path: &Path, reparse: ReparsePoint) -> io::Result<FileAttr> {
// However, there are special system files, such as
// `C:\hiberfil.sys`, that are locked in a way that denies even that.
unsafe {
- let path = maybe_verbatim(path)?;
-
// `FindFirstFileW` accepts wildcard file names.
// Fortunately wildcards are not valid file names and
// `ERROR_SHARING_VIOLATION` means the file exists (but is locked)
@@ -1403,13 +1455,13 @@ fn get_path(f: &File) -> io::Result<PathBuf> {
)
}
-pub fn canonicalize(p: &Path) -> io::Result<PathBuf> {
+pub fn canonicalize(p: &NativePath) -> io::Result<PathBuf> {
let mut opts = OpenOptions::new();
// No read or write permissions are necessary
opts.access_mode(0);
// This flag is so we can open directories too
opts.custom_flags(c::FILE_FLAG_BACKUP_SEMANTICS);
- let f = File::open(p, &opts)?;
+ let f = File::open_native(p, &opts)?;
get_path(&f)
}
@@ -1467,7 +1519,7 @@ fn symlink_junction_inner(original: &Path, junction: &Path) -> io::Result<()> {
let mut opts = OpenOptions::new();
opts.write(true);
opts.custom_flags(c::FILE_FLAG_OPEN_REPARSE_POINT | c::FILE_FLAG_BACKUP_SEMANTICS);
- let f = File::open(junction, &opts)?;
+ let f = File::open_native(&maybe_verbatim(junction)?, &opts)?;
let h = f.as_inner().as_raw_handle();
unsafe {
let mut data =
@@ -1525,14 +1577,14 @@ fn symlink_junction_inner(original: &Path, junction: &Path) -> io::Result<()> {
}
// Try to see if a file exists but, unlike `exists`, report I/O errors.
-pub fn try_exists(path: &Path) -> io::Result<bool> {
+pub fn try_exists(path: &NativePath) -> io::Result<bool> {
// Open the file to ensure any symlinks are followed to their target.
let mut opts = OpenOptions::new();
// No read, write, etc access rights are needed.
opts.access_mode(0);
// Backup semantics enables opening directories as well as files.
opts.custom_flags(c::FILE_FLAG_BACKUP_SEMANTICS);
- match File::open(path, &opts) {
+ match File::open_native(path, &opts) {
Err(e) => match e.kind() {
// The file definitely does not exist
io::ErrorKind::NotFound => Ok(false),
diff --git a/library/std/src/sys/pal/windows/pipe.rs b/library/std/src/sys/pal/windows/pipe.rs
index 013f588676ae8..99b5a91960ac8 100644
--- a/library/std/src/sys/pal/windows/pipe.rs
+++ b/library/std/src/sys/pal/windows/pipe.rs
@@ -3,7 +3,6 @@ use crate::os::windows::prelude::*;
use crate::ffi::OsStr;
use crate::io::{self, BorrowedCursor, IoSlice, IoSliceMut, Read};
use crate::mem;
-use crate::path::Path;
use crate::ptr;
use crate::slice;
use crate::sync::atomic::AtomicUsize;
@@ -12,6 +11,7 @@ use crate::sys::c;
use crate::sys::fs::{File, OpenOptions};
use crate::sys::handle::Handle;
use crate::sys::hashmap_random_keys;
+use crate::sys::path::NativePathBuf;
use crate::sys_common::{FromInner, IntoInner};
////////////////////////////////////////////////////////////////////////////////
@@ -161,7 +161,8 @@ pub fn anon_pipe(ours_readable: bool, their_handle_inheritable: bool) -> io::Res
bInheritHandle: their_handle_inheritable as i32,
};
opts.security_attributes(&mut sa);
- let theirs = File::open(Path::new(&name), &opts)?;
+ let path = NativePathBuf::from_os_str(&name)?;
+ let theirs = File::open_native(&path, &opts)?;
let theirs = AnonPipe { inner: theirs.into_inner() };
Ok(Pipes {
diff --git a/library/std/src/sys/pal/windows/process.rs b/library/std/src/sys/pal/windows/process.rs
index e4ab2ca7da1ce..c3ecf87024290 100644
--- a/library/std/src/sys/pal/windows/process.rs
+++ b/library/std/src/sys/pal/windows/process.rs
@@ -23,7 +23,7 @@ use crate::sys::c::{self, NonZeroDWORD, EXIT_FAILURE, EXIT_SUCCESS};
use crate::sys::cvt;
use crate::sys::fs::{File, OpenOptions};
use crate::sys::handle::Handle;
-use crate::sys::path;
+use crate::sys::path::{self, NativePathBuf};
use crate::sys::pipe::{self, AnonPipe};
use crate::sys::stdio;
use crate::sys_common::process::{CommandEnv, CommandEnvs};
@@ -597,7 +597,8 @@ impl Stdio {
opts.read(stdio_id == c::STD_INPUT_HANDLE);
opts.write(stdio_id != c::STD_INPUT_HANDLE);
opts.security_attributes(&mut sa);
- File::open(Path::new(r"\\.\NUL"), &opts).map(|file| file.into_inner())
+ File::open_native(&NativePathBuf::from_os_str(r"\\.\NUL")?, &opts)
+ .map(|file| file.into_inner())
}
}
}
diff --git a/library/std/src/sys/path/cstr_native.rs b/library/std/src/sys/path/cstr_native.rs
new file mode 100644
index 0000000000000..f983bd1434277
--- /dev/null
+++ b/library/std/src/sys/path/cstr_native.rs
@@ -0,0 +1,35 @@
+use crate::ffi::CStr;
+use crate::io;
+use crate::mem;
+use crate::path::{AsPath, Path};
+use crate::sys::common::small_c_string::run_path_with_cstr;
+
+pub type NativePath = CStr;
+
+#[unstable(feature = "fs_native_path_internals", issue = "none")]
+impl<P: AsRef<Path>> AsPath for P {
+ #[doc(hidden)]
+ fn with_path<T, F: FnOnce(&Path) -> io::Result<T>>(self, f: F) -> io::Result<T> {
+ f(self.as_ref())
+ }
+ #[doc(hidden)]
+ fn with_native_path<T, F: Fn(&NativePath) -> io::Result<T>>(self, f: F) -> io::Result<T> {
+ run_path_with_cstr(self.as_ref(), &f)
+ }
+}
+
+#[unstable(feature = "fs_native_path_internals", issue = "none")]
+impl AsPath for &crate::path::NativePath {
+ #[doc(hidden)]
+ fn with_path<T, F: FnOnce(&Path) -> io::Result<T>>(self, f: F) -> io::Result<T> {
+ // SAFETY: OsStr is a byte slice on platforms with CStr paths.
+ // Note: We can't use os::unix::OsStrExt because that isn't necessarily
+ // available for all platforms that use CStr paths.
+ let osstr: &Path = unsafe { mem::transmute(self.0.to_bytes()) };
+ f(osstr)
+ }
+ #[doc(hidden)]
+ fn with_native_path<T, F: Fn(&NativePath) -> io::Result<T>>(self, f: F) -> io::Result<T> {
+ f(&self.0)
+ }
+}
diff --git a/library/std/src/sys/path/mod.rs b/library/std/src/sys/path/mod.rs
index 24a94ec782824..000e706db70f9 100644
--- a/library/std/src/sys/path/mod.rs
+++ b/library/std/src/sys/path/mod.rs
@@ -1,3 +1,10 @@
+cfg_if::cfg_if! {
+ if #[cfg(not(target_os = "windows"))] {
+ mod cstr_native;
+ pub use cstr_native::NativePath;
+ }
+}
+
cfg_if::cfg_if! {
if #[cfg(target_os = "windows")] {
mod windows;
diff --git a/library/std/src/sys/path/windows.rs b/library/std/src/sys/path/windows.rs
index cebc791023115..91269057cb51b 100644
--- a/library/std/src/sys/path/windows.rs
+++ b/library/std/src/sys/path/windows.rs
@@ -1,6 +1,6 @@
use crate::ffi::{OsStr, OsString};
use crate::io;
-use crate::path::{Path, PathBuf, Prefix};
+use crate::path::{AsPath, Path, PathBuf, Prefix};
use crate::ptr;
use crate::sys::pal::{c, fill_utf16_buf, os2path, to_u16s};
@@ -10,6 +10,59 @@ mod tests;
pub const MAIN_SEP_STR: &str = "\\";
pub const MAIN_SEP: char = '\\';
+pub(crate) struct NativePathBuf(pub Vec<u16>);
+impl NativePathBuf {
+ pub fn from_os_str<S: AsRef<OsStr>>(path: S) -> io::Result<Self> {
+ to_u16s(path).map(Self)
+ }
+}
+impl core::ops::Deref for NativePathBuf {
+ type Target = NativePath;
+ fn deref(&self) -> &Self::Target {
+ unsafe { NativePath::new_unchecked(&self.0) }
+ }
+}
+
+/// A null-terminated `[u16]` string.
+#[unstable(feature = "fs_native_path_internals", issue = "none")]
+#[repr(transparent)]
+#[derive(Debug)]
+pub struct NativePath(pub [u16]);
+impl NativePath {
+ pub(crate) unsafe fn new_unchecked(native: &[u16]) -> &Self {
+ unsafe { &*(native as *const [u16] as *const Self) }
+ }
+ pub(crate) fn as_ptr(&self) -> *const u16 {
+ self.0.as_ptr()
+ }
+}
+
+#[unstable(feature = "fs_native_path_internals", issue = "none")]
+impl<P: AsRef<Path>> AsPath for P {
+ #[doc(hidden)]
+ fn with_path<T, F: FnOnce(&Path) -> io::Result<T>>(self, f: F) -> io::Result<T> {
+ f(self.as_ref())
+ }
+ #[doc(hidden)]
+ fn with_native_path<T, F: Fn(&NativePath) -> io::Result<T>>(self, f: F) -> io::Result<T> {
+ let path = maybe_verbatim(self.as_ref())?;
+ f(&path)
+ }
+}
+
+#[unstable(feature = "fs_native_path_internals", issue = "none")]
+impl AsPath for &crate::path::NativePath {
+ #[doc(hidden)]
+ fn with_path<T, F: FnOnce(&Path) -> io::Result<T>>(self, f: F) -> io::Result<T> {
+ let path = os2path(&self.0.0[..self.0.0.len().saturating_sub(1)]);
+ f(&path)
+ }
+ #[doc(hidden)]
+ fn with_native_path<T, F: Fn(&NativePath) -> io::Result<T>>(self, f: F) -> io::Result<T> {
+ f(&self.0)
+ }
+}
+
#[inline]
pub fn is_sep_byte(b: u8) -> bool {
b == b'/' || b == b'\\'
@@ -213,9 +266,9 @@ fn parse_next_component(path: &OsStr, verbatim: bool) -> (&OsStr, &OsStr) {
/// Returns a UTF-16 encoded path capable of bypassing the legacy `MAX_PATH` limits.
///
/// This path may or may not have a verbatim prefix.
-pub(crate) fn maybe_verbatim(path: &Path) -> io::Result<Vec<u16>> {
+pub(crate) fn maybe_verbatim(path: &Path) -> io::Result<NativePathBuf> {
let path = to_u16s(path)?;
- get_long_path(path, true)
+ get_long_path(path, true).map(NativePathBuf)
}
/// Get a normalized absolute path that can bypass path length limits.
diff --git a/library/std/src/sys/path/windows/tests.rs b/library/std/src/sys/path/windows/tests.rs
index 623c6236166da..05c459536d636 100644
--- a/library/std/src/sys/path/windows/tests.rs
+++ b/library/std/src/sys/path/windows/tests.rs
@@ -38,7 +38,7 @@ fn verbatim() {
use crate::path::Path;
fn check(path: &str, expected: &str) {
let verbatim = maybe_verbatim(Path::new(path)).unwrap();
- let verbatim = String::from_utf16_lossy(verbatim.strip_suffix(&[0]).unwrap());
+ let verbatim = String::from_utf16_lossy(verbatim.0.strip_suffix(&[0]).unwrap());
assert_eq!(&verbatim, expected, "{}", path);
}
diff --git a/src/tools/miri/tests/fail/shims/fs/isolated_file.stderr b/src/tools/miri/tests/fail/shims/fs/isolated_file.stderr
index 1f08649428a4c..1b0e74912e61d 100644
--- a/src/tools/miri/tests/fail/shims/fs/isolated_file.stderr
+++ b/src/tools/miri/tests/fail/shims/fs/isolated_file.stderr
@@ -8,15 +8,15 @@ LL | let fd = cvt_r(|| unsafe { open64(path.as_ptr(), flags, opts.mode a
= help: or pass `-Zmiri-isolation-error=warn` to configure Miri to return an error code from isolated operations (if supported for that operation) and continue with a warning
= note: BACKTRACE:
= note: inside closure at RUSTLIB/std/src/sys/pal/PLATFORM/fs.rs:LL:CC
- = note: inside `std::sys::pal::PLATFORM::cvt_r::<i32, {closure@std::sys::pal::PLATFORM::fs::File::open_c::{closure#0}}>` at RUSTLIB/std/src/sys/pal/PLATFORM/mod.rs:LL:CC
- = note: inside `std::sys::pal::PLATFORM::fs::File::open_c` at RUSTLIB/std/src/sys/pal/PLATFORM/fs.rs:LL:CC
- = note: inside closure at RUSTLIB/std/src/sys/pal/PLATFORM/fs.rs:LL:CC
- = note: inside `std::sys::pal::PLATFORM::small_c_string::run_with_cstr_stack::<std::sys::pal::PLATFORM::fs::File>` at RUSTLIB/std/src/sys/pal/PLATFORM/small_c_string.rs:LL:CC
- = note: inside `std::sys::pal::PLATFORM::small_c_string::run_with_cstr::<std::sys::pal::PLATFORM::fs::File>` at RUSTLIB/std/src/sys/pal/PLATFORM/small_c_string.rs:LL:CC
- = note: inside `std::sys::pal::PLATFORM::small_c_string::run_path_with_cstr::<std::sys::pal::PLATFORM::fs::File>` at RUSTLIB/std/src/sys/pal/PLATFORM/small_c_string.rs:LL:CC
- = note: inside `std::sys::pal::PLATFORM::fs::File::open` at RUSTLIB/std/src/sys/pal/PLATFORM/fs.rs:LL:CC
+ = note: inside `std::sys::pal::PLATFORM::cvt_r::<i32, {closure@std::sys::pal::PLATFORM::fs::File::open_native::{closure#0}}>` at RUSTLIB/std/src/sys/pal/PLATFORM/mod.rs:LL:CC
+ = note: inside `std::sys::pal::PLATFORM::fs::File::open_native` at RUSTLIB/std/src/sys/pal/PLATFORM/fs.rs:LL:CC
= note: inside `std::fs::OpenOptions::_open` at RUSTLIB/std/src/fs.rs:LL:CC
- = note: inside `std::fs::OpenOptions::open::<&std::path::Path>` at RUSTLIB/std/src/fs.rs:LL:CC
+ = note: inside closure at RUSTLIB/std/src/fs.rs:LL:CC
+ = note: inside `std::sys::pal::PLATFORM::small_c_string::run_with_cstr_stack::<std::fs::File>` at RUSTLIB/std/src/sys/pal/PLATFORM/small_c_string.rs:LL:CC
+ = note: inside `std::sys::pal::PLATFORM::small_c_string::run_with_cstr::<std::fs::File>` at RUSTLIB/std/src/sys/pal/PLATFORM/small_c_string.rs:LL:CC
+ = note: inside `std::sys::pal::PLATFORM::small_c_string::run_path_with_cstr::<std::fs::File>` at RUSTLIB/std/src/sys/pal/PLATFORM/small_c_string.rs:LL:CC
+ = note: inside `std::sys::path::cstr_native::<impl std::path::AsPath for &str>::with_native_path::<std::fs::File, {closure@std::fs::OpenOptions::open<&str>::{closure#0}}>` at RUSTLIB/std/src/sys/path/cstr_native.rs:LL:CC
+ = note: inside `std::fs::OpenOptions::open::<&str>` at RUSTLIB/std/src/fs.rs:LL:CC
= note: inside `std::fs::File::open::<&str>` at RUSTLIB/std/src/fs.rs:LL:CC
note: inside `main`
--> $DIR/isolated_file.rs:LL:CC
diff --git a/tests/ui/async-await/issue-72442.stderr b/tests/ui/async-await/issue-72442.stderr
index e68f7a299908f..f559b72f68330 100644
--- a/tests/ui/async-await/issue-72442.stderr
+++ b/tests/ui/async-await/issue-72442.stderr
@@ -1,11 +1,13 @@
-error[E0277]: the trait bound `Option<&str>: AsRef<Path>` is not satisfied
+error[E0277]: the trait bound `Option<&str>: AsPath` is not satisfied
--> $DIR/issue-72442.rs:12:36
|
LL | let mut f = File::open(path.to_str())?;
- | ---------- ^^^^^^^^^^^^^ the trait `AsRef<Path>` is not implemented for `Option<&str>`
+ | ---------- ^^^^^^^^^^^^^ the trait `AsRef<Path>` is not implemented for `Option<&str>`, which is required by `Option<&str>: AsPath`
| |
| required by a bound introduced by this call
|
+ = help: the trait `AsPath` is implemented for `&NativePath`
+ = note: required for `Option<&str>` to implement `AsPath`
note: required by a bound in `File::open`
--> $SRC_DIR/std/src/fs.rs:LL:COL
help: consider removing this method call, as the receiver has type `&Path` and `&Path: AsRef<Path>` trivially holds