Skip to content

Commit c5ac220

Browse files
committed
requested changes
1 parent ef09707 commit c5ac220

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
@@ -1524,7 +1524,7 @@ impl Dir {
15241524
/// [`new_with`]: Dir::new_with
15251525
#[unstable(feature = "dirfd", issue = "120426")]
15261526
pub fn new<P: AsRef<Path>>(path: P) -> io::Result<Self> {
1527-
Ok(Self { inner: fs_imp::Dir::new(path)? })
1527+
fs_imp::Dir::new(path).map(|inner| Self { inner })
15281528
}
15291529

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

15531579
/// Attempts to open a file in read-only mode relative to this directory.
@@ -1627,6 +1653,57 @@ impl Dir {
16271653
self.inner.create_dir(path)
16281654
}
16291655

1656+
/// Attempts to open a directory relative to this directory in read-only mode.
1657+
///
1658+
/// # Errors
1659+
///
1660+
/// This function will return an error if `path` does not point to an existing directory.
1661+
/// Other errors may also be returned according to [`OpenOptions::open`].
1662+
///
1663+
/// # Examples
1664+
///
1665+
/// ```no_run
1666+
/// #![feature(dirfd)]
1667+
/// use std::{fs::Dir, io::Read};
1668+
///
1669+
/// fn main() -> std::io::Result<()> {
1670+
/// let foo = Dir::new("foo")?;
1671+
/// let foobar = foo.open_dir("bar")?;
1672+
/// let mut s = String::new();
1673+
/// foobar.open("baz")?.read_to_string(&mut s)?;
1674+
/// println!("{s}");
1675+
/// Ok(())
1676+
/// }
1677+
/// ```
1678+
#[unstable(feature = "dirfd", issue = "120426")]
1679+
pub fn open_dir<P: AsRef<Path>>(&self, path: P) -> io::Result<Self> {
1680+
self.inner.open_dir(path).map(|inner| Self { inner })
1681+
}
1682+
1683+
/// Attempts to open a directory relative to this directory in read-only mode.
1684+
///
1685+
/// # Errors
1686+
///
1687+
/// This function will return an error according to [`OpenOptions::open`].
1688+
///
1689+
/// # Examples
1690+
///
1691+
/// ```no_run
1692+
/// #![feature(dirfd)]
1693+
/// use std::{fs::{Dir, OpenOptions}, io::Write};
1694+
///
1695+
/// fn main() -> std::io::Result<()> {
1696+
/// let foo = Dir::new("foo")?;
1697+
/// let foobar = foo.open_dir_with("bar", OpenOptions::new().write(true))?;
1698+
/// foobar.open("baz")?.write(b"baz")?;
1699+
/// Ok(())
1700+
/// }
1701+
/// ```
1702+
#[unstable(feature = "dirfd", issue = "120426")]
1703+
pub fn open_dir_with<P: AsRef<Path>>(&self, path: P, opts: &OpenOptions) -> io::Result<Self> {
1704+
self.inner.open_dir_with(path, &opts.0).map(|inner| Self { inner })
1705+
}
1706+
16301707
/// Attempts to remove a file relative to this directory.
16311708
///
16321709
/// # 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
@@ -942,23 +942,39 @@ fn run_path_with_utf16<T, P: AsRef<Path>>(
942942
impl Dir {
943943
pub fn new<P: AsRef<Path>>(path: P) -> io::Result<Self> {
944944
let opts = OpenOptions::new();
945-
Self::new_native(path.as_ref(), &opts)
945+
Self::new_with_native(path.as_ref(), &opts).map(|handle| Self { handle })
946946
}
947947

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

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

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

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

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

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

0 commit comments

Comments
 (0)