Skip to content

Commit be0d761

Browse files
committed
Add Dir::open(_file) and some trait impls
1 parent beeb8e3 commit be0d761

File tree

13 files changed

+607
-94
lines changed

13 files changed

+607
-94
lines changed

library/std/src/fs.rs

Lines changed: 105 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -153,6 +153,32 @@ pub enum TryLockError {
153153
WouldBlock,
154154
}
155155

156+
/// An object providing access to a directory on the filesystem.
157+
///
158+
/// Directories are automatically closed when they go out of scope. Errors detected
159+
/// on closing are ignored by the implementation of `Drop`.
160+
///
161+
/// # Examples
162+
///
163+
/// Opens a directory and then a file inside it.
164+
///
165+
/// ```no_run
166+
/// #![feature(dirfd)]
167+
/// use std::{fs::Dir, io};
168+
///
169+
/// fn main() -> std::io::Result<()> {
170+
/// let dir = Dir::open("foo")?;
171+
/// let mut file = dir.open_file("bar.txt")?;
172+
/// let contents = io::read_to_string(file)?;
173+
/// assert_eq!(contents, "Hello, world!");
174+
/// Ok(())
175+
/// }
176+
/// ```
177+
#[unstable(feature = "dirfd", issue = "120426")]
178+
pub struct Dir {
179+
inner: fs_imp::Dir,
180+
}
181+
156182
/// Metadata information about a file.
157183
///
158184
/// This structure is returned from the [`metadata`] or
@@ -1474,6 +1500,85 @@ impl Seek for Arc<File> {
14741500
}
14751501
}
14761502

1503+
impl Dir {
1504+
/// Attempts to open a directory at `path` in read-only mode.
1505+
///
1506+
/// # Errors
1507+
///
1508+
/// This function will return an error if `path` does not point to an existing directory.
1509+
/// Other errors may also be returned according to [`OpenOptions::open`].
1510+
///
1511+
/// # Examples
1512+
///
1513+
/// ```no_run
1514+
/// #![feature(dirfd)]
1515+
/// use std::{fs::Dir, io};
1516+
///
1517+
/// fn main() -> std::io::Result<()> {
1518+
/// let dir = Dir::open("foo")?;
1519+
/// let mut f = dir.open_file("bar.txt")?;
1520+
/// let contents = io::read_to_string(f)?;
1521+
/// assert_eq!(contents, "Hello, world!");
1522+
/// Ok(())
1523+
/// }
1524+
/// ```
1525+
#[unstable(feature = "dirfd", issue = "120426")]
1526+
pub fn open<P: AsRef<Path>>(path: P) -> io::Result<Self> {
1527+
fs_imp::Dir::open(path).map(|inner| Self { inner })
1528+
}
1529+
1530+
///
1531+
/// Attempts to open a file in read-only mode relative to this directory.
1532+
///
1533+
/// # Errors
1534+
///
1535+
/// This function will return an error if `path` does not point to an existing file.
1536+
/// Other errors may also be returned according to [`OpenOptions::open`].
1537+
///
1538+
/// # Examples
1539+
///
1540+
/// ```no_run
1541+
/// #![feature(dirfd)]
1542+
/// use std::{fs::Dir, io};
1543+
///
1544+
/// fn main() -> std::io::Result<()> {
1545+
/// let dir = Dir::open("foo")?;
1546+
/// let mut f = dir.open_file("bar.txt")?;
1547+
/// let contents = io::read_to_string(f)?;
1548+
/// assert_eq!(contents, "Hello, world!");
1549+
/// Ok(())
1550+
/// }
1551+
/// ```
1552+
#[unstable(feature = "dirfd", issue = "120426")]
1553+
pub fn open_file<P: AsRef<Path>>(&self, path: P) -> io::Result<File> {
1554+
self.inner.open_file(path).map(|f| File { inner: f })
1555+
}
1556+
}
1557+
1558+
impl AsInner<fs_imp::Dir> for Dir {
1559+
#[inline]
1560+
fn as_inner(&self) -> &fs_imp::Dir {
1561+
&self.inner
1562+
}
1563+
}
1564+
impl FromInner<fs_imp::Dir> for Dir {
1565+
fn from_inner(f: fs_imp::Dir) -> Dir {
1566+
Dir { inner: f }
1567+
}
1568+
}
1569+
impl IntoInner<fs_imp::Dir> for Dir {
1570+
fn into_inner(self) -> fs_imp::Dir {
1571+
self.inner
1572+
}
1573+
}
1574+
1575+
#[unstable(feature = "dirfd", issue = "120426")]
1576+
impl fmt::Debug for Dir {
1577+
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1578+
self.inner.fmt(f)
1579+
}
1580+
}
1581+
14771582
impl OpenOptions {
14781583
/// Creates a blank new set of options ready for configuration.
14791584
///

library/std/src/fs/tests.rs

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
use rand::RngCore;
22

3+
use super::Dir;
34
#[cfg(any(
45
windows,
56
target_os = "freebsd",
@@ -2226,3 +2227,24 @@ fn test_open_options_invalid_combinations() {
22262227
assert_eq!(err.kind(), ErrorKind::InvalidInput);
22272228
assert_eq!(err.to_string(), "must specify at least one of read, write, or append access");
22282229
}
2230+
2231+
#[test]
2232+
fn test_dir_smoke_test() {
2233+
let tmpdir = tmpdir();
2234+
let dir = Dir::open(tmpdir.path());
2235+
check!(dir);
2236+
}
2237+
2238+
#[test]
2239+
fn test_dir_read_file() {
2240+
let tmpdir = tmpdir();
2241+
let mut f = check!(File::create(tmpdir.join("foo.txt")));
2242+
check!(f.write(b"bar"));
2243+
check!(f.flush());
2244+
drop(f);
2245+
let dir = check!(Dir::open(tmpdir.path()));
2246+
let mut f = check!(dir.open_file("foo.txt"));
2247+
let mut buf = [0u8; 3];
2248+
check!(f.read_exact(&mut buf));
2249+
assert_eq!(b"bar", &buf);
2250+
}

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

Lines changed: 25 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,10 @@
11
#![allow(dead_code)] // not used on all platforms
22

3-
use crate::fs;
43
use crate::io::{self, Error, ErrorKind};
5-
use crate::path::Path;
4+
use crate::path::{Path, PathBuf};
5+
use crate::sys::fs::{File, OpenOptions};
66
use crate::sys_common::ignore_notfound;
7+
use crate::{fmt, fs};
78

89
pub(crate) const NOT_FILE_ERROR: Error = io::const_error!(
910
ErrorKind::InvalidInput,
@@ -58,3 +59,25 @@ pub fn exists(path: &Path) -> io::Result<bool> {
5859
Err(error) => Err(error),
5960
}
6061
}
62+
63+
pub struct Dir {
64+
path: PathBuf,
65+
}
66+
67+
impl Dir {
68+
pub fn open<P: AsRef<Path>>(path: P) -> io::Result<Self> {
69+
Ok(Self { path: path.as_ref().to_path_buf() })
70+
}
71+
72+
pub fn open_file<P: AsRef<Path>>(&self, path: P) -> io::Result<File> {
73+
let mut opts = OpenOptions::new();
74+
opts.read(true);
75+
File::open(&self.path.join(path), &opts)
76+
}
77+
}
78+
79+
impl fmt::Debug for Dir {
80+
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
81+
f.debug_struct("Dir").field("path", &self.path).finish()
82+
}
83+
}

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

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,14 +11,15 @@ use crate::path::{Path, PathBuf};
1111
use crate::sync::Arc;
1212
use crate::sys::common::small_c_string::run_path_with_cstr;
1313
use crate::sys::fd::FileDesc;
14-
pub use crate::sys::fs::common::{copy, exists};
14+
pub use crate::sys::fs::common::{Dir, copy, exists};
1515
use crate::sys::time::SystemTime;
1616
use crate::sys::{cvt, unsupported, unsupported_err};
1717
use crate::sys_common::{AsInner, AsInnerMut, FromInner, IntoInner};
1818
use crate::{fmt, mem};
1919

2020
#[derive(Debug)]
2121
pub struct File(FileDesc);
22+
2223
#[derive(Clone)]
2324
pub struct FileAttr {
2425
stat_val: stat_struct,

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,7 @@ pub fn with_native_path<T>(path: &Path, f: &dyn Fn(&Path) -> io::Result<T>) -> i
5353
}
5454

5555
pub use imp::{
56-
DirBuilder, DirEntry, File, FileAttr, FilePermissions, FileTimes, FileType, OpenOptions,
56+
Dir, DirBuilder, DirEntry, File, FileAttr, FilePermissions, FileTimes, FileType, OpenOptions,
5757
ReadDir,
5858
};
5959

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ use crate::os::raw::{c_int, c_short};
99
use crate::os::solid::ffi::OsStrExt;
1010
use crate::path::{Path, PathBuf};
1111
use crate::sync::Arc;
12-
pub use crate::sys::fs::common::exists;
12+
pub use crate::sys::fs::common::{Dir, exists};
1313
use crate::sys::pal::{abi, error};
1414
use crate::sys::time::SystemTime;
1515
use crate::sys::{unsupported, unsupported_err};

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

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,8 @@ pub struct FileAttr {
2020
size: u64,
2121
}
2222

23+
pub struct Dir(!);
24+
2325
pub struct ReadDir(!);
2426

2527
pub struct DirEntry(!);
@@ -115,6 +117,22 @@ impl FileType {
115117
}
116118
}
117119

120+
impl Dir {
121+
pub fn open<P: AsRef<Path>>(_path: P) -> io::Result<Self> {
122+
unsupported()
123+
}
124+
125+
pub fn open_file<P: AsRef<Path>>(&self, _path: P) -> io::Result<File> {
126+
self.0
127+
}
128+
}
129+
130+
impl fmt::Debug for Dir {
131+
fn fmt(&self, _f: &mut fmt::Formatter<'_>) -> fmt::Result {
132+
self.0
133+
}
134+
}
135+
118136
impl fmt::Debug for ReadDir {
119137
fn fmt(&self, _f: &mut fmt::Formatter<'_>) -> fmt::Result {
120138
self.0

0 commit comments

Comments
 (0)