Skip to content

Commit f07f7c5

Browse files
committed
requested changes
1 parent 9ae1e46 commit f07f7c5

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
@@ -1508,7 +1508,7 @@ impl Dir {
15081508
/// [`new_with`]: Dir::new_with
15091509
#[unstable(feature = "dirfd", issue = "120426")]
15101510
pub fn new<P: AsRef<Path>>(path: P) -> io::Result<Self> {
1511-
Ok(Self { inner: fs_imp::Dir::new(path)? })
1511+
fs_imp::Dir::new(path).map(|inner| Self { inner })
15121512
}
15131513

15141514
/// Attempts to open a directory at `path` with the options specified by `opts`.
@@ -1531,7 +1531,33 @@ impl Dir {
15311531
/// ```
15321532
#[unstable(feature = "dirfd", issue = "120426")]
15331533
pub fn new_with<P: AsRef<Path>>(path: P, opts: &OpenOptions) -> io::Result<Self> {
1534-
Ok(Self { inner: fs_imp::Dir::new_with(path, &opts.0)? })
1534+
fs_imp::Dir::new_with(path, &opts.0).map(|inner| Self { inner })
1535+
}
1536+
1537+
/// Attempts to open a directory at `path` with the minimum permissions for traversal.
1538+
///
1539+
/// # Errors
1540+
///
1541+
/// This function may return an error according to [`OpenOptions::open`].
1542+
///
1543+
/// # Examples
1544+
///
1545+
/// ```no_run
1546+
/// #![feature(dirfd)]
1547+
/// use std::{fs::Dir, io::Read};
1548+
///
1549+
/// fn main() -> std::io::Result<()> {
1550+
/// let foo = Dir::new_for_traversal("foo")?;
1551+
/// let foobar = foo.open_dir("bar")?;
1552+
/// let mut s = String::new();
1553+
/// foobar.open("baz")?.read_to_string(&mut s)?;
1554+
/// println!("{s}");
1555+
/// Ok(())
1556+
/// }
1557+
/// ```
1558+
#[unstable(feature = "dirfd", issue = "120426")]
1559+
pub fn new_for_traversal<P: AsRef<Path>>(path: P) -> io::Result<Self> {
1560+
fs_imp::Dir::new_for_traversal(path).map(|inner| Self { inner })
15351561
}
15361562

15371563
/// Attempts to open a file in read-only mode relative to this directory.
@@ -1611,6 +1637,57 @@ impl Dir {
16111637
self.inner.create_dir(path)
16121638
}
16131639

1640+
/// Attempts to open a directory relative to this directory in read-only mode.
1641+
///
1642+
/// # Errors
1643+
///
1644+
/// This function will return an error if `path` does not point to an existing directory.
1645+
/// Other errors may also be returned according to [`OpenOptions::open`].
1646+
///
1647+
/// # Examples
1648+
///
1649+
/// ```no_run
1650+
/// #![feature(dirfd)]
1651+
/// use std::{fs::Dir, io::Read};
1652+
///
1653+
/// fn main() -> std::io::Result<()> {
1654+
/// let foo = Dir::new("foo")?;
1655+
/// let foobar = foo.open_dir("bar")?;
1656+
/// let mut s = String::new();
1657+
/// foobar.open("baz")?.read_to_string(&mut s)?;
1658+
/// println!("{s}");
1659+
/// Ok(())
1660+
/// }
1661+
/// ```
1662+
#[unstable(feature = "dirfd", issue = "120426")]
1663+
pub fn open_dir<P: AsRef<Path>>(&self, path: P) -> io::Result<Self> {
1664+
self.inner.open_dir(path).map(|inner| Self { inner })
1665+
}
1666+
1667+
/// Attempts to open a directory relative to this directory in read-only mode.
1668+
///
1669+
/// # Errors
1670+
///
1671+
/// This function will return an error according to [`OpenOptions::open`].
1672+
///
1673+
/// # Examples
1674+
///
1675+
/// ```no_run
1676+
/// #![feature(dirfd)]
1677+
/// use std::{fs::{Dir, OpenOptions}, io::Write};
1678+
///
1679+
/// fn main() -> std::io::Result<()> {
1680+
/// let foo = Dir::new("foo")?;
1681+
/// let foobar = foo.open_dir_with("bar", OpenOptions::new().write(true))?;
1682+
/// foobar.open("baz")?.write(b"baz")?;
1683+
/// Ok(())
1684+
/// }
1685+
/// ```
1686+
#[unstable(feature = "dirfd", issue = "120426")]
1687+
pub fn open_dir_with<P: AsRef<Path>>(&self, path: P, opts: &OpenOptions) -> io::Result<Self> {
1688+
self.inner.open_dir_with(path, &opts.0).map(|inner| Self { inner })
1689+
}
1690+
16141691
/// Attempts to remove a file relative to this directory.
16151692
///
16161693
/// # 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;
@@ -277,11 +294,15 @@ impl Dir {
277294
pub fn new<P: AsRef<Path>>(path: P) -> io::Result<Self> {
278295
let mut opts = OpenOptions::new();
279296
opts.read(true);
280-
run_path_with_cstr(path.as_ref(), &|path| Self::open_c_dir(path, &opts))
297+
run_path_with_cstr(path.as_ref(), &|path| Self::new_with_c(path, &opts))
281298
}
282299

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

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

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

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

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

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

Lines changed: 28 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -941,23 +941,39 @@ fn run_path_with_utf16<T, P: AsRef<Path>>(
941941
impl Dir {
942942
pub fn new<P: AsRef<Path>>(path: P) -> io::Result<Self> {
943943
let opts = OpenOptions::new();
944-
Self::new_native(path.as_ref(), &opts)
944+
Self::new_with_native(path.as_ref(), &opts).map(|handle| Self { handle })
945945
}
946946

947947
pub fn new_with<P: AsRef<Path>>(path: P, opts: &OpenOptions) -> io::Result<Self> {
948-
Self::new_native(path.as_ref(), &opts)
948+
Self::new_with_native(path.as_ref(), &opts).map(|handle| Self { handle })
949+
}
950+
951+
pub fn new_for_traversal<P: AsRef<Path>>(path: P) -> io::Result<Self> {
952+
Self::new_native(path.as_ref()).map(|handle| Self { handle })
949953
}
950954

951955
pub fn open<P: AsRef<Path>>(&self, path: P) -> io::Result<File> {
952956
let mut opts = OpenOptions::new();
953957
let path = path.as_ref().as_os_str().encode_wide().collect::<Vec<_>>();
954958
opts.read(true);
955-
Ok(File { handle: self.open_native(&path, &opts)? })
959+
self.open_native(&path, &opts).map(|handle| File { handle })
956960
}
957961

958962
pub fn open_with<P: AsRef<Path>>(&self, path: P, opts: &OpenOptions) -> io::Result<File> {
959963
let path = path.as_ref().as_os_str().encode_wide().collect::<Vec<_>>();
960-
Ok(File { handle: self.open_native(&path, &opts)? })
964+
self.open_native(&path, &opts).map(|handle| File { handle })
965+
}
966+
967+
pub fn open_dir<P: AsRef<Path>>(&self, path: P) -> io::Result<Self> {
968+
let mut opts = OpenOptions::new();
969+
let path = path.as_ref().as_os_str().encode_wide().collect::<Vec<_>>();
970+
opts.read(true);
971+
self.open_native(&path, &opts).map(|handle| Self { handle })
972+
}
973+
974+
pub fn open_dir_with<P: AsRef<Path>>(&self, path: P, opts: &OpenOptions) -> io::Result<Self> {
975+
let path = path.as_ref().as_os_str().encode_wide().collect::<Vec<_>>();
976+
self.open_native(&path, &opts).map(|handle| Self { handle })
961977
}
962978

963979
pub fn create_dir<P: AsRef<Path>>(&self, path: P) -> io::Result<()> {
@@ -983,9 +999,14 @@ impl Dir {
983999
run_path_with_wcstr(to.as_ref(), &|to| self.rename_native(from.as_ref(), to_dir, to))
9841000
}
9851001

986-
fn new_native(path: &Path, opts: &OpenOptions) -> io::Result<Self> {
987-
let handle = File::open(path, opts)?.into_inner();
988-
Ok(Self { handle })
1002+
fn new_native(path: &Path) -> io::Result<Handle> {
1003+
let mut opts = OpenOptions::new();
1004+
opts.access_mode(c::FILE_TRAVERSE);
1005+
File::open(path, &opts).map(|file| file.into_inner())
1006+
}
1007+
1008+
fn new_with_native(path: &Path, opts: &OpenOptions) -> io::Result<Handle> {
1009+
File::open(path, opts).map(|file| file.into_inner())
9891010
}
9901011

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

0 commit comments

Comments
 (0)