Skip to content

Commit 621123e

Browse files
committed
requested changes
1 parent bc20381 commit 621123e

File tree

3 files changed

+159
-12
lines changed

3 files changed

+159
-12
lines changed

library/std/src/fs.rs

Lines changed: 79 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1529,7 +1529,7 @@ impl Dir {
15291529
/// [`new_with`]: Dir::new_with
15301530
#[unstable(feature = "dirfd", issue = "120426")]
15311531
pub fn new<P: AsRef<Path>>(path: P) -> io::Result<Self> {
1532-
Ok(Self { inner: fs_imp::Dir::new(path)? })
1532+
fs_imp::Dir::new(path).map(|inner| Self { inner })
15331533
}
15341534

15351535
/// Attempts to open a directory at `path` with the options specified by `opts`.
@@ -1552,7 +1552,33 @@ impl Dir {
15521552
/// ```
15531553
#[unstable(feature = "dirfd", issue = "120426")]
15541554
pub fn new_with<P: AsRef<Path>>(path: P, opts: &OpenOptions) -> io::Result<Self> {
1555-
Ok(Self { inner: fs_imp::Dir::new_with(path, &opts.0)? })
1555+
fs_imp::Dir::new_with(path, &opts.0).map(|inner| Self { inner })
1556+
}
1557+
1558+
/// Attempts to open a directory at `path` with the minimum permissions for traversal.
1559+
///
1560+
/// # Errors
1561+
///
1562+
/// This function may return an error according to [`OpenOptions::open`].
1563+
///
1564+
/// # Examples
1565+
///
1566+
/// ```no_run
1567+
/// #![feature(dirfd)]
1568+
/// use std::{fs::Dir, io::Read};
1569+
///
1570+
/// fn main() -> std::io::Result<()> {
1571+
/// let foo = Dir::new_for_traversal("foo")?;
1572+
/// let foobar = foo.open_dir("bar")?;
1573+
/// let mut s = String::new();
1574+
/// foobar.open("baz")?.read_to_string(&mut s)?;
1575+
/// println!("{s}");
1576+
/// Ok(())
1577+
/// }
1578+
/// ```
1579+
#[unstable(feature = "dirfd", issue = "120426")]
1580+
pub fn new_for_traversal<P: AsRef<Path>>(path: P) -> io::Result<Self> {
1581+
fs_imp::Dir::new_for_traversal(path).map(|inner| Self { inner })
15561582
}
15571583

15581584
/// Attempts to open a file in read-only mode relative to this directory.
@@ -1632,6 +1658,57 @@ impl Dir {
16321658
self.inner.create_dir(path)
16331659
}
16341660

1661+
/// Attempts to open a directory relative to this directory in read-only mode.
1662+
///
1663+
/// # Errors
1664+
///
1665+
/// This function will return an error if `path` does not point to an existing directory.
1666+
/// Other errors may also be returned according to [`OpenOptions::open`].
1667+
///
1668+
/// # Examples
1669+
///
1670+
/// ```no_run
1671+
/// #![feature(dirfd)]
1672+
/// use std::{fs::Dir, io::Read};
1673+
///
1674+
/// fn main() -> std::io::Result<()> {
1675+
/// let foo = Dir::new("foo")?;
1676+
/// let foobar = foo.open_dir("bar")?;
1677+
/// let mut s = String::new();
1678+
/// foobar.open("baz")?.read_to_string(&mut s)?;
1679+
/// println!("{s}");
1680+
/// Ok(())
1681+
/// }
1682+
/// ```
1683+
#[unstable(feature = "dirfd", issue = "120426")]
1684+
pub fn open_dir<P: AsRef<Path>>(&self, path: P) -> io::Result<Self> {
1685+
self.inner.open_dir(path).map(|inner| Self { inner })
1686+
}
1687+
1688+
/// Attempts to open a directory relative to this directory in read-only mode.
1689+
///
1690+
/// # Errors
1691+
///
1692+
/// This function will return an error according to [`OpenOptions::open`].
1693+
///
1694+
/// # Examples
1695+
///
1696+
/// ```no_run
1697+
/// #![feature(dirfd)]
1698+
/// use std::{fs::{Dir, OpenOptions}, io::Write};
1699+
///
1700+
/// fn main() -> std::io::Result<()> {
1701+
/// let foo = Dir::new("foo")?;
1702+
/// let foobar = foo.open_dir_with("bar", OpenOptions::new().write(true))?;
1703+
/// foobar.open("baz")?.write(b"baz")?;
1704+
/// Ok(())
1705+
/// }
1706+
/// ```
1707+
#[unstable(feature = "dirfd", issue = "120426")]
1708+
pub fn open_dir_with<P: AsRef<Path>>(&self, path: P, opts: &OpenOptions) -> io::Result<Self> {
1709+
self.inner.open_dir_with(path, &opts.0).map(|inner| Self { inner })
1710+
}
1711+
16351712
/// Attempts to remove a file relative to this directory.
16361713
///
16371714
/// # Errors

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

Lines changed: 52 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -78,6 +78,23 @@ use libc::{
7878
stat64, unlinkat,
7979
};
8080

81+
#[cfg(any(target_os = "freebsd", target_os = "aix"))]
82+
const TRAVERSE_DIRECTORY: i32 = libc::O_EXEC;
83+
#[cfg(any(target_os = "linux", target_os = "android", target_os = "l4re", target_os = "redox"))]
84+
const TRAVERSE_DIRECTORY: i32 = libc::O_PATH;
85+
#[cfg(target_os = "illumos")]
86+
const TRAVERSE_DIRECTORY: i32 = libc::O_SEARCH;
87+
#[cfg(not(any(
88+
target_os = "aix",
89+
target_os = "android",
90+
target_os = "freebsd",
91+
target_os = "illumos",
92+
target_os = "l4re",
93+
target_os = "linux",
94+
target_os = "redox",
95+
)))]
96+
const TRAVERSE_DIRECTORY: i32 = libc::O_RDONLY;
97+
8198
use crate::ffi::{CStr, OsStr, OsString};
8299
use crate::fmt::{self, Write as _};
83100
use crate::fs::TryLockError;
@@ -278,11 +295,15 @@ impl Dir {
278295
pub fn new<P: AsRef<Path>>(path: P) -> io::Result<Self> {
279296
let mut opts = OpenOptions::new();
280297
opts.read(true);
281-
run_path_with_cstr(path.as_ref(), &|path| Self::open_c_dir(path, &opts))
298+
run_path_with_cstr(path.as_ref(), &|path| Self::new_with_c(path, &opts))
282299
}
283300

284301
pub fn new_with<P: AsRef<Path>>(path: P, opts: &OpenOptions) -> io::Result<Self> {
285-
run_path_with_cstr(path.as_ref(), &|path| Self::open_c_dir(path, &opts))
302+
run_path_with_cstr(path.as_ref(), &|path| Self::new_with_c(path, opts))
303+
}
304+
305+
pub fn new_for_traversal<P: AsRef<Path>>(path: P) -> io::Result<Self> {
306+
run_path_with_cstr(path.as_ref(), &|path| Self::new_c(path))
286307
}
287308

288309
pub fn open<P: AsRef<Path>>(&self, path: P) -> io::Result<File> {
@@ -299,6 +320,14 @@ impl Dir {
299320
run_path_with_cstr(path.as_ref(), &|path| self.create_dir_c(path))
300321
}
301322

323+
pub fn open_dir<P: AsRef<Path>>(&self, path: P) -> io::Result<Self> {
324+
run_path_with_cstr(path.as_ref(), &|path| self.open_c_dir(path, &OpenOptions::new()))
325+
}
326+
327+
pub fn open_dir_with<P: AsRef<Path>>(&self, path: P, opts: &OpenOptions) -> io::Result<Self> {
328+
run_path_with_cstr(path.as_ref(), &|path| self.open_c_dir(path, opts))
329+
}
330+
302331
pub fn remove_file<P: AsRef<Path>>(&self, path: P) -> io::Result<()> {
303332
run_path_with_cstr(path.as_ref(), &|path| self.remove_c(path, false))
304333
}
@@ -329,7 +358,25 @@ impl Dir {
329358
Ok(File(unsafe { FileDesc::from_raw_fd(fd) }))
330359
}
331360

332-
pub fn open_c_dir(path: &CStr, opts: &OpenOptions) -> io::Result<Self> {
361+
pub fn open_c_dir(&self, path: &CStr, opts: &OpenOptions) -> io::Result<Self> {
362+
let flags = libc::O_CLOEXEC
363+
| libc::O_DIRECTORY
364+
| opts.get_access_mode()?
365+
| opts.get_creation_mode()?
366+
| (opts.custom_flags as c_int & !libc::O_ACCMODE);
367+
let fd = cvt_r(|| unsafe {
368+
openat64(self.0.as_raw_fd(), path.as_ptr(), flags, opts.mode as c_int)
369+
})?;
370+
Ok(Self(unsafe { OwnedFd::from_raw_fd(fd) }))
371+
}
372+
373+
pub fn new_c(path: &CStr) -> io::Result<Self> {
374+
let flags = libc::O_CLOEXEC | libc::O_DIRECTORY | TRAVERSE_DIRECTORY;
375+
let fd = cvt_r(|| unsafe { open64(path.as_ptr(), flags, 0) })?;
376+
Ok(Self(unsafe { OwnedFd::from_raw_fd(fd) }))
377+
}
378+
379+
pub fn new_with_c(path: &CStr, opts: &OpenOptions) -> io::Result<Self> {
333380
let flags = libc::O_CLOEXEC
334381
| libc::O_DIRECTORY
335382
| opts.get_access_mode()?
@@ -467,6 +514,8 @@ impl fmt::Debug for Dir {
467514
}
468515
}
469516

517+
// SAFETY: `int dirfd (DIR *dirstream)` is MT-safe, implying that the pointer
518+
// may be safely sent among threads.
470519
unsafe impl Send for DirStream {}
471520
unsafe impl Sync for DirStream {}
472521

library/std/src/sys/fs/windows.rs

Lines changed: 28 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -947,23 +947,39 @@ fn run_path_with_utf16<T, P: AsRef<Path>>(
947947
impl Dir {
948948
pub fn new<P: AsRef<Path>>(path: P) -> io::Result<Self> {
949949
let opts = OpenOptions::new();
950-
Self::new_native(path.as_ref(), &opts)
950+
Self::new_with_native(path.as_ref(), &opts).map(|handle| Self { handle })
951951
}
952952

953953
pub fn new_with<P: AsRef<Path>>(path: P, opts: &OpenOptions) -> io::Result<Self> {
954-
Self::new_native(path.as_ref(), &opts)
954+
Self::new_with_native(path.as_ref(), &opts).map(|handle| Self { handle })
955+
}
956+
957+
pub fn new_for_traversal<P: AsRef<Path>>(path: P) -> io::Result<Self> {
958+
Self::new_native(path.as_ref()).map(|handle| Self { handle })
955959
}
956960

957961
pub fn open<P: AsRef<Path>>(&self, path: P) -> io::Result<File> {
958962
let mut opts = OpenOptions::new();
959963
let path = path.as_ref().as_os_str().encode_wide().collect::<Vec<_>>();
960964
opts.read(true);
961-
Ok(File { handle: self.open_native(&path, &opts)? })
965+
self.open_native(&path, &opts).map(|handle| File { handle })
962966
}
963967

964968
pub fn open_with<P: AsRef<Path>>(&self, path: P, opts: &OpenOptions) -> io::Result<File> {
965969
let path = path.as_ref().as_os_str().encode_wide().collect::<Vec<_>>();
966-
Ok(File { handle: self.open_native(&path, &opts)? })
970+
self.open_native(&path, &opts).map(|handle| File { handle })
971+
}
972+
973+
pub fn open_dir<P: AsRef<Path>>(&self, path: P) -> io::Result<Self> {
974+
let mut opts = OpenOptions::new();
975+
let path = path.as_ref().as_os_str().encode_wide().collect::<Vec<_>>();
976+
opts.read(true);
977+
self.open_native(&path, &opts).map(|handle| Self { handle })
978+
}
979+
980+
pub fn open_dir_with<P: AsRef<Path>>(&self, path: P, opts: &OpenOptions) -> io::Result<Self> {
981+
let path = path.as_ref().as_os_str().encode_wide().collect::<Vec<_>>();
982+
self.open_native(&path, &opts).map(|handle| Self { handle })
967983
}
968984

969985
pub fn create_dir<P: AsRef<Path>>(&self, path: P) -> io::Result<()> {
@@ -989,9 +1005,14 @@ impl Dir {
9891005
run_path_with_wcstr(to.as_ref(), &|to| self.rename_native(from.as_ref(), to_dir, to))
9901006
}
9911007

992-
fn new_native(path: &Path, opts: &OpenOptions) -> io::Result<Self> {
993-
let handle = File::open(path, opts)?.into_inner();
994-
Ok(Self { handle })
1008+
fn new_native(path: &Path) -> io::Result<Handle> {
1009+
let mut opts = OpenOptions::new();
1010+
opts.access_mode(c::FILE_TRAVERSE);
1011+
File::open(path, &opts).map(|file| file.into_inner())
1012+
}
1013+
1014+
fn new_with_native(path: &Path, opts: &OpenOptions) -> io::Result<Handle> {
1015+
File::open(path, opts).map(|file| file.into_inner())
9951016
}
9961017

9971018
fn open_native(&self, path: &[u16], opts: &OpenOptions) -> io::Result<Handle> {

0 commit comments

Comments
 (0)