Skip to content
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.

Commit b7e9898

Browse files
committedMar 22, 2025··
Start using with_native_path in std::sys::fs
1 parent db68788 commit b7e9898

File tree

4 files changed

+180
-118
lines changed

4 files changed

+180
-118
lines changed
 

‎library/std/src/fs.rs

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -2362,7 +2362,7 @@ impl AsInner<fs_imp::DirEntry> for DirEntry {
23622362
#[doc(alias = "rm", alias = "unlink", alias = "DeleteFile")]
23632363
#[stable(feature = "rust1", since = "1.0.0")]
23642364
pub fn remove_file<P: AsRef<Path>>(path: P) -> io::Result<()> {
2365-
fs_imp::unlink(path.as_ref())
2365+
fs_imp::remove_file(path.as_ref())
23662366
}
23672367

23682368
/// Given a path, queries the file system to get information about a file,
@@ -2401,7 +2401,7 @@ pub fn remove_file<P: AsRef<Path>>(path: P) -> io::Result<()> {
24012401
#[doc(alias = "stat")]
24022402
#[stable(feature = "rust1", since = "1.0.0")]
24032403
pub fn metadata<P: AsRef<Path>>(path: P) -> io::Result<Metadata> {
2404-
fs_imp::stat(path.as_ref()).map(Metadata)
2404+
fs_imp::metadata(path.as_ref()).map(Metadata)
24052405
}
24062406

24072407
/// Queries the metadata about a file without following symlinks.
@@ -2436,7 +2436,7 @@ pub fn metadata<P: AsRef<Path>>(path: P) -> io::Result<Metadata> {
24362436
#[doc(alias = "lstat")]
24372437
#[stable(feature = "symlink_metadata", since = "1.1.0")]
24382438
pub fn symlink_metadata<P: AsRef<Path>>(path: P) -> io::Result<Metadata> {
2439-
fs_imp::lstat(path.as_ref()).map(Metadata)
2439+
fs_imp::symlink_metadata(path.as_ref()).map(Metadata)
24402440
}
24412441

24422442
/// Renames a file or directory to a new name, replacing the original file if
@@ -2590,7 +2590,7 @@ pub fn copy<P: AsRef<Path>, Q: AsRef<Path>>(from: P, to: Q) -> io::Result<u64> {
25902590
#[doc(alias = "CreateHardLink", alias = "linkat")]
25912591
#[stable(feature = "rust1", since = "1.0.0")]
25922592
pub fn hard_link<P: AsRef<Path>, Q: AsRef<Path>>(original: P, link: Q) -> io::Result<()> {
2593-
fs_imp::link(original.as_ref(), link.as_ref())
2593+
fs_imp::hard_link(original.as_ref(), link.as_ref())
25942594
}
25952595

25962596
/// Creates a new symbolic link on the filesystem.
@@ -2622,7 +2622,7 @@ pub fn hard_link<P: AsRef<Path>, Q: AsRef<Path>>(original: P, link: Q) -> io::Re
26222622
std::os::windows::fs::{symlink_file, symlink_dir}"
26232623
)]
26242624
pub fn soft_link<P: AsRef<Path>, Q: AsRef<Path>>(original: P, link: Q) -> io::Result<()> {
2625-
fs_imp::symlink(original.as_ref(), link.as_ref())
2625+
fs_imp::soft_link(original.as_ref(), link.as_ref())
26262626
}
26272627

26282628
/// Reads a symbolic link, returning the file that the link points to.
@@ -2656,7 +2656,7 @@ pub fn soft_link<P: AsRef<Path>, Q: AsRef<Path>>(original: P, link: Q) -> io::Re
26562656
/// ```
26572657
#[stable(feature = "rust1", since = "1.0.0")]
26582658
pub fn read_link<P: AsRef<Path>>(path: P) -> io::Result<PathBuf> {
2659-
fs_imp::readlink(path.as_ref())
2659+
fs_imp::read_link(path.as_ref())
26602660
}
26612661

26622662
/// Returns the canonical, absolute form of a path with all intermediate
@@ -2832,7 +2832,7 @@ pub fn create_dir_all<P: AsRef<Path>>(path: P) -> io::Result<()> {
28322832
#[doc(alias = "rmdir", alias = "RemoveDirectory")]
28332833
#[stable(feature = "rust1", since = "1.0.0")]
28342834
pub fn remove_dir<P: AsRef<Path>>(path: P) -> io::Result<()> {
2835-
fs_imp::rmdir(path.as_ref())
2835+
fs_imp::remove_dir(path.as_ref())
28362836
}
28372837

28382838
/// Removes a directory at this path, after removing all its contents. Use
@@ -2959,7 +2959,7 @@ pub fn remove_dir_all<P: AsRef<Path>>(path: P) -> io::Result<()> {
29592959
#[doc(alias = "ls", alias = "opendir", alias = "FindFirstFile", alias = "FindNextFile")]
29602960
#[stable(feature = "rust1", since = "1.0.0")]
29612961
pub fn read_dir<P: AsRef<Path>>(path: P) -> io::Result<ReadDir> {
2962-
fs_imp::readdir(path.as_ref()).map(ReadDir)
2962+
fs_imp::read_dir(path.as_ref()).map(ReadDir)
29632963
}
29642964

29652965
/// Changes the permissions found on a file or a directory.
@@ -2995,7 +2995,7 @@ pub fn read_dir<P: AsRef<Path>>(path: P) -> io::Result<ReadDir> {
29952995
#[doc(alias = "chmod", alias = "SetFileAttributes")]
29962996
#[stable(feature = "set_permissions", since = "1.1.0")]
29972997
pub fn set_permissions<P: AsRef<Path>>(path: P, perm: Permissions) -> io::Result<()> {
2998-
fs_imp::set_perm(path.as_ref(), perm.0)
2998+
fs_imp::set_permissions(path.as_ref(), perm.0)
29992999
}
30003000

30013001
impl DirBuilder {

‎library/std/src/os/unix/fs.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -975,7 +975,7 @@ impl DirEntryExt2 for fs::DirEntry {
975975
/// ```
976976
#[stable(feature = "symlink", since = "1.1.0")]
977977
pub fn symlink<P: AsRef<Path>, Q: AsRef<Path>>(original: P, link: Q) -> io::Result<()> {
978-
sys::fs::symlink(original.as_ref(), link.as_ref())
978+
sys::fs::soft_link(original.as_ref(), link.as_ref())
979979
}
980980

981981
/// Unix-specific extensions to [`fs::DirBuilder`].

‎library/std/src/sys/fs/mod.rs

Lines changed: 91 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,28 +1,112 @@
11
#![deny(unsafe_op_in_unsafe_fn)]
22

3+
use crate::io;
4+
use crate::path::{Path, PathBuf};
5+
36
pub mod common;
47

58
cfg_if::cfg_if! {
69
if #[cfg(target_family = "unix")] {
710
mod unix;
8-
pub use unix::*;
11+
use unix as imp;
12+
pub use unix::{chown, fchown, lchown, chroot};
13+
pub(crate) use unix::debug_assert_fd_is_open;
14+
#[cfg(any(target_os = "linux", target_os = "android"))]
15+
pub(crate) use unix::CachedFileMetadata;
16+
use crate::sys::common::small_c_string::run_path_with_cstr as with_native_path;
917
} else if #[cfg(target_os = "windows")] {
1018
mod windows;
11-
pub use windows::*;
19+
use windows as imp;
20+
pub use windows::{symlink_inner, junction_point};
1221
} else if #[cfg(target_os = "hermit")] {
1322
mod hermit;
14-
pub use hermit::*;
23+
use hermit as imp;
1524
} else if #[cfg(target_os = "solid_asp3")] {
1625
mod solid;
17-
pub use solid::*;
26+
use solid as imp;
1827
} else if #[cfg(target_os = "uefi")] {
1928
mod uefi;
20-
pub use uefi::*;
29+
use uefi as imp;
2130
} else if #[cfg(target_os = "wasi")] {
2231
mod wasi;
23-
pub use wasi::*;
32+
use wasi as imp;
2433
} else {
2534
mod unsupported;
26-
pub use unsupported::*;
35+
use unsupported as imp;
2736
}
2837
}
38+
39+
// FIXME: Replace this with platform-specific path conversion functions.
40+
#[cfg(not(target_family = "unix"))]
41+
#[inline]
42+
pub fn with_native_path<T>(path: &Path, f: &dyn Fn(&Path) -> io::Result<T>) -> io::Result<T> {
43+
f(path)
44+
}
45+
46+
pub use imp::{
47+
DirBuilder, DirEntry, File, FileAttr, FilePermissions, FileTimes, FileType, OpenOptions,
48+
ReadDir,
49+
};
50+
51+
pub fn read_dir(path: &Path) -> io::Result<ReadDir> {
52+
// FIXME: use with_native_path
53+
imp::readdir(path)
54+
}
55+
56+
pub fn remove_file(path: &Path) -> io::Result<()> {
57+
with_native_path(path, &imp::unlink)
58+
}
59+
60+
pub fn rename(old: &Path, new: &Path) -> io::Result<()> {
61+
with_native_path(old, &|old| with_native_path(new, &|new| imp::rename(old, new)))
62+
}
63+
64+
pub fn remove_dir(path: &Path) -> io::Result<()> {
65+
with_native_path(path, &imp::rmdir)
66+
}
67+
68+
pub fn remove_dir_all(path: &Path) -> io::Result<()> {
69+
with_native_path(path, &imp::remove_dir_all)
70+
}
71+
72+
pub fn read_link(path: &Path) -> io::Result<PathBuf> {
73+
with_native_path(path, &imp::readlink)
74+
}
75+
76+
pub fn soft_link(original: &Path, link: &Path) -> io::Result<()> {
77+
with_native_path(original, &|original| {
78+
with_native_path(link, &|link| imp::symlink(original, link))
79+
})
80+
}
81+
82+
pub fn hard_link(original: &Path, link: &Path) -> io::Result<()> {
83+
with_native_path(original, &|original| {
84+
with_native_path(link, &|link| imp::link(original, link))
85+
})
86+
}
87+
88+
pub fn metadata(path: &Path) -> io::Result<FileAttr> {
89+
with_native_path(path, &imp::stat)
90+
}
91+
92+
pub fn symlink_metadata(path: &Path) -> io::Result<FileAttr> {
93+
with_native_path(path, &imp::lstat)
94+
}
95+
96+
pub fn set_permissions(path: &Path, perm: FilePermissions) -> io::Result<()> {
97+
with_native_path(path, &|path| imp::set_perm(path, perm.clone()))
98+
}
99+
100+
pub fn canonicalize(path: &Path) -> io::Result<PathBuf> {
101+
with_native_path(path, &imp::canonicalize)
102+
}
103+
104+
pub fn copy(from: &Path, to: &Path) -> io::Result<u64> {
105+
// FIXME: use with_native_path
106+
imp::copy(from, to)
107+
}
108+
109+
pub fn exists(path: &Path) -> io::Result<bool> {
110+
// FIXME: use with_native_path
111+
imp::exists(path)
112+
}

‎library/std/src/sys/fs/unix.rs

Lines changed: 79 additions & 101 deletions
Original file line numberDiff line numberDiff line change
@@ -926,7 +926,7 @@ impl DirEntry {
926926
miri
927927
))]
928928
pub fn metadata(&self) -> io::Result<FileAttr> {
929-
lstat(&self.path())
929+
run_path_with_cstr(&self.path(), &lstat)
930930
}
931931

932932
#[cfg(any(
@@ -1653,7 +1653,7 @@ impl fmt::Debug for File {
16531653
fn get_path(fd: c_int) -> Option<PathBuf> {
16541654
let mut p = PathBuf::from("/proc/self/fd");
16551655
p.push(&fd.to_string());
1656-
readlink(&p).ok()
1656+
run_path_with_cstr(&p, &readlink).ok()
16571657
}
16581658

16591659
#[cfg(any(target_vendor = "apple", target_os = "netbsd"))]
@@ -1826,127 +1826,106 @@ pub fn readdir(path: &Path) -> io::Result<ReadDir> {
18261826
}
18271827
}
18281828

1829-
pub fn unlink(p: &Path) -> io::Result<()> {
1830-
run_path_with_cstr(p, &|p| cvt(unsafe { libc::unlink(p.as_ptr()) }).map(|_| ()))
1829+
pub fn unlink(p: &CStr) -> io::Result<()> {
1830+
cvt(unsafe { libc::unlink(p.as_ptr()) }).map(|_| ())
18311831
}
18321832

1833-
pub fn rename(old: &Path, new: &Path) -> io::Result<()> {
1834-
run_path_with_cstr(old, &|old| {
1835-
run_path_with_cstr(new, &|new| {
1836-
cvt(unsafe { libc::rename(old.as_ptr(), new.as_ptr()) }).map(|_| ())
1837-
})
1838-
})
1833+
pub fn rename(old: &CStr, new: &CStr) -> io::Result<()> {
1834+
cvt(unsafe { libc::rename(old.as_ptr(), new.as_ptr()) }).map(|_| ())
18391835
}
18401836

1841-
pub fn set_perm(p: &Path, perm: FilePermissions) -> io::Result<()> {
1842-
run_path_with_cstr(p, &|p| cvt_r(|| unsafe { libc::chmod(p.as_ptr(), perm.mode) }).map(|_| ()))
1837+
pub fn set_perm(p: &CStr, perm: FilePermissions) -> io::Result<()> {
1838+
cvt_r(|| unsafe { libc::chmod(p.as_ptr(), perm.mode) }).map(|_| ())
18431839
}
18441840

1845-
pub fn rmdir(p: &Path) -> io::Result<()> {
1846-
run_path_with_cstr(p, &|p| cvt(unsafe { libc::rmdir(p.as_ptr()) }).map(|_| ()))
1841+
pub fn rmdir(p: &CStr) -> io::Result<()> {
1842+
cvt(unsafe { libc::rmdir(p.as_ptr()) }).map(|_| ())
18471843
}
18481844

1849-
pub fn readlink(p: &Path) -> io::Result<PathBuf> {
1850-
run_path_with_cstr(p, &|c_path| {
1851-
let p = c_path.as_ptr();
1852-
1853-
let mut buf = Vec::with_capacity(256);
1845+
pub fn readlink(c_path: &CStr) -> io::Result<PathBuf> {
1846+
let p = c_path.as_ptr();
18541847

1855-
loop {
1856-
let buf_read =
1857-
cvt(unsafe { libc::readlink(p, buf.as_mut_ptr() as *mut _, buf.capacity()) })?
1858-
as usize;
1848+
let mut buf = Vec::with_capacity(256);
18591849

1860-
unsafe {
1861-
buf.set_len(buf_read);
1862-
}
1850+
loop {
1851+
let buf_read =
1852+
cvt(unsafe { libc::readlink(p, buf.as_mut_ptr() as *mut _, buf.capacity()) })? as usize;
18631853

1864-
if buf_read != buf.capacity() {
1865-
buf.shrink_to_fit();
1854+
unsafe {
1855+
buf.set_len(buf_read);
1856+
}
18661857

1867-
return Ok(PathBuf::from(OsString::from_vec(buf)));
1868-
}
1858+
if buf_read != buf.capacity() {
1859+
buf.shrink_to_fit();
18691860

1870-
// Trigger the internal buffer resizing logic of `Vec` by requiring
1871-
// more space than the current capacity. The length is guaranteed to be
1872-
// the same as the capacity due to the if statement above.
1873-
buf.reserve(1);
1861+
return Ok(PathBuf::from(OsString::from_vec(buf)));
18741862
}
1875-
})
1863+
1864+
// Trigger the internal buffer resizing logic of `Vec` by requiring
1865+
// more space than the current capacity. The length is guaranteed to be
1866+
// the same as the capacity due to the if statement above.
1867+
buf.reserve(1);
1868+
}
18761869
}
18771870

1878-
pub fn symlink(original: &Path, link: &Path) -> io::Result<()> {
1879-
run_path_with_cstr(original, &|original| {
1880-
run_path_with_cstr(link, &|link| {
1881-
cvt(unsafe { libc::symlink(original.as_ptr(), link.as_ptr()) }).map(|_| ())
1882-
})
1883-
})
1871+
pub fn symlink(original: &CStr, link: &CStr) -> io::Result<()> {
1872+
cvt(unsafe { libc::symlink(original.as_ptr(), link.as_ptr()) }).map(|_| ())
18841873
}
18851874

1886-
pub fn link(original: &Path, link: &Path) -> io::Result<()> {
1887-
run_path_with_cstr(original, &|original| {
1888-
run_path_with_cstr(link, &|link| {
1889-
cfg_if::cfg_if! {
1890-
if #[cfg(any(target_os = "vxworks", target_os = "redox", target_os = "android", target_os = "espidf", target_os = "horizon", target_os = "vita", target_env = "nto70"))] {
1891-
// VxWorks, Redox and ESP-IDF lack `linkat`, so use `link` instead. POSIX leaves
1892-
// it implementation-defined whether `link` follows symlinks, so rely on the
1893-
// `symlink_hard_link` test in library/std/src/fs/tests.rs to check the behavior.
1894-
// Android has `linkat` on newer versions, but we happen to know `link`
1895-
// always has the correct behavior, so it's here as well.
1896-
cvt(unsafe { libc::link(original.as_ptr(), link.as_ptr()) })?;
1897-
} else {
1898-
// Where we can, use `linkat` instead of `link`; see the comment above
1899-
// this one for details on why.
1900-
cvt(unsafe { libc::linkat(libc::AT_FDCWD, original.as_ptr(), libc::AT_FDCWD, link.as_ptr(), 0) })?;
1901-
}
1902-
}
1903-
Ok(())
1904-
})
1905-
})
1875+
pub fn link(original: &CStr, link: &CStr) -> io::Result<()> {
1876+
cfg_if::cfg_if! {
1877+
if #[cfg(any(target_os = "vxworks", target_os = "redox", target_os = "android", target_os = "espidf", target_os = "horizon", target_os = "vita", target_env = "nto70"))] {
1878+
// VxWorks, Redox and ESP-IDF lack `linkat`, so use `link` instead. POSIX leaves
1879+
// it implementation-defined whether `link` follows symlinks, so rely on the
1880+
// `symlink_hard_link` test in library/std/src/fs/tests.rs to check the behavior.
1881+
// Android has `linkat` on newer versions, but we happen to know `link`
1882+
// always has the correct behavior, so it's here as well.
1883+
cvt(unsafe { libc::link(original.as_ptr(), link.as_ptr()) })?;
1884+
} else {
1885+
// Where we can, use `linkat` instead of `link`; see the comment above
1886+
// this one for details on why.
1887+
cvt(unsafe { libc::linkat(libc::AT_FDCWD, original.as_ptr(), libc::AT_FDCWD, link.as_ptr(), 0) })?;
1888+
}
1889+
}
1890+
Ok(())
19061891
}
19071892

1908-
pub fn stat(p: &Path) -> io::Result<FileAttr> {
1909-
run_path_with_cstr(p, &|p| {
1910-
cfg_has_statx! {
1911-
if let Some(ret) = unsafe { try_statx(
1912-
libc::AT_FDCWD,
1913-
p.as_ptr(),
1914-
libc::AT_STATX_SYNC_AS_STAT,
1915-
libc::STATX_BASIC_STATS | libc::STATX_BTIME,
1916-
) } {
1917-
return ret;
1918-
}
1893+
pub fn stat(p: &CStr) -> io::Result<FileAttr> {
1894+
cfg_has_statx! {
1895+
if let Some(ret) = unsafe { try_statx(
1896+
libc::AT_FDCWD,
1897+
p.as_ptr(),
1898+
libc::AT_STATX_SYNC_AS_STAT,
1899+
libc::STATX_BASIC_STATS | libc::STATX_BTIME,
1900+
) } {
1901+
return ret;
19191902
}
1903+
}
19201904

1921-
let mut stat: stat64 = unsafe { mem::zeroed() };
1922-
cvt(unsafe { stat64(p.as_ptr(), &mut stat) })?;
1923-
Ok(FileAttr::from_stat64(stat))
1924-
})
1905+
let mut stat: stat64 = unsafe { mem::zeroed() };
1906+
cvt(unsafe { stat64(p.as_ptr(), &mut stat) })?;
1907+
Ok(FileAttr::from_stat64(stat))
19251908
}
19261909

1927-
pub fn lstat(p: &Path) -> io::Result<FileAttr> {
1928-
run_path_with_cstr(p, &|p| {
1929-
cfg_has_statx! {
1930-
if let Some(ret) = unsafe { try_statx(
1931-
libc::AT_FDCWD,
1932-
p.as_ptr(),
1933-
libc::AT_SYMLINK_NOFOLLOW | libc::AT_STATX_SYNC_AS_STAT,
1934-
libc::STATX_BASIC_STATS | libc::STATX_BTIME,
1935-
) } {
1936-
return ret;
1937-
}
1910+
pub fn lstat(p: &CStr) -> io::Result<FileAttr> {
1911+
cfg_has_statx! {
1912+
if let Some(ret) = unsafe { try_statx(
1913+
libc::AT_FDCWD,
1914+
p.as_ptr(),
1915+
libc::AT_SYMLINK_NOFOLLOW | libc::AT_STATX_SYNC_AS_STAT,
1916+
libc::STATX_BASIC_STATS | libc::STATX_BTIME,
1917+
) } {
1918+
return ret;
19381919
}
1920+
}
19391921

1940-
let mut stat: stat64 = unsafe { mem::zeroed() };
1941-
cvt(unsafe { lstat64(p.as_ptr(), &mut stat) })?;
1942-
Ok(FileAttr::from_stat64(stat))
1943-
})
1922+
let mut stat: stat64 = unsafe { mem::zeroed() };
1923+
cvt(unsafe { lstat64(p.as_ptr(), &mut stat) })?;
1924+
Ok(FileAttr::from_stat64(stat))
19441925
}
19451926

1946-
pub fn canonicalize(p: &Path) -> io::Result<PathBuf> {
1947-
let r = run_path_with_cstr(p, &|path| unsafe {
1948-
Ok(libc::realpath(path.as_ptr(), ptr::null_mut()))
1949-
})?;
1927+
pub fn canonicalize(path: &CStr) -> io::Result<PathBuf> {
1928+
let r = unsafe { libc::realpath(path.as_ptr(), ptr::null_mut()) };
19501929
if r.is_null() {
19511930
return Err(io::Error::last_os_error());
19521931
}
@@ -2202,8 +2181,7 @@ mod remove_dir_impl {
22022181
use crate::io;
22032182
use crate::os::unix::io::{AsRawFd, FromRawFd, IntoRawFd};
22042183
use crate::os::unix::prelude::{OwnedFd, RawFd};
2205-
use crate::path::{Path, PathBuf};
2206-
use crate::sys::common::small_c_string::run_path_with_cstr;
2184+
use crate::path::PathBuf;
22072185
use crate::sys::{cvt, cvt_r};
22082186
use crate::sys_common::ignore_notfound;
22092187

@@ -2324,19 +2302,19 @@ mod remove_dir_impl {
23242302
Ok(())
23252303
}
23262304

2327-
fn remove_dir_all_modern(p: &Path) -> io::Result<()> {
2305+
fn remove_dir_all_modern(p: &CStr) -> io::Result<()> {
23282306
// We cannot just call remove_dir_all_recursive() here because that would not delete a passed
23292307
// symlink. No need to worry about races, because remove_dir_all_recursive() does not recurse
23302308
// into symlinks.
23312309
let attr = lstat(p)?;
23322310
if attr.file_type().is_symlink() {
2333-
crate::fs::remove_file(p)
2311+
super::unlink(p)
23342312
} else {
2335-
run_path_with_cstr(p, &|p| remove_dir_all_recursive(None, &p))
2313+
remove_dir_all_recursive(None, &p)
23362314
}
23372315
}
23382316

2339-
pub fn remove_dir_all(p: &Path) -> io::Result<()> {
2317+
pub fn remove_dir_all(p: &CStr) -> io::Result<()> {
23402318
remove_dir_all_modern(p)
23412319
}
23422320
}

0 commit comments

Comments
 (0)
Please sign in to comment.